[SmokeTest] Add request mode choice
[platform/core/appfw/wgt-backend.git] / src / unit_tests / smoke_test.cc
index 5185bdb..0cbbfb8 100644 (file)
@@ -6,6 +6,8 @@
 #include <boost/filesystem/path.hpp>
 #include <boost/range/iterator_range.hpp>
 #include <boost/system/error_code.hpp>
+#include <boost/format.hpp>
+#include <boost/program_options.hpp>
 
 #include <common/paths.h>
 #include <common/pkgmgr_interface.h>
@@ -16,6 +18,9 @@
 #include <common/utils/file_util.h>
 #include <common/utils/subprocess.h>
 #include <common/utils/user_util.h>
+#include <gum/gum-user.h>
+#include <gum/gum-user-service.h>
+#include <gum/common/gum-user-types.h>
 
 #include <gtest/gtest.h>
 #include <gtest/gtest-death-test.h>
 #include <tzplatform_config.h>
 #include <vconf.h>
 #include <vconf-internal-keys.h>
+#include <getopt.h>
 
 #include <array>
 #include <cstdio>
 #include <cstdlib>
 #include <vector>
+#include <regex>
 
 #include "hybrid/hybrid_installer.h"
 #include "wgt/wgt_app_query_interface.h"
 
 namespace bf = boost::filesystem;
 namespace bs = boost::system;
