Implement request handlers 49/262449/16
authorJunghyun Yeon <jungh.yeon@samsung.com>
Wed, 11 Aug 2021 05:57:36 +0000 (14:57 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Fri, 20 Aug 2021 00:16:30 +0000 (09:16 +0900)
Implement request handlers and its unit tests.

Change-Id: I131b551905d32d0b9794eb072f654c0b43a3476c
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
17 files changed:
src/rsc-copy/include/abstract_request_handler.hh
src/rsc-copy/include/copy_request_handler.hh
src/rsc-copy/include/file_util.hh [new file with mode: 0644]
src/rsc-copy/include/remove_request_handler.hh
src/rsc-copy/include/uninstall_request_handler.hh
src/rsc-copy/src/abstract_request_handler.cc
src/rsc-copy/src/condition_validator.cc
src/rsc-copy/src/copy_request_handler.cc
src/rsc-copy/src/file_util.cc [new file with mode: 0644]
src/rsc-copy/src/param_checker.cc
src/rsc-copy/src/remove_request_handler.cc
src/rsc-copy/src/request_handler_invoker.cc
src/rsc-copy/src/uninstall_request_handler.cc
tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_dir1/resource_dir2/resource_file2.txt [new file with mode: 0644]
tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_dir1/resource_file3.txt [new file with mode: 0644]
tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_file.txt [new file with mode: 0644]
tests/unit_tests/rsc-copy/src/test_request_handler.cc [new file with mode: 0644]

index 55d4a20..8cb8fd1 100644 (file)
@@ -27,17 +27,21 @@ namespace rsc_handler {
 
 class AbstractRequestHandler {
  public:
-  AbstractRequestHandler(std::string pkgid, std::list<RscPathInfo> path_list) :
-      pkgid_(pkgid), path_list_(path_list) {};
+  AbstractRequestHandler(
+      std::string pkgid, std::string root_path, std::list<RscPathInfo> path_list) :
+      pkgid_(pkgid), root_path_(root_path), path_list_(path_list) {};
 
   virtual ErrorType Execute() = 0;
   virtual const std::string GetRequestHandlerType() const = 0;
 
  protected:
   std::string GetRootPath();
+  const std::string GetPkgID() const;
+  const std::list<RscPathInfo> GetPathList() const;
 
  private:
   std::string pkgid_;
+  std::string root_path_;
   std::list<RscPathInfo> path_list_;
 };
 
index 5e7cda0..c723929 100644 (file)
@@ -28,7 +28,8 @@ namespace rsc_handler {
 
 class CopyRequestHandler : public AbstractRequestHandler {
  public:
-  CopyRequestHandler(std::string pkgid, std::list<RscPathInfo> path_list);
+  CopyRequestHandler(std::string pkgid, std::string root_path,
+      std::list<RscPathInfo> path_list);
 
   ErrorType Execute() override;
   const std::string GetRequestHandlerType() const override;
diff --git a/src/rsc-copy/include/file_util.hh b/src/rsc-copy/include/file_util.hh
new file mode 100644 (file)
index 0000000..0e6d431
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FILE_UTIL_HH_
+#define FILE_UTIL_HH_
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace rsc_handler {
+
+// TODO(jungh.yeon) : is this necessary?
+enum FSFlag : int {
+  FS_NONE              = 0,
+  FS_MERGE_SKIP        = (1 << 0),
+  FS_MERGE_OVERWRITE   = (1 << 1),
+  FS_COMMIT_COPY_FILE  = (1 << 2),
+  FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS = (1 << 3)
+};
+
+FSFlag operator|(FSFlag a, FSFlag b);
+
+bool CreateDir(const boost::filesystem::path& path);
+
+bool CopyDir(const boost::filesystem::path& src,
+             const boost::filesystem::path& dst,
+             FSFlag flags = FS_NONE, bool skip_symlink = false);
+
+bool CopyFile(const boost::filesystem::path& src,
+             const boost::filesystem::path& dst);
+
+bool RemoveAll(const boost::filesystem::path& path);
+
+}  // namespace rsc_handler
+
+#endif  // FILE_UTIL_HH_
index a4432e2..35469f6 100644 (file)
@@ -28,7 +28,9 @@ namespace rsc_handler {
 
 class RemoveRequestHandler : public AbstractRequestHandler {
  public:
-  RemoveRequestHandler(std::string pkgid, std::list<RscPathInfo> path_list);
+  RemoveRequestHandler(
+      std::string pkgid, std::string root_path,
+      std::list<RscPathInfo> path_list);
 
   ErrorType Execute() override;
   const std::string GetRequestHandlerType() const override;
index e8a6a51..4e9627a 100644 (file)
@@ -28,7 +28,8 @@ namespace rsc_handler {
 
 class UninstallRequestHandler : public AbstractRequestHandler {
  public:
-  UninstallRequestHandler(std::string pkgid, std::list<RscPathInfo> path_list);
+  UninstallRequestHandler(
+      std::string pkgid, std::string root_path, std::list<RscPathInfo> path_list);
 
   ErrorType Execute() override;
   const std::string GetRequestHandlerType() const override;
index c51b3e0..d35bea0 100644 (file)
 namespace rsc_handler {
 
 std::string AbstractRequestHandler::GetRootPath() {
-  std::cout << "AbstractRequestHandler::GetRootPath" << std::endl;
+  return root_path_;
+}
 
-  std::string root_path("to_be_added_with_tzplatform/");
-  root_path += pkgid_;
+const std::string AbstractRequestHandler::GetPkgID() const {
+  return pkgid_;
+}
 
-  return root_path;
+const std::list<RscPathInfo> AbstractRequestHandler::GetPathList() const {
+  return path_list_;
 }
 
-}  // namesapce rsc_handler
+}  // namespace rsc_handler
index 8cc575b..46b2315 100644 (file)
@@ -22,6 +22,8 @@
 #include <boost/system/error_code.hpp>
 #include <tzplatform_config.h>
 
+#include <sys/stat.h>
+
 #include <iostream>
 #include <list>
 #include <string>
@@ -32,6 +34,8 @@
 
 #include <pkgmgr-info.h>
 
+namespace bf = boost::filesystem;
+
 namespace {
 
 std::string GetRootPath(uid_t uid) {
@@ -54,20 +58,19 @@ bool IsPackageExists(std::string pkgid, uid_t uid) {
 }
 
 bool CheckFreeSpaceAtPath(int64_t required_size,
-    const boost::filesystem::path& target_location) {
+    const bf::path& target_location) {
   boost::system::error_code error;
-  boost::filesystem::path root = target_location;
+  bf::path root = target_location;
 
-  while (!boost::filesystem::exists(root) && root != root.root_path())
+  while (!bf::exists(root) && root != root.root_path())
     root = root.parent_path();
 
-  if (!boost::filesystem::exists(root)) {
+  if (!bf::exists(root)) {
     LOG(ERROR) << "No mount point for path: " << target_location;
     return false;
   }
 
-  boost::filesystem::space_info space_info =
-      boost::filesystem::space(root, error);
+  bf::space_info space_info = bf::space(root, error);
   if (error) {
     LOG(ERROR) << "Failed to get space_info: " << error.message();
     return false;
@@ -76,6 +79,40 @@ bool CheckFreeSpaceAtPath(int64_t required_size,
   return (space_info.free >= static_cast<uint64_t>(required_size));
 }
 
+int64_t GetBlockSizeForPath(const bf::path& path_in_partition) {
+  struct stat stats;
+  if (stat(path_in_partition.string().c_str(), &stats)) {
+    LOG(ERROR) << "stat(" << path_in_partition.string()
+               << ") failed - error code: " << errno;
+    return -1;
+  }
+  return stats.st_blksize;
+}
+
+int64_t RoundUpToBlockSizeOf(int64_t size, int64_t block_size) {
+  return ((size + block_size - 1) / block_size) * block_size;
+}
+
+int64_t GetDirectorySize(const bf::path& path) {
+  int64_t block_size = GetBlockSizeForPath(path);
+
+  if (block_size == -1)
+    return -1;
+
+  int64_t size = 0;
+  for (bf::recursive_directory_iterator iter(path);
+      iter != bf::recursive_directory_iterator(); ++iter) {
+      struct stat buf;
+      if (lstat(iter->path().c_str(), &buf) == -1) {
+        LOG(ERROR) << "lstat() failed for: " << iter->path();
+        return -1;
+      }
+      size += RoundUpToBlockSizeOf(buf.st_size, block_size);
+  }
+
+  return size;
+}
+
 }  // namespace
 
 namespace rsc_handler {
@@ -112,7 +149,10 @@ ErrorType ConditionValidator::CheckCopyRequest(
       return ErrorType::ERROR_RES_NOT_FOUND;
     }
 
-    rsc_size += boost::filesystem::file_size(rsc_path);
+    if (boost::filesystem::is_directory(rsc_path))
+      rsc_size += GetDirectorySize(rsc_path);
+    else
+      rsc_size += boost::filesystem::file_size(rsc_path);
   }
   LOG(INFO) << "Required size for resource: " << rsc_size;
 
index f810b90..b4ce458 100644 (file)
 
 #include "include/copy_request_handler.hh"
 
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
 #include <iostream>
 #include <string>
 
 #include "include/abstract_request_handler.hh"
 #include "include/error_type.hh"
+#include "include/file_util.hh"
+#include "include/logging.hh"
 #include "include/rsc_path_info.hh"
 
+namespace bf = boost::filesystem;
+
 namespace {
 
 constexpr char kCopyReqHandlerType[] = "copy";
@@ -33,11 +40,43 @@ constexpr char kCopyReqHandlerType[] = "copy";
 namespace rsc_handler {
 
 CopyRequestHandler::CopyRequestHandler(
-    std::string pkgid, std::list<RscPathInfo> path_list) :
-  AbstractRequestHandler(pkgid, path_list) {}
+    std::string pkgid, std::string root_path,
+    std::list<RscPathInfo> path_list) :
+  AbstractRequestHandler(pkgid, root_path, path_list) {}
 
 ErrorType CopyRequestHandler::Execute() {
-  std::cout << "CopyRequestHandler::Execute" << std::endl;
+  bf::path root_path(GetRootPath());
+  bf::path src_root_path = root_path / "apps_rw" / GetPkgID();
+  bf::path dst_root_path = root_path / "shared_res" / GetPkgID();
+
+  if (!CreateDir(dst_root_path))
+    return ErrorType::ERROR_SYSTEM_ERROR;
+
+  for (auto& path_info : GetPathList()) {
+    bf::path src_path = src_root_path / path_info.GetSrcPath();
+    if (!bf::exists(src_path)) {
+      LOG(ERROR) << "Path not exists :" << src_path;
+      return ErrorType::ERROR_RES_NOT_FOUND;
+    }
+
+    bf::path dst_path = dst_root_path / path_info.GetDstPath();
+
+    if (bf::is_directory(src_path)) {
+      if (!CopyDir(src_path, dst_path,
+          FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS, true)) {
+        LOG(ERROR) << "Failed to copy directory " << src_path;
+        return ErrorType::ERROR_SYSTEM_ERROR;
+      }
+    } else {
+      if (bf::is_directory(dst_path))
+        dst_path /= src_path.filename();
+
+      if (!CopyFile(src_path, dst_path)) {
+        LOG(ERROR) << "Failed to copy directory " << src_path;
+        return ErrorType::ERROR_SYSTEM_ERROR;
+      }
+    }
+  }
 
   return ErrorType::ERROR_NONE;
 }
diff --git a/src/rsc-copy/src/file_util.cc b/src/rsc-copy/src/file_util.cc
new file mode 100644 (file)
index 0000000..322d034
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/file_util.hh"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/system/error_code.hpp>
+
+#include "include/logging.hh"
+
+namespace bs = boost::system;
+namespace bf = boost::filesystem;
+
+namespace rsc_handler {
+
+FSFlag operator|(FSFlag a, FSFlag b) {
+  return static_cast<FSFlag>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+bool SetDirPermissions(const boost::filesystem::path& path,
+                      boost::filesystem::perms permissions) {
+  boost::system::error_code error;
+  bf::permissions(path, permissions, error);
+
+  if (error) {
+    LOG(ERROR) << "Failed to set permissions for directory: " << path
+               << boost::system::system_error(error).what();
+    return false;
+  }
+  return true;
+}
+
+bool SetOwnership(const bf::path& path, uid_t uid, gid_t gid) {
+  int ret = lchown(path.c_str(), uid, gid);
+  if (ret != 0) {
+    LOG(ERROR) << "Failed to change owner of: " << path;
+    return false;
+  }
+  return true;
+}
+
+bool SetDirOwnershipAndPermissions(const boost::filesystem::path& path,
+                      boost::filesystem::perms permissions, uid_t uid,
+                      gid_t gid) {
+  if (!SetOwnership(path, uid, gid)) {
+    LOG(ERROR) << "Failed to change owner: " << path
+               << "(" << uid << ", " << gid << ")";
+    return false;
+  }
+  if (!SetDirPermissions(path, permissions)) {
+    LOG(ERROR) << "Failed to change permission: " << path
+               << std::oct << permissions;
+    return false;
+  }
+
+  return true;
+}
+
+bool CopyOwnershipAndPermissions(const boost::filesystem::path& src,
+                                 const boost::filesystem::path& dst) {
+  if (!bf::exists(src)) {
+    LOG(ERROR) << "Failed to copy ownership and permissions"
+               << " from " << src << " to " << dst;
+    return false;
+  }
+  bf::perms permissions = bf::status(src).permissions();
+  struct stat stats;
+  if (stat(src.c_str(), &stats) != 0)
+    return false;
+  if (!SetDirOwnershipAndPermissions(dst, permissions, stats.st_uid,
+                                    stats.st_gid)) {
+    LOG(ERROR) << "Failed to copy ownership and permissions"
+               << " from " << src << " to " << dst;
+    return false;
+  }
+  return true;
+}
+
+bool RemoveAll(const bf::path& path) {
+  if (!exists(path) && !bf::is_symlink(bf::symlink_status(path)))
+    return true;
+
+  bs::error_code error;
+  bf::remove_all(path, error);
+
+  if (error) {
+    LOG(ERROR) << "Cannot remove: " << path << ", " << error.message();
+    return false;
+  }
+
+  return true;
+}
+
+bool CopyDir(const boost::filesystem::path& src,
+             const boost::filesystem::path& dst,
+             FSFlag flags, bool skip_symlink) {
+  try {
+    // Check whether the function call is valid
+    if (!bf::exists(src) || !bf::is_directory(src)) {
+      LOG(ERROR) << "Source directory " << src
+                 << " does not exist or is not a directory.";
+      return false;
+    }
+    if (!bf::exists(dst)) {
+      // Create the destination directory
+      if (!CreateDir(dst)) {
+        LOG(ERROR) << "Unable to create destination directory" << dst;
+        return false;
+      }
+      if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)
+        CopyOwnershipAndPermissions(src, dst);
+    } else {
+      if (!(flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE))) {
+        LOG(ERROR) << "Destination directory " << dst.string()
+                   << " already exists.";
+        return false;
+      }
+      if (flags & (FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS))
+        CopyOwnershipAndPermissions(src, dst);
+    }
+  } catch (const bf::filesystem_error& error) {
+    LOG(ERROR) << "Failed to copy directory: " << error.what();
+    return false;
+  }
+
+  // Iterate through the source directory
+  for (bf::directory_iterator file(src);
+      file != bf::directory_iterator();
+      ++file) {
+    try {
+      bf::path current(file->path());
+      bf::path target = dst / current.filename();
+
+      if (bf::is_symlink(symlink_status(current))) {
+        if (skip_symlink)
+          continue;
+        if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) &&
+            bf::exists(target))
+          continue;
+        bs::error_code error;
+        bf::copy_symlink(current, target, error);
+        if (error) {
+          LOG(ERROR) << "Failed to copy symlink: " << current << ", "
+                     << error.message();
+          return false;
+        }
+      } else if (bf::is_directory(current)) {
+        // Found directory: Recursion
+        if (!CopyDir(current, target, flags, skip_symlink)) {
+          return false;
+        }
+      } else {
+        if ((flags & FS_MERGE_SKIP) && bf::exists(target))
+          continue;
+        bf::path destination = target;
+
+        if (flags & FS_COMMIT_COPY_FILE)
+          destination =
+              bf::unique_path(target.parent_path() / "%%%%-%%%%-%%%%-%%%%");
+
+        if (flags & FS_MERGE_OVERWRITE)
+          bf::copy_file(current, destination,
+                        bf::copy_option::overwrite_if_exists);
+        else
+          bf::copy_file(current, destination);
+
+        if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)
+          CopyOwnershipAndPermissions(current, destination);
+
+        if (flags & FS_COMMIT_COPY_FILE) {
+          if (flags & FS_MERGE_OVERWRITE)
+            bf::remove(target);
+          bf::rename(destination, target);
+        }
+      }
+    } catch (const bf::filesystem_error& error) {
+      LOG(ERROR) << "Failed to copy directory: " << error.what();
+      return false;
+    }
+  }
+  return true;
+}
+
+bool CreateDir(const bf::path& path) {
+  if (bf::exists(path))
+    return true;
+
+  boost::system::error_code error;
+  bf::create_directories(path, error);
+
+  if (error) {
+    LOG(ERROR) << "Failed to create directory: "
+               << boost::system::system_error(error).what();
+    return false;
+  }
+  return true;
+}
+
+bool CopyFile(const bf::path& src, const bf::path& dst) {
+  bs::error_code error;
+
+  bf::copy_file(src, dst, bf::copy_option::overwrite_if_exists, error);
+  if (error) {
+    LOG(WARNING) << "copy file " << src << " due to error ["
+        << error.message() << "]";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace rsc_handler
index 107d3ac..f319715 100644 (file)
@@ -61,7 +61,10 @@ ParamChecker::ParamChecker(int argc, char* argv[]) {
     } else if (o.string_key == "session-id") {
       session_id_ = o.value.front();
     } else if (o.string_key == "path") {
-      path_info_list_.emplace_back(o.value.front(), o.value.back());
+      if (o.value.front() == o.value.back())
+        path_info_list_.emplace_back(o.value.front(), "");
+      else
+        path_info_list_.emplace_back(o.value.front(), o.value.back());
     } else if (o.string_key == "copy" ||
         o.string_key == "delete" ||
         o.string_key == "remove") {
index 3232965..af7581b 100644 (file)
 
 #include "include/remove_request_handler.hh"
 
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
 #include <iostream>
 #include <string>
 
 #include "include/abstract_request_handler.hh"
 #include "include/error_type.hh"
+#include "include/file_util.hh"
+#include "include/logging.hh"
 #include "include/rsc_path_info.hh"
 
+namespace bf = boost::filesystem;
+
 namespace {
 
 constexpr char kRemoveReqHandlerType[] = "remove";
@@ -33,11 +40,29 @@ constexpr char kRemoveReqHandlerType[] = "remove";
 namespace rsc_handler {
 
 RemoveRequestHandler::RemoveRequestHandler(
-    std::string pkgid, std::list<RscPathInfo> path_list) :
-  AbstractRequestHandler(pkgid, path_list) {}
+    std::string pkgid, std::string root_path,
+    std::list<RscPathInfo> path_list) :
+  AbstractRequestHandler(pkgid, root_path, path_list) {}
 
 ErrorType RemoveRequestHandler::Execute() {
-  std::cout << "RemoveRequestHandler::Execute" << std::endl;
+  bf::path root_path(GetRootPath());
+  bf::path dst_root_path = root_path / "shared_res" / GetPkgID();
+
+  if (!bf::exists(dst_root_path)) {
+    LOG(ERROR) << "root path not exists";
+    return ErrorType::ERROR_RES_NOT_FOUND;
+  }
+
+  for (auto& path_info : GetPathList()) {
+    bf::path dst_path = dst_root_path / path_info.GetSrcPath();
+    if (!bf::exists(dst_path)) {
+      LOG(ERROR) << "Path not exists: " << dst_path;
+      continue;
+    }
+
+    if (!RemoveAll(dst_path))
+      return ErrorType::ERROR_SYSTEM_ERROR;
+  }
 
   return ErrorType::ERROR_NONE;
 }
index 3c3cd16..2b95f57 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <iostream>
 
+#include <tzplatform_config.h>
+
 #include "include/abstract_request_handler.hh"
 #include "include/condition_validator.hh"
 #include "include/copy_request_handler.hh"
 #include "include/request_type.hh"
 #include "include/uninstall_request_handler.hh"
 
+namespace {
+
+std::string GetRootPathForUid(uid_t uid) {
+  tzplatform_set_user(uid);
+  const char* rootpath = tzplatform_getenv(TZ_USER_HOME);
+  tzplatform_reset_user();
+  return rootpath;
+}
+
+}  // namespace
+
 namespace rsc_handler {
 
 RequestHandlerInvoker::RequestHandlerInvoker(
@@ -77,17 +90,25 @@ void RequestHandlerInvoker::SetReqHandler() {
   switch (option_.GetRequestType()) {
   case ReqType::REQ_TYPE_NEW:
     handler_.reset(
-        new CopyRequestHandler(option_.GetPkgID(), option_.GetPathList()));
+        new CopyRequestHandler(
+            option_.GetPkgID(),
+            GetRootPathForUid(option_.GetUID()),
+            option_.GetPathList()));
     break;
   case ReqType::REQ_TYPE_REMOVE:
 
     handler_.reset(
-        new RemoveRequestHandler(option_.GetPkgID(), option_.GetPathList()));
+        new RemoveRequestHandler(
+            option_.GetPkgID(),
+            GetRootPathForUid(option_.GetUID()),
+            option_.GetPathList()));
     break;
   case ReqType::REQ_TYPE_UNINSTALL:
     handler_.reset(
         new UninstallRequestHandler(
-            option_.GetPkgID(), option_.GetPathList()));
+            option_.GetPkgID(),
+            GetRootPathForUid(option_.GetUID()),
+            option_.GetPathList()));
     break;
   default:
     LOG(ERROR) << "Invalid request type";
index 7b787db..abb66a9 100644 (file)
 
 #include "include/abstract_request_handler.hh"
 #include "include/error_type.hh"
+#include "include/file_util.hh"
+#include "include/logging.hh"
 #include "include/rsc_path_info.hh"
 
+namespace bf = boost::filesystem;
+
 namespace {
 
 constexpr char kUninstallReqHandlerType[] = "delete";
@@ -33,11 +37,26 @@ constexpr char kUninstallReqHandlerType[] = "delete";
 namespace rsc_handler {
 
 UninstallRequestHandler::UninstallRequestHandler(
-    std::string pkgid, std::list<RscPathInfo> path_list) :
-  AbstractRequestHandler(pkgid, path_list) {}
+    std::string pkgid, std::string root_path,
+    std::list<RscPathInfo> path_list) :
+  AbstractRequestHandler(pkgid, root_path, path_list) {}
 
 ErrorType UninstallRequestHandler::Execute() {
-  std::cout << "UninstallRequestHandler::Execute" << std::endl;
+  if (GetPkgID().length() == 0) {
+    LOG(ERROR) << "Invalid argument";
+    return ErrorType::ERROR_INVALID_PARAMETER;
+  }
+
+  bf::path root_path(GetRootPath());
+  root_path = root_path / "shared_res" / GetPkgID();
+
+  if (!bf::exists(root_path)) {
+    LOG(WARNING) << "path not exists : " << root_path;
+    return ErrorType::ERROR_NONE;
+  }
+
+  if (!RemoveAll(root_path))
+    return ErrorType::ERROR_SYSTEM_ERROR;
 
   return ErrorType::ERROR_NONE;
 }
diff --git a/tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_dir1/resource_dir2/resource_file2.txt b/tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_dir1/resource_dir2/resource_file2.txt
new file mode 100644 (file)
index 0000000..409d6cf
--- /dev/null
@@ -0,0 +1 @@
+this is second resource file
diff --git a/tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_dir1/resource_file3.txt b/tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_dir1/resource_file3.txt
new file mode 100644 (file)
index 0000000..241ce06
--- /dev/null
@@ -0,0 +1 @@
+this is 3rd resource file
diff --git a/tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_file.txt b/tests/unit_tests/rsc-copy/data/apps_rw/test_pkg/data/resource_file.txt
new file mode 100644 (file)
index 0000000..93ec8fc
--- /dev/null
@@ -0,0 +1 @@
+this is resource file to being copied
diff --git a/tests/unit_tests/rsc-copy/src/test_request_handler.cc b/tests/unit_tests/rsc-copy/src/test_request_handler.cc
new file mode 100644 (file)
index 0000000..8373591
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "mock/os_mock.h"
+#include "mock/pkgmgr_info_mock.h"
+#include "mock/test_fixture.h"
+
+#include "include/abstract_request_handler.hh"
+#include "include/copy_request_handler.hh"
+#include "include/error_type.hh"
+#include "include/param_checker.hh"
+#include "include/remove_request_handler.hh"
+#include "include/request_type.hh"
+#include "include/uninstall_request_handler.hh"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::InvokeArgument;
+using ::testing::SaveArg;
+
+using rsc_handler::CopyRequestHandler;
+using rsc_handler::RemoveRequestHandler;
+using rsc_handler::RscPathInfo;
+using rsc_handler::UninstallRequestHandler;
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+
+class Mocks : public ::testing::NiceMock<PkgMgrInfoMock>,
+    public ::testing::NiceMock<OsMock> {};
+
+class CopyRequestHandlerTest : public TestFixture {
+ public:
+  CopyRequestHandlerTest() : TestFixture(std::make_unique<Mocks>()) {}
+  virtual ~CopyRequestHandlerTest() {}
+
+  virtual void SetUp() {
+    bf::path rootpath(root_path);
+    bf::create_directories(
+        rootpath / "shared_res/test_pkg/dest_dir");
+  }
+  virtual void TearDown() {
+    bf::remove_all("./tests/unit_tests/rsc-copy/data/shared_res/test_pkg");
+  }
+
+  std::string root_path = "./tests/unit_tests/rsc-copy/data";
+};
+
+class RemoveRequestHandlerTest : public TestFixture {
+ public:
+  RemoveRequestHandlerTest() : TestFixture(std::make_unique<Mocks>()) {}
+  virtual ~RemoveRequestHandlerTest() {}
+
+  virtual void SetUp() {
+    bf::path rootpath(root_path);
+    bf::create_directories(
+        rootpath / "shared_res/test_pkg/new_dir/new_dir2");
+
+    bf::copy_file(rootpath / "apps_rw/test_pkg/data/resource_file.txt",
+        rootpath / "shared_res/test_pkg/resource_file.txt");
+
+    bf::copy_file(rootpath / "apps_rw/test_pkg/data/resource_file.txt",
+        rootpath / "shared_res/test_pkg/new_dir/resource_file.txt");
+
+    bf::copy_file(rootpath / "apps_rw/test_pkg/data/resource_file.txt",
+        rootpath / "shared_res/test_pkg/new_dir/new_dir2/resource_file.txt");
+  }
+  virtual void TearDown() {
+    bf::remove_all("./tests/unit_tests/rsc-copy/data/shared_res/test_pkg");
+  }
+
+  std::string root_path = "./tests/unit_tests/rsc-copy/data";
+};
+
+class UninstallRequestHandlerTest : public TestFixture {
+ public:
+  UninstallRequestHandlerTest() : TestFixture(std::make_unique<Mocks>()) {}
+  virtual ~UninstallRequestHandlerTest() {}
+
+  virtual void SetUp() {
+    bf::path rootpath(root_path);
+    bf::create_directories(
+        rootpath / "shared_res/test_pkg");
+  }
+  virtual void TearDown() {
+    bf::remove_all("./tests/unit_tests/rsc-copy/data/shared_res/test_pkg");
+  }
+
+  std::string root_path = "./tests/unit_tests/rsc-copy/data";
+};
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtRootToRoot) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_file.txt", "");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtRootToRoot_ChangeFileName) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_file.txt", "another_name.txt");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "another_name.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtRootToDirectory) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_file.txt", "dest_dir");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "dest_dir";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtRootToDirectory_ChangeFileName) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_file.txt", "dest_dir/newname.txt");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "dest_dir";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "newname.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtDirectoryToRoot) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1/resource_file3.txt", "");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file3.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtDirectoryToRoot_ChangeFileName) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back(
+      "data/resource_dir1/resource_file3.txt", "newname.txt");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "newname.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtDirectoryToDirectory) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1/resource_file3.txt", "dest_dir");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "dest_dir";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file3.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyFileAtDirectoryToDirectory_ChangeFileName) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back(
+      "data/resource_dir1/resource_file3.txt", "dest_dir/newname.txt");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "dest_dir";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "newname.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyDirectoryAtRootToRoot) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1", "");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file3.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path = check_path.parent_path();
+  check_path /= "resource_dir2";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file2.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyDirectoryAtRootToDirectory) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1", "dest_dir");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "dest_dir";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file3.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path = check_path.parent_path();
+  check_path /= "resource_dir2";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file2.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyDirectoryAtRootToDirectory2) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1", "resource_dir1");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_dir1";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file3.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path = check_path.parent_path();
+  check_path /= "resource_dir2";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file2.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyDirectoryAtDirectoryToRoot) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1/resource_dir2", "");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file2.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, CopyDirectoryAtDirectoryToDirectory) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_dir1/resource_dir2", "dest_dir");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg");
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "dest_dir";
+  EXPECT_TRUE(bf::exists(check_path));
+
+  check_path /= "resource_file2.txt";
+  EXPECT_TRUE(bf::exists(check_path));
+}
+
+TEST_F(CopyRequestHandlerTest, RscNotexists) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/not_existed_rsc", "new_dir");
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_RES_NOT_FOUND);
+}
+
+TEST_F(CopyRequestHandlerTest, ReplaceRsc) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("data/resource_file.txt", "new_dir");
+
+  CopyRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  CopyRequestHandler replace_handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+}
+
+TEST_F(RemoveRequestHandlerTest, RemoveFileAtRoot) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("resource_file.txt", "");
+
+  RemoveRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg/resource_file.txt");
+  EXPECT_FALSE(bf::exists(check_path));
+}
+
+TEST_F(RemoveRequestHandlerTest, RemoveFileAtDirectory) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("new_dir/resource_file.txt", "");
+
+  RemoveRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(
+      root_path + "/shared_res/test_pkg/new_dir/resource_file.txt");
+  EXPECT_FALSE(bf::exists(check_path));
+}
+
+TEST_F(RemoveRequestHandlerTest, RemoveDirectoryAtRoot) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("new_dir", "");
+
+  RemoveRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg/new_dir");
+  EXPECT_FALSE(bf::exists(check_path));
+}
+
+TEST_F(RemoveRequestHandlerTest, RemoveDirectoryAtDirectory) {
+  std::list<RscPathInfo> path_list;
+  path_list.emplace_back("new_dir/new_dir2", "");
+
+  RemoveRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg/new_dir/new_dir2");
+  EXPECT_FALSE(bf::exists(check_path));
+}
+
+TEST_F(UninstallRequestHandlerTest, RemoveRootPath) {
+  std::list<RscPathInfo> path_list;
+
+  UninstallRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+
+  bf::path check_path(root_path + "/shared_res/test_pkg/");
+  EXPECT_FALSE(bf::exists(check_path));
+}
+
+TEST_F(UninstallRequestHandlerTest, RootNotExists) {
+  std::list<RscPathInfo> path_list;
+  bf::path check_path(root_path + "/shared_res/test_pkg/");
+  bf::remove_all(check_path);
+
+  UninstallRequestHandler handler("test_pkg", root_path, path_list);
+  EXPECT_EQ(handler.Execute(), rsc_handler::ErrorType::ERROR_NONE);
+}
+
+TEST_F(UninstallRequestHandlerTest, EmptyPkgID) {
+  std::list<RscPathInfo> path_list;
+
+  UninstallRequestHandler handler("", root_path, path_list);
+  EXPECT_EQ(handler.Execute(),
+      rsc_handler::ErrorType::ERROR_INVALID_PARAMETER);
+}