+namespace bo = boost::program_options;
 namespace ci = common_installer;
 
 namespace {
+ci::RequestMode ParseRequestMode(int argc,  char** argv) {
+  bo::options_description desc("Available options");
+  desc.add_options()
+      ("request-mode", bo::value<std::string>(), "set request mode")
+      ("global-request,g", "set request mode to global")
+      ("user-request,u", "set request mode to user");
+
+  bo::variables_map vm;
+  bo::store(bo::parse_command_line(argc, argv, desc), vm);
+  bo::notify(vm);
+
+  if (vm.count("global-request")) {
+    std::cout << "Request mode was set to global." << std::endl;
+    return ci::RequestMode::GLOBAL;
+  }
+  if (vm.count("user-request")) {
+    std::cout << "Request mode was set to user." << std::endl;
+    return ci::RequestMode::USER;
+  }
+  if (vm.count("request-mode")) {
+    if (vm["request-mode"].as<std::string>() == "global") {
+      std::cout << "Request mode was set to global." << std::endl;
+      return ci::RequestMode::GLOBAL;
+    }
+    if (vm["request-mode"].as<std::string>() == "user") {
+      std::cout << "Request mode was set to user." << std::endl;
+      return ci::RequestMode::USER;
+    }
+    std::cout << "Cannot set request mode to "
+              << vm["request-mode"].as<std::string>() << std::endl;
+    std::cout << "Request mode was set to global." << std::endl;
+    return ci::RequestMode::GLOBAL;
+
+  }
+}
 
 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
 const uid_t kGlobalUserGid = tzplatform_getgid(TZ_SYS_GLOBALAPP_USER);
 const uid_t kDefaultUserUid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
-const uid_t kTestUserId = kGlobalUserUid;
-const gid_t kTestGroupId = kGlobalUserGid;
+uid_t kTestUserId = kGlobalUserUid;
+gid_t kTestGroupId = kGlobalUserGid;
+std::string kTestUserIdStr = std::to_string(kTestUserId);
+const char kNormalUserName[] = "smokeuser";
 const char kSystemShareGroupName[] = "system_share";
-const std::string& kTestUserIdStr =
-    std::to_string(kTestUserId);
 const std::string& kDefaultUserIdStr = std::to_string(kDefaultUserUid);
 const char kLegacyExtImageDir[] = "legacy_extimage_dir";
 const char kMigrateTestDBName[] = "app2sd_migrate.db";
@@ -59,6 +102,22 @@ const char kMigrateTestDBName[] = "app2sd_migrate.db";
 const bf::path kSmokePackagesDirectory =
     "/usr/share/wgt-backend-ut/test_samples/smoke/";
 
+enum RWDirectory {
+    DATA,
+    CACHE,
+    SHARED_CACHE,
+    SHARED_DATA,
+    SHARED_TRUSTED
+};
+
+const char* rwDirectories[] = {
+  "data",
+  "cache",
+  "shared/cache",
+  "shared/data",
+  "shared/trusted",
+};
+
 // common entries
 const std::vector<std::string> kDBEntries = {
   {".pkgmgr_parser.db"},
@@ -136,6 +195,62 @@ bool TouchFile(const bf::path& path) {
   return true;
 }
 
+bool AddUser(const char *user_name) {
+  GumUser* user = nullptr;
+  user = gum_user_create_sync(FALSE);
+  if (user == nullptr)
+    LOG(WARNING) << "Failed to create gum user! (user name: "
+                 << user_name << ")";
+  g_object_set(G_OBJECT(user), "username", user_name, "usertype",
+      GUM_USERTYPE_NORMAL, NULL);
+  gboolean rval = FALSE;
+  rval = gum_user_add_sync(user);
+  g_object_unref(user);
+  return rval;
+}
+
+bool DeleteUser(const char *user_name, bool rem_home_dir) {
+  bool rval = FALSE;
+  GumUser* guser = gum_user_get_by_name_sync(user_name, FALSE);
+  if(guser)
+    rval = gum_user_delete_sync(guser, rem_home_dir);
+  return rval;
+}
+
+bool AddTestUser(const char *user_name) {
+  std::cout << "Adding test user: " << user_name << std::endl;
+  bool ret = AddUser(user_name);
+  if (boost::optional<uid_t> uid = ci::GetUidByUserName(user_name)) {
+    kTestUserId = *uid;
+    kTestUserIdStr = std::to_string(kTestUserId);
+    std::cout << "User created properly: uid=" << *uid;
+    if (boost::optional<gid_t> gid = ci::GetGidByUid(*uid)) {
+      kTestGroupId = *gid;
+      std::cout << " gid=" << *gid;
+    }
+    std::cout << std::endl;
+    return true;
+  }
+  LOG(ERROR) << "Adding test user failed";
+  return false;
+}
+
+bool DeleteTestUser(const char *user_name) {
+  std::cout << "Deleting test user: " << user_name << std::endl;
+  uid_t test_uid;
+  if (boost::optional<uid_t> uid = ci::GetUidByUserName(user_name))
+    test_uid = *uid;
+  bool ret = DeleteUser(user_name, true);
+  if (boost::optional<uid_t> uid = ci::GetUidByUserName(user_name));
+  else {
+    std::cout << "User deleted properly: user_name=" << user_name
+              << " uid=" << test_uid << std::endl;
+    return true;
+  }
+  LOG(ERROR) << "Deleting test user failed";
+  return false;
+}
+
 void RemoveAllRecoveryFiles() {
   bf::path root_path = ci::GetRootAppPath(false,
       kTestUserId);
@@ -144,7 +259,8 @@ void RemoveAllRecoveryFiles() {
   for (auto& dir_entry : boost::make_iterator_range(
          bf::directory_iterator(root_path), bf::directory_iterator())) {
     if (bf::is_regular_file(dir_entry)) {
-      if (dir_entry.path().string().find("/recovery") != std::string::npos) {
+      if (dir_entry.path().string().find("/wgt-recovery")
+          != std::string::npos) {
         bs::error_code error;
         bf::remove(dir_entry.path(), error);
       }
@@ -158,7 +274,8 @@ bf::path FindRecoveryFile() {
   for (auto& dir_entry : boost::make_iterator_range(
          bf::directory_iterator(root_path), bf::directory_iterator())) {
     if (bf::is_regular_file(dir_entry)) {
-      if (dir_entry.path().string().find("/recovery") != std::string::npos) {
+      if (dir_entry.path().string().find("/wgt-recovery")
+          != std::string::npos) {
         return dir_entry.path();
       }
     }
@@ -228,9 +345,9 @@ void ValidateDataFiles(const std::string& pkgid, uid_t uid) {
 void ValidatePackageRWFS(const std::string& pkgid, uid_t uid) {
   bf::path root_path = ci::GetRootAppPath(false, uid);
   bf::path package_path = root_path / pkgid;
-  bf::path data_path = package_path / "data";
-  bf::path cache_path = package_path / "cache";
-  bf::path shared_data_path = package_path / "shared" / "data";
+  bf::path data_path = package_path / rwDirectories[DATA];
+  bf::path cache_path = package_path / rwDirectories[CACHE];
+  bf::path shared_data_path = package_path / rwDirectories[SHARED_DATA];
 
   ASSERT_TRUE(bf::exists(data_path));
   ASSERT_TRUE(bf::exists(cache_path));
@@ -291,9 +408,15 @@ void ValidatePackageFS(const std::string& pkgid,
       iter != bf::recursive_directory_iterator(); ++iter) {
     if (bf::is_symlink(symlink_status(iter->path())))
       continue;
-    if (iter->path().filename() == "data" ||
-        iter->path().filename() == ".mmc")
+    bool is_rw_dir = false;
+    for(const auto rw_dir : rwDirectories) {
+      bf::path rw_dir_path = rw_dir;
+      is_rw_dir |= ci::MakeRelativePath(iter->path(), package_path) == rw_dir_path;
+    }
+    if (is_rw_dir || iter->path().filename() == ".mmc") {
+      iter.no_push();
       continue;
+    }
     struct stat stats;
     stat(iter->path().c_str(), &stats);
     ASSERT_EQ(uid, stats.st_uid) << "Invalid uid: " << iter->path();
@@ -373,6 +496,8 @@ void CheckPackageNonExistance(const std::string& pkgid,
   PackageCheckCleanup(pkgid, appids);
   if (kTestUserId == kGlobalUserUid) {
       ci::UserList list = ci::GetUserList();
+      bf::path skel_path(kSkelDir);
+      ASSERT_FALSE(bf::exists(skel_path / pkgid));
       for (auto& l : list) {
         bf::path root_path = ci::GetRootAppPath(false, std::get<0>(l));
         bf::path package_path = root_path / pkgid;
@@ -642,11 +767,11 @@ void RestorePath(const bf::path& path) {
   }
 }
 
-std::vector<bf::path> SetupBackupDirectories(uid_t uid) {
+std::vector<bf::path> SetupBackupDirectories() {
   std::vector<bf::path> entries;
   bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB));
-  if (uid != kGlobalUserUid)
-    db_dir = db_dir / "user" / std::to_string(uid);
+  if (kTestUserId != kGlobalUserUid)
+    db_dir = db_dir / "user" / std::to_string(kTestUserId);
   for (auto e : kDBEntries) {
     bf::path path = db_dir / e;
     entries.emplace_back(path);
@@ -658,7 +783,7 @@ std::vector<bf::path> SetupBackupDirectories(uid_t uid) {
     entries.emplace_back(kPreloadIcons);
   }
 
-  if (uid == kGlobalUserUid) {
+  if (kTestUserId == kGlobalUserUid) {
     entries.emplace_back(kSkelDir);
     entries.emplace_back(kGlobalManifestDir);
     ci::UserList list = ci::GetUserList();
@@ -667,13 +792,13 @@ std::vector<bf::path> SetupBackupDirectories(uid_t uid) {
       entries.emplace_back(apps);
     }
   } else {
-    tzplatform_set_user(uid);
+    tzplatform_set_user(kTestUserId);
     bf::path approot = tzplatform_getenv(TZ_USER_APPROOT);
     tzplatform_reset_user();
     entries.emplace_back(approot);
   }
 
-  bf::path apps_rw = ci::GetRootAppPath(false, uid);
+  bf::path apps_rw = ci::GetRootAppPath(false, kTestUserId);
   entries.emplace_back(apps_rw);
 
   return entries;
@@ -685,23 +810,27 @@ void UninstallAllAppsInDirectory(bf::path dir, bool is_preload) {
         bf::directory_iterator(dir), bf::directory_iterator())) {
       if (dir_entry.path().string().find("smoke") != std::string::npos &&
           bf::is_directory(dir_entry)) {
-        if(Uninstall(dir_entry.path().filename().string(), PackageType::WGT,
-            is_preload, RequestResult::NORMAL) !=
-            ci::AppInstaller::Result::OK) {
-          LOG(ERROR) << "Cannot uninstall smoke test app: "
-              << dir_entry.path().filename().string();
+        std::string package = dir_entry.path().filename().string();
+        std::regex pkg_regex("smoke[a-zA-Z]{3,}[1-9]{2,}");
+        if (std::regex_match(package, pkg_regex)) {
+          if(Uninstall(dir_entry.path().filename().string(), PackageType::WGT,
+              is_preload, RequestResult::NORMAL) !=
+              ci::AppInstaller::Result::OK) {
+            LOG(ERROR) << "Cannot uninstall smoke test app: "
+                << dir_entry.path().filename().string();
+          }
         }
       }
     }
   }
 }
 
-void UninstallAllSmokeApps(uid_t uid) {
-  if (getuid() == 0) {
+void UninstallAllSmokeApps(ci::RequestMode request_mode) {
+  if (getuid() == 0 && request_mode == ci::RequestMode::GLOBAL) {
     bf::path root_path = kPreloadApps;
     UninstallAllAppsInDirectory(root_path, true);
   }
-  bf::path apps_rw = ci::GetRootAppPath(false, uid);
+  bf::path apps_rw = ci::GetRootAppPath(false, kTestUserId);
   UninstallAllAppsInDirectory(apps_rw, false);
 }
 
@@ -711,27 +840,46 @@ namespace common_installer {
 
 class SmokeEnvironment : public testing::Environment {
  public:
-  explicit SmokeEnvironment(uid_t uid) : uid_(uid) {
+  explicit SmokeEnvironment(ci::RequestMode mode) {\
+    request_mode_ = mode;
   }
   void SetUp() override {
-    backups_ = SetupBackupDirectories(uid_);
+    if (request_mode_ == ci::RequestMode::USER)
+      ASSERT_TRUE(AddTestUser(kNormalUserName));
+    else {
+      kTestUserId = kGlobalUserUid;
+      kTestGroupId = kGlobalUserGid;
+      kTestUserIdStr = std::to_string(kTestUserId);
+    }
+    backups_ = SetupBackupDirectories();
     for (auto& path : backups_)
       BackupPath(path);
   }
   void TearDown() override {
-    UninstallAllSmokeApps(uid_);
+    ASSERT_TRUE(request_mode_ == ci::RequestMode::GLOBAL ||
+                (request_mode_ == ci::RequestMode::USER &&
+                kGlobalUserUid != kTestUserId));
+    UninstallAllSmokeApps(request_mode_);
     for (auto& path : backups_)
       RestorePath(path);
+    if (request_mode_ == ci::RequestMode::USER)
+      ASSERT_TRUE(DeleteTestUser(kNormalUserName));
   }
 
  private:
-  uid_t uid_;
+  ci::RequestMode request_mode_;
   std::vector<bf::path> backups_;
 };
 
 class SmokeTest : public testing::Test {
 };
 
+class PreloadSmokeTest : public testing::Test {
+  void SetUp() override {
+    ASSERT_EQ(kGlobalUserUid, kTestUserId);
+  }
+};
+
 TEST_F(SmokeTest, InstallationMode) {
   bf::path path = kSmokePackagesDirectory / "InstallationMode.wgt";
   std::string pkgid = "smokewgt03";
@@ -943,11 +1091,13 @@ TEST_F(SmokeTest, RecoveryMode_ForMountUpdate) {
 }
 
 TEST_F(SmokeTest, InstallationMode_GoodSignature) {
+  // pkgid: smokewgt08
   bf::path path = kSmokePackagesDirectory / "InstallationMode_GoodSignature.wgt";  // NOLINT
   ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
 }
 
 TEST_F(SmokeTest, InstallationMode_WrongSignature) {
+  // pkgid: smokewgt12
   bf::path path = kSmokePackagesDirectory / "InstallationMode_WrongSignature.wgt";  // NOLINT
   ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::ERROR);
 }
@@ -1264,7 +1414,7 @@ TEST_F(SmokeTest, MigrateLegacyExternalImageMode) {
   ValidateExternalPackage(pkgid, {appid});
 }
 
-TEST_F(SmokeTest, InstallationMode_Preload) {
+TEST_F(PreloadSmokeTest, InstallationMode_Preload) {
   ASSERT_EQ(getuid(), 0) << "Test cannot be run by normal user";
   bf::path path = kSmokePackagesDirectory / "InstallationMode_Preload.wgt";
   std::string pkgid = "smokewgt37";
@@ -1274,7 +1424,7 @@ TEST_F(SmokeTest, InstallationMode_Preload) {
   ValidatePackage(pkgid, {appid}, true);
 }
 
-TEST_F(SmokeTest, UpdateMode_Preload) {
+TEST_F(PreloadSmokeTest, UpdateMode_Preload) {
   ASSERT_EQ(getuid(), 0) << "Test cannot be run by normal user";
   bf::path path_old = kSmokePackagesDirectory / "UpdateMode_Preload.wgt";
   bf::path path_new = kSmokePackagesDirectory / "UpdateMode_Preload2.wgt";
@@ -1292,7 +1442,7 @@ TEST_F(SmokeTest, UpdateMode_Preload) {
   ValidateDataFiles(pkgid, kTestUserId);
 }
 
-TEST_F(SmokeTest, DeinstallationMode_Preload) {
+TEST_F(PreloadSmokeTest, DeinstallationMode_Preload) {
   ASSERT_EQ(getuid(), 0) << "Test cannot be run by normal user";
   bf::path path = kSmokePackagesDirectory / "DeinstallationMode_Preload.wgt";
   std::string pkgid = "smokewgt39";
@@ -1304,11 +1454,82 @@ TEST_F(SmokeTest, DeinstallationMode_Preload) {
   CheckPackageReadonlyNonExistance(pkgid, {appid});
 }
 
+TEST_F(SmokeTest, SharedRes24) {
+  bf::path path = kSmokePackagesDirectory / "SharedRes24.wgt";
+  std::string pkgid = "smokeSh2xx";
+  std::string appid = "smokeSh2xx.SharedRes24";
+  ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, {appid});
+  bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "NOT-SHARED-WGT"));  // NOLINT
+  ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "NOT-SHARED-WGT"));  // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30) {
+  bf::path path = kSmokePackagesDirectory / "SharedRes30.wgt";
+  std::string pkgid = "smokeSh3xx";
+  std::string appid = "smokeSh3xx.SharedRes30";
+  ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, {appid});
+  bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30Delta) {
+  bf::path path = kSmokePackagesDirectory / "SharedRes30Delta.wgt";
+  bf::path delta_package = kSmokePackagesDirectory / "SharedRes30Delta.delta";
+  std::string pkgid = "smokeSh3De";
+  std::string appid = "smokeSh3De.SharedRes30Delta";
+  ASSERT_EQ(DeltaInstall(path, delta_package, PackageType::WGT),
+            ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, {appid});
+  // Check delta modifications
+  bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
+  ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30Hybrid) {
+  bf::path path = kSmokePackagesDirectory / "SharedRes30Hybrid.wgt";
+  std::string pkgid = "smokeSh3Hy";
+  std::string appid1 = "smokeSh3Hy.SharedRes30Hybrid";
+  std::string appid2 = "sharedres30hybridserivce";
+  ASSERT_EQ(Install(path, PackageType::HYBRID), ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, {appid1, appid2});
+  bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK"));  // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30HybridDelta) {
+  bf::path path = kSmokePackagesDirectory / "SharedRes30HybridDelta.wgt";
+  bf::path delta_package = kSmokePackagesDirectory / "SharedRes30HybridDelta.delta";
+  std::string pkgid = "smokeSh3HD";
+  std::string appid1 = "smokeSh3HD.SharedRes30HybridDelta";
+  std::string appid2 = "sharedres30hybriddeltaserivce";
+  ASSERT_EQ(DeltaInstall(path, delta_package, PackageType::HYBRID),
+            ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, {appid1, appid2});
+  // Check delta modifications
+  bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK-2"));  // NOLINT
+  ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
+  ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
+}
+
 }  // namespace common_installer
 
 int main(int argc,  char** argv) {
   testing::InitGoogleTest(&argc, argv);
-  testing::AddGlobalTestEnvironment(
-      new common_installer::SmokeEnvironment(kGlobalUserUid));
+  testing::Environment *env = testing::AddGlobalTestEnvironment(
+      new common_installer::SmokeEnvironment(ParseRequestMode(argc, argv)));
   return RUN_ALL_TESTS();
 }