From: Piotr Ganicz Date: Mon, 20 Mar 2017 12:28:21 +0000 (+0100) Subject: Export Smoke Utils X-Git-Tag: accepted/tizen/unified/20170515.154302~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ad0b24c375c41a68cd2f279a0358cc54fb525259;p=platform%2Fcore%2Fappfw%2Fwgt-backend.git Export Smoke Utils This change exports utility functions to smoke_utils.h Change-Id: I080275d4add34c417710f6c792fe0108780d284f --- diff --git a/src/unit_tests/CMakeLists.txt b/src/unit_tests/CMakeLists.txt index 7b0f80d..5aa1409 100644 --- a/src/unit_tests/CMakeLists.txt +++ b/src/unit_tests/CMakeLists.txt @@ -3,6 +3,8 @@ SET(DESTINATION_DIR wgt-backend-ut) # Executables ADD_EXECUTABLE(${TARGET_SMOKE_TEST} smoke_test.cc + smoke_utils.h + smoke_utils.cc ) ADD_EXECUTABLE(${TARGET_SMOKE_TEST_HELPER} smoke_test_helper.cc diff --git a/src/unit_tests/smoke_test.cc b/src/unit_tests/smoke_test.cc index 37790e0..f446f8a 100644 --- a/src/unit_tests/smoke_test.cc +++ b/src/unit_tests/smoke_test.cc @@ -2,839 +2,15 @@ // Use of this source code is governed by an apache-2.0 license that can be // found in the LICENSE file. -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include + +#include #include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "hybrid/hybrid_installer.h" -#include "wgt/wgt_app_query_interface.h" -#include "wgt/wgt_installer.h" - -#define SIZEOFARRAY(ARR) \ - sizeof(ARR) / sizeof(ARR[0]) \ - -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(), "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() == "global") { - std::cout << "Request mode was set to global." << std::endl; - return ci::RequestMode::GLOBAL; - } - if (vm["request-mode"].as() == "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::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); -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& kDefaultUserIdStr = std::to_string(kDefaultUserUid); -const char kLegacyExtImageDir[] = "legacy_extimage_dir"; -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 kDBEntries = { - {".pkgmgr_parser.db"}, - {".pkgmgr_parser.db-journal"}, - {".pkgmgr_cert.db"}, - {".pkgmgr_cert.db-journal"}, - {".app2sd.db"}, - {".app2sd.db-journal"}, -}; -// globaluser entries -const char kGlobalManifestDir[] = "/opt/share/packages"; -const char kSkelDir[] = "/etc/skel/apps_rw"; -const char kPreloadApps[] = "/usr/apps"; -const char kPreloadManifestDir[] = "/usr/share/packages"; -const char kPreloadIcons[] = "/usr/share/icons"; - -enum class RequestResult { - NORMAL, - FAIL -}; - -class ScopedTzipInterface { - public: - explicit ScopedTzipInterface(const std::string& pkgid) - : pkg_path_(bf::path(ci::GetRootAppPath(false, - kTestUserId)) / pkgid), - interface_(ci::GetMountLocation(pkg_path_)), - mounted_(true) { - interface_.MountZip(ci::GetZipPackageLocation(pkg_path_, pkgid)); - } - - void Release() { - if (mounted_) { - interface_.UnmountZip(); - mounted_ = false; - } - } - - ~ScopedTzipInterface() { - Release(); - } - - private: - bf::path pkg_path_; - ci::TzipInterface interface_; - bool mounted_; -}; - -class TestPkgmgrInstaller : public ci::PkgmgrInstallerInterface { - public: - bool CreatePkgMgrInstaller(pkgmgr_installer** installer, - ci::InstallationMode* mode) { - *installer = pkgmgr_installer_offline_new(); - if (!*installer) - return false; - *mode = ci::InstallationMode::ONLINE; - return true; - } - - bool ShouldCreateSignal() const { - return false; - } -}; - -enum class PackageType { - WGT, - HYBRID -}; - -bool TouchFile(const bf::path& path) { - FILE* f = fopen(path.c_str(), "w+"); - if (!f) - return false; - fclose(f); - 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 = ci::GetUidByUserName(user_name)) { - kTestUserId = *uid; - kTestUserIdStr = std::to_string(kTestUserId); - std::cout << "User created properly: uid=" << *uid; - if (boost::optional 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 = ci::GetUidByUserName(user_name)) - test_uid = *uid; - bool ret = DeleteUser(user_name, true); - if (boost::optional 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); - if (!bf::exists(root_path)) - return; - 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("/wgt-recovery") - != std::string::npos) { - bs::error_code error; - bf::remove(dir_entry.path(), error); - } - } - } -} - -bf::path FindRecoveryFile() { - bf::path root_path = ci::GetRootAppPath(false, - kTestUserId); - 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("/wgt-recovery") - != std::string::npos) { - return dir_entry.path(); - } - } - } - return {}; -} - -bf::path GetPackageRoot(const std::string& pkgid, uid_t uid) { - bf::path root_path = ci::GetRootAppPath(false, uid); - return root_path / pkgid; -} - -bool ValidateFileContentInPackage(const std::string& pkgid, - const std::string& relative, - const std::string& expected, - bool is_readonly = false) { - bf::path file_path = ci::GetRootAppPath(is_readonly, kTestUserId); - file_path = file_path / pkgid / relative; - if (!bf::exists(file_path)) { - LOG(ERROR) << file_path << " doesn't exist"; - return false; - } - FILE* handle = fopen(file_path.c_str(), "r"); - if (!handle) { - LOG(ERROR) << file_path << " cannot be open"; - return false; - } - std::string content; - std::array buffer; - while (fgets(buffer.data(), buffer.size(), handle)) { - content += buffer.data(); - } - fclose(handle); - return content == expected; -} - -void AddDataFiles(const std::string& pkgid, uid_t uid) { - if (uid == kGlobalUserUid) { - ci::UserList list = ci::GetUserList(); - for (auto l : list) { - auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l)); - ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt")); - ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt")); - } - } else { - auto pkg_path = GetPackageRoot(pkgid, uid); - ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt")); - ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt")); - } -} - -void ValidateDataFiles(const std::string& pkgid, uid_t uid) { - if (uid == kGlobalUserUid) { - ci::UserList list = ci::GetUserList(); - for (auto l : list) { - auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l)); - ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt")); - ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt")); - } - } else { - auto pkg_path = GetPackageRoot(pkgid, uid); - ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt")); - ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt")); - } -} - -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 / 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)); - - struct stat stats; - stat(data_path.c_str(), &stats); - // gid of RW dirs should be system_share - boost::optional system_share = - ci::GetGidByGroupName(kSystemShareGroupName); - ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << data_path; - ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " << data_path; - if (bf::exists(shared_data_path)) { - stat(shared_data_path.c_str(), &stats); - ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << shared_data_path; - ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " - << shared_data_path; - } - - stat(cache_path.c_str(), &stats); - ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << cache_path; - ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " << cache_path; -} - -void ValidatePackageFS(const std::string& pkgid, - const std::vector& appids, - uid_t uid, gid_t gid, bool is_readonly) { - bf::path root_path = ci::GetRootAppPath(is_readonly, uid); - bf::path package_path = root_path / pkgid; - bf::path shared_path = package_path / "shared"; - ASSERT_TRUE(bf::exists(root_path)); - ASSERT_TRUE(bf::exists(package_path)); - ASSERT_TRUE(bf::exists(shared_path)); - - bf::path manifest_path = - bf::path(getUserManifestPath(uid, is_readonly)) / (pkgid + ".xml"); - ASSERT_TRUE(bf::exists(manifest_path)); - - for (auto& appid : appids) { - bf::path binary_path = package_path / "bin" / appid; - ASSERT_TRUE(bf::exists(binary_path)); - } - - bf::path widget_root_path = package_path / "res" / "wgt"; - bf::path config_path = widget_root_path / "config.xml"; - ASSERT_TRUE(bf::exists(widget_root_path)); - ASSERT_TRUE(bf::exists(config_path)); - - bf::path private_tmp_path = package_path / "tmp"; - ASSERT_TRUE(bf::exists(private_tmp_path)); - - // backups should not exist - bf::path package_backup = ci::GetBackupPathForPackagePath(package_path); - bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path); - ASSERT_FALSE(bf::exists(package_backup)); - ASSERT_FALSE(bf::exists(manifest_backup)); - - for (bf::recursive_directory_iterator iter(package_path); - iter != bf::recursive_directory_iterator(); ++iter) { - if (bf::is_symlink(symlink_status(iter->path()))) - continue; - 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(); - ASSERT_EQ(gid, stats.st_gid) << "Invalid gid: " << iter->path(); - } -} - -void PackageCheckCleanup(const std::string& pkgid, - const std::vector&, bool is_readonly = false) { - bf::path root_path = ci::GetRootAppPath(is_readonly, kTestUserId); - bf::path package_path = root_path / pkgid; - ASSERT_FALSE(bf::exists(package_path)); - - bf::path manifest_path = bf::path(getUserManifestPath(kTestUserId, - is_readonly)) / (pkgid + ".xml"); - ASSERT_FALSE(bf::exists(manifest_path)); - - // backups should not exist - bf::path package_backup = ci::GetBackupPathForPackagePath(package_path); - bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path); - ASSERT_FALSE(bf::exists(package_backup)); - ASSERT_FALSE(bf::exists(manifest_backup)); -} - -void ValidatePackage(const std::string& pkgid, - const std::vector& appids, bool is_readonly = false) { - ASSERT_TRUE(ci::QueryIsPackageInstalled( - pkgid, ci::GetRequestMode(kTestUserId), kTestUserId)); - ValidatePackageFS(pkgid, appids, kTestUserId, kTestGroupId, is_readonly); - if (kTestUserId == kGlobalUserUid) { - ci::UserList list = ci::GetUserList(); - for (auto& l : list) - ValidatePackageRWFS(pkgid, std::get<0>(l)); - } else { - ValidatePackageRWFS(pkgid, kTestUserId); - } -} -void ValidateExternalPackageFS(const std::string& pkgid, - const std::vector& appids, - uid_t uid, gid_t gid) { - ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(), uid), 0); - bf::path root_path = ci::GetRootAppPath(false, uid); - ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "res")); - ValidatePackageFS(pkgid, appids, uid, gid, false); - ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(), uid), 0); -} - -void ValidateExternalPackage(const std::string& pkgid, - const std::vector& appids) { - ASSERT_TRUE(ci::QueryIsPackageInstalled( - pkgid, ci::GetRequestMode(kTestUserId), - kTestUserId)); - std::string storage = ci::QueryStorageForPkgId(pkgid, kTestUserId); - bf::path ext_mount_path = ci::GetExternalCardPath(); - if (bf::is_empty(ext_mount_path)) { - LOG(INFO) << "Sdcard not exists!"; - ASSERT_EQ(storage, "installed_internal"); - } else { - ASSERT_EQ(storage, "installed_external"); - } - ValidateExternalPackageFS(pkgid, appids, kTestUserId, kTestGroupId); - if (kTestUserId == kGlobalUserUid) { - ci::UserList list = ci::GetUserList(); - for (auto& l : list) - ValidatePackageRWFS(pkgid, std::get<0>(l)); - } else { - ValidatePackageRWFS(pkgid, kTestUserId); - } -} - -void CheckPackageNonExistance(const std::string& pkgid, - const std::vector& appids) { - ASSERT_FALSE(ci::QueryIsPackageInstalled( - pkgid, ci::GetRequestMode(kTestUserId), - kTestUserId)); - 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; - ASSERT_FALSE(bf::exists(package_path)); - } - } -} - -void CheckPackageReadonlyNonExistance(const std::string& pkgid, - const std::vector& appids) { - ASSERT_FALSE(ci::QueryIsPackageInstalled( - pkgid, ci::GetRequestMode(kTestUserId), kTestUserId)); - PackageCheckCleanup(pkgid, appids, true); -} - -std::unique_ptr CreateQueryInterface() { - std::unique_ptr query_interface( - new wgt::WgtAppQueryInterface()); - return query_interface; -} - -std::unique_ptr CreateInstaller(ci::PkgMgrPtr pkgmgr, - PackageType type) { - switch (type) { - case PackageType::WGT: - return std::unique_ptr(new wgt::WgtInstaller(pkgmgr)); - case PackageType::HYBRID: - return std::unique_ptr( - new hybrid::HybridInstaller(pkgmgr)); - default: - LOG(ERROR) << "Unknown installer type"; - return nullptr; - } -} - -ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr, - PackageType type, - RequestResult mode) { - std::unique_ptr installer = CreateInstaller(pkgmgr, type); - switch (mode) { - case RequestResult::FAIL: - installer->AddStep(); - break; - default: - break; - } - return installer->Run(); -} -ci::AppInstaller::Result CallBackend(int argc, - const char* argv[], - PackageType type, - RequestResult mode = RequestResult::NORMAL - ) { - TestPkgmgrInstaller pkgmgr_installer; - std::unique_ptr query_interface = - CreateQueryInterface(); - auto pkgmgr = - ci::PkgMgrInterface::Create(argc, const_cast(argv), - &pkgmgr_installer, query_interface.get()); - if (!pkgmgr) { - LOG(ERROR) << "Failed to initialize pkgmgr interface"; - return ci::AppInstaller::Result::UNKNOWN; - } - return RunInstallerWithPkgrmgr(pkgmgr, type, mode); -} - -ci::AppInstaller::Result Install(const bf::path& path, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - const char* argv[] = {"", "-i", path.c_str(), "-u", kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -ci::AppInstaller::Result InstallPreload(const bf::path& path, PackageType type, - RequestResult mode = RequestResult::NORMAL) { - const char* argv[] = {"", "-i", path.c_str(), "--preload"}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -bool CheckAvailableExternalPath() { - bf::path ext_mount_path = ci::GetExternalCardPath(); - LOG(DEBUG) << "ext_mount_path :" << ext_mount_path; - if (ext_mount_path.empty()) { - LOG(ERROR) << "Sdcard not exists!"; - return false; - } - return true; -} - -ci::AppInstaller::Result InstallExternal(const bf::path& path, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - int default_storage = 0; - vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, - &default_storage); - vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, 1); - - const char* argv[] = {"", "-i", path.c_str(), "-u", kTestUserIdStr.c_str()}; - ci::AppInstaller::Result result = - CallBackend(SIZEOFARRAY(argv), argv, type, mode); - - vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, - default_storage); - return result; -} - -ci::AppInstaller::Result MigrateLegacyExternalImage(const std::string& pkgid, - const bf::path& path, - const bf::path& legacy_path, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - if (InstallExternal(path, type) != ci::AppInstaller::Result::OK) { - LOG(ERROR) << "Failed to install application. Cannot perform Migrate"; - return ci::AppInstaller::Result::ERROR; - } - - bf::path ext_mount_path = ci::GetExternalCardPath(); - if (bf::is_empty(ext_mount_path)) { - LOG(ERROR) << "Sdcard not exists!"; - return ci::AppInstaller::Result::ERROR; - } - bf::path app2sd_path = ext_mount_path / "app2sd"; - - char* image_name = app2ext_usr_getname_image(pkgid.c_str(), - kGlobalUserUid); - if (!image_name) { - LOG(ERROR) << "Failed to get external image name"; - return ci::AppInstaller::Result::ERROR; - } - bf::path org_image = app2sd_path / image_name; - free(image_name); - - bs::error_code error; - bf::remove(org_image, error); - if (error) { - LOG(ERROR) << "Failed to remove org image"; - return ci::AppInstaller::Result::ERROR; - } - - bf::path db_path = tzplatform_getenv(TZ_SYS_DB); - bf::path app2sd_db = db_path / ".app2sd.db"; - bf::path app2sd_db_journal = db_path / ".app2sd.db-journal"; - bf::remove(app2sd_db, error); - if (error) { - LOG(ERROR) << "Failed to remove app2sd db"; - return ci::AppInstaller::Result::ERROR; - } - bf::remove(app2sd_db_journal, error); - if (error) { - LOG(ERROR) << "Failed to remove app2sd journal db"; - return ci::AppInstaller::Result::ERROR; - } - - bf::path app2sd_migrate_db = legacy_path / kMigrateTestDBName; - if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) { - LOG(ERROR) << "Failed to copy test db"; - return ci::AppInstaller::Result::ERROR; - } - - bf::path legacy_src = legacy_path / pkgid; - bf::path legacy_dst = app2sd_path / pkgid; - if (!ci::CopyFile(legacy_src, legacy_dst)) { - LOG(ERROR) << "Failed to copy test image"; - return ci::AppInstaller::Result::ERROR; - } - const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(), - "-u", kDefaultUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -ci::AppInstaller::Result MountInstall(const bf::path& path, - PackageType type, RequestResult mode = RequestResult::NORMAL) { - const char* argv[] = {"", "-w", path.c_str(), "-u", kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -ci::AppInstaller::Result Uninstall(const std::string& pkgid, - PackageType type, - bool is_preload, - RequestResult mode = RequestResult::NORMAL) { - if (is_preload) { - const char* argv[] = {"", "-d", pkgid.c_str(), "--preload", - "--force-remove"}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); - } else { - const char* argv[] = {"", "-d", pkgid.c_str(), "-u", - kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); - } -} - -ci::AppInstaller::Result RDSUpdate(const bf::path& path, - const std::string& pkgid, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - if (Install(path, type) != ci::AppInstaller::Result::OK) { - LOG(ERROR) << "Failed to install application. Cannot perform RDS"; - return ci::AppInstaller::Result::UNKNOWN; - } - const char* argv[] = {"", "-r", pkgid.c_str(), "-u", - kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -ci::AppInstaller::Result DeltaInstall(const bf::path& path, - const bf::path& delta_package, PackageType type) { - if (Install(path, type) != ci::AppInstaller::Result::OK) { - LOG(ERROR) << "Failed to install application. Cannot perform delta update"; - return ci::AppInstaller::Result::UNKNOWN; - } - return Install(delta_package, type); -} - -ci::AppInstaller::Result EnablePackage(const std::string& pkgid, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - const char* argv[] = {"", "-A", pkgid.c_str(), "-u", kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -ci::AppInstaller::Result DisablePackage(const std::string& pkgid, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - const char* argv[] = {"", "-D", pkgid.c_str(), "-u", kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -ci::AppInstaller::Result Recover(const bf::path& recovery_file, - PackageType type, - RequestResult mode = RequestResult::NORMAL) { - const char* argv[] = {"", "-b", recovery_file.c_str(), "-u", - kTestUserIdStr.c_str()}; - return CallBackend(SIZEOFARRAY(argv), argv, type, mode); -} - -void BackupPath(const bf::path& path) { - bf::path backup_path = path.string() + ".bck"; - std::cout << "Backup path: " << path << " to " << backup_path << std::endl; - bs::error_code error; - bf::remove_all(backup_path, error); - if (error) - LOG(ERROR) << "Remove failed: " << backup_path - << " (" << error.message() << ")"; - if (bf::exists(path)) { - bf::rename(path, backup_path, error); - if (error) - LOG(ERROR) << "Failed to setup test environment. Does some previous" - << " test crashed? Path: " - << backup_path << " should not exist."; - assert(!error); - } -} +#include "unit_tests/smoke_utils.h" -void RestorePath(const bf::path& path) { - bf::path backup_path = path.string() + ".bck"; - std::cout << "Restore path: " << path << " from " << backup_path << std::endl; - bs::error_code error; - bf::remove_all(path, error); - if (error) - LOG(ERROR) << "Remove failed: " << path - << " (" << error.message() << ")"; - if (bf::exists(backup_path)) { - bf::rename(backup_path, path, error); - if (error) - LOG(ERROR) << "Failed to restore backup path: " << backup_path - << " (" << error.message() << ")"; - } -} - -std::vector SetupBackupDirectories() { - std::vector entries; - bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB)); - 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); - } - - if (getuid() == 0) { - entries.emplace_back(kPreloadApps); - entries.emplace_back(kPreloadManifestDir); - entries.emplace_back(kPreloadIcons); - } - - if (kTestUserId == kGlobalUserUid) { - entries.emplace_back(kSkelDir); - entries.emplace_back(kGlobalManifestDir); - ci::UserList list = ci::GetUserList(); - for (auto l : list) { - bf::path apps = std::get<2>(l) / "apps_rw"; - entries.emplace_back(apps); - } - } else { - 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, kTestUserId); - entries.emplace_back(apps_rw); - - return entries; -} - -void UninstallAllAppsInDirectory(bf::path dir, bool is_preload) { - if(bf::exists(dir)) { - for (auto& dir_entry : boost::make_iterator_range( - bf::directory_iterator(dir), bf::directory_iterator())) { - if (dir_entry.path().string().find("smoke") != std::string::npos && - bf::is_directory(dir_entry)) { - 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(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, kTestUserId); - UninstallAllAppsInDirectory(apps_rw, false); -} - -} // namespace namespace common_installer { @@ -844,9 +20,9 @@ class SmokeEnvironment : public testing::Environment { request_mode_ = mode; } void SetUp() override { - if (request_mode_ == ci::RequestMode::USER) + if (request_mode_ == ci::RequestMode::USER) { ASSERT_TRUE(AddTestUser(kNormalUserName)); - else { + } else { kTestUserId = kGlobalUserUid; kTestGroupId = kGlobalUserGid; kTestUserIdStr = std::to_string(kTestUserId); @@ -1508,7 +684,8 @@ TEST_F(SmokeTest, SharedRes30Hybrid) { TEST_F(SmokeTest, SharedRes30HybridDelta) { bf::path path = kSmokePackagesDirectory / "SharedRes30HybridDelta.wgt"; - bf::path delta_package = kSmokePackagesDirectory / "SharedRes30HybridDelta.delta"; + bf::path delta_package = kSmokePackagesDirectory / + "SharedRes30HybridDelta.delta"; std::string pkgid = "smokeSh3HD"; std::string appid1 = "smokeSh3HD.SharedRes30HybridDelta"; std::string appid2 = "sharedres30hybriddeltaserivce"; diff --git a/src/unit_tests/smoke_utils.cc b/src/unit_tests/smoke_utils.cc new file mode 100644 index 0000000..c1750f1 --- /dev/null +++ b/src/unit_tests/smoke_utils.cc @@ -0,0 +1,757 @@ +// Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by an apache-2.0 license that can be +// found in the LICENSE file. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "wgt/wgt_installer.h" + +#include "unit_tests/smoke_utils.h" + +namespace bo = boost::program_options; + +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); +uid_t kTestUserId = kGlobalUserUid; +gid_t kTestGroupId = kGlobalUserGid; +const char kNormalUserName[] = "smokeuser"; +const char kSystemShareGroupName[] = "system_share"; +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"; + +const bf::path kSmokePackagesDirectory = + "/usr/share/wgt-backend-ut/test_samples/smoke/"; + + +const char* rwDirectories[] = { + "data", + "cache", + "shared/cache", + "shared/data", + "shared/trusted", +}; + +// common entries +const std::vector kDBEntries = { + {".pkgmgr_parser.db"}, + {".pkgmgr_parser.db-journal"}, + {".pkgmgr_cert.db"}, + {".pkgmgr_cert.db-journal"}, + {".app2sd.db"}, + {".app2sd.db-journal"}, +}; +// globaluser entries +const char kGlobalManifestDir[] = "/opt/share/packages"; +const char kSkelDir[] = "/etc/skel/apps_rw"; +const char kPreloadApps[] = "/usr/apps"; +const char kPreloadManifestDir[] = "/usr/share/packages"; +const char kPreloadIcons[] = "/usr/share/icons"; + + +ci::RequestMode ParseRequestMode(int argc, char** argv) { + bo::options_description desc("Available options"); + desc.add_options() + ("request-mode", bo::value(), "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() == "global") { + std::cout << "Request mode was set to global." << std::endl; + return ci::RequestMode::GLOBAL; + } + if (vm["request-mode"].as() == "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::endl; + std::cout << "Request mode was set to global." << std::endl; + return ci::RequestMode::GLOBAL; + } +} + +bool TouchFile(const bf::path& path) { + FILE* f = fopen(path.c_str(), "w+"); + if (!f) + return false; + fclose(f); + 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 = ci::GetUidByUserName(user_name)) { + kTestUserId = *uid; + kTestUserIdStr = std::to_string(kTestUserId); + std::cout << "User created properly: uid=" << *uid; + if (boost::optional 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 = ci::GetUidByUserName(user_name)) + test_uid = *uid; + bool ret = DeleteUser(user_name, true); + if (!ci::GetUidByUserName(user_name)) { + 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); + if (!bf::exists(root_path)) + return; + 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("/wgt-recovery") + != std::string::npos) { + bs::error_code error; + bf::remove(dir_entry.path(), error); + } + } + } +} + +bf::path FindRecoveryFile() { + bf::path root_path = ci::GetRootAppPath(false, + kTestUserId); + 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("/wgt-recovery") + != std::string::npos) { + return dir_entry.path(); + } + } + } + return {}; +} + +bf::path GetPackageRoot(const std::string& pkgid, uid_t uid) { + bf::path root_path = ci::GetRootAppPath(false, uid); + return root_path / pkgid; +} + +bool ValidateFileContentInPackage(const std::string& pkgid, + const std::string& relative, + const std::string& expected, + bool is_readonly) { + bf::path file_path = ci::GetRootAppPath(is_readonly, kTestUserId); + file_path = file_path / pkgid / relative; + if (!bf::exists(file_path)) { + LOG(ERROR) << file_path << " doesn't exist"; + return false; + } + FILE* handle = fopen(file_path.c_str(), "r"); + if (!handle) { + LOG(ERROR) << file_path << " cannot be open"; + return false; + } + std::string content; + std::array buffer; + while (fgets(buffer.data(), buffer.size(), handle)) { + content += buffer.data(); + } + fclose(handle); + return content == expected; +} + +void AddDataFiles(const std::string& pkgid, uid_t uid) { + if (uid == kGlobalUserUid) { + ci::UserList list = ci::GetUserList(); + for (auto l : list) { + auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l)); + ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt")); + ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt")); + } + } else { + auto pkg_path = GetPackageRoot(pkgid, uid); + ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt")); + ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt")); + } +} + +void ValidateDataFiles(const std::string& pkgid, uid_t uid) { + if (uid == kGlobalUserUid) { + ci::UserList list = ci::GetUserList(); + for (auto l : list) { + auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l)); + ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt")); + ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt")); + } + } else { + auto pkg_path = GetPackageRoot(pkgid, uid); + ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt")); + ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt")); + } +} + +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 / 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)); + + struct stat stats; + stat(data_path.c_str(), &stats); + // gid of RW dirs should be system_share + boost::optional system_share = + ci::GetGidByGroupName(kSystemShareGroupName); + ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << data_path; + ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " << data_path; + if (bf::exists(shared_data_path)) { + stat(shared_data_path.c_str(), &stats); + ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << shared_data_path; + ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " + << shared_data_path; + } + + stat(cache_path.c_str(), &stats); + ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << cache_path; + ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " << cache_path; +} + +void ValidatePackageFS(const std::string& pkgid, + const std::vector& appids, + uid_t uid, gid_t gid, bool is_readonly) { + bf::path root_path = ci::GetRootAppPath(is_readonly, uid); + bf::path package_path = root_path / pkgid; + bf::path shared_path = package_path / "shared"; + ASSERT_TRUE(bf::exists(root_path)); + ASSERT_TRUE(bf::exists(package_path)); + ASSERT_TRUE(bf::exists(shared_path)); + + bf::path manifest_path = + bf::path(getUserManifestPath(uid, is_readonly)) / (pkgid + ".xml"); + ASSERT_TRUE(bf::exists(manifest_path)); + + for (auto& appid : appids) { + bf::path binary_path = package_path / "bin" / appid; + ASSERT_TRUE(bf::exists(binary_path)); + } + + bf::path widget_root_path = package_path / "res" / "wgt"; + bf::path config_path = widget_root_path / "config.xml"; + ASSERT_TRUE(bf::exists(widget_root_path)); + ASSERT_TRUE(bf::exists(config_path)); + + bf::path private_tmp_path = package_path / "tmp"; + ASSERT_TRUE(bf::exists(private_tmp_path)); + + // backups should not exist + bf::path package_backup = ci::GetBackupPathForPackagePath(package_path); + bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path); + ASSERT_FALSE(bf::exists(package_backup)); + ASSERT_FALSE(bf::exists(manifest_backup)); + + for (bf::recursive_directory_iterator iter(package_path); + iter != bf::recursive_directory_iterator(); ++iter) { + if (bf::is_symlink(symlink_status(iter->path()))) + continue; + 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(); + ASSERT_EQ(gid, stats.st_gid) << "Invalid gid: " << iter->path(); + } +} + +void PackageCheckCleanup(const std::string& pkgid, + const std::vector&, bool is_readonly) { + bf::path root_path = ci::GetRootAppPath(is_readonly, kTestUserId); + bf::path package_path = root_path / pkgid; + ASSERT_FALSE(bf::exists(package_path)); + + bf::path manifest_path = bf::path(getUserManifestPath(kTestUserId, + is_readonly)) / (pkgid + ".xml"); + ASSERT_FALSE(bf::exists(manifest_path)); + + // backups should not exist + bf::path package_backup = ci::GetBackupPathForPackagePath(package_path); + bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path); + ASSERT_FALSE(bf::exists(package_backup)); + ASSERT_FALSE(bf::exists(manifest_backup)); +} + +void ValidatePackage(const std::string& pkgid, + const std::vector& appids, bool is_readonly) { + ASSERT_TRUE(ci::QueryIsPackageInstalled( + pkgid, ci::GetRequestMode(kTestUserId), kTestUserId)); + ValidatePackageFS(pkgid, appids, kTestUserId, kTestGroupId, is_readonly); + if (kTestUserId == kGlobalUserUid) { + ci::UserList list = ci::GetUserList(); + for (auto& l : list) + ValidatePackageRWFS(pkgid, std::get<0>(l)); + } else { + ValidatePackageRWFS(pkgid, kTestUserId); + } +} + +void ValidateExternalPackageFS(const std::string& pkgid, + const std::vector& appids, + uid_t uid, gid_t gid) { + ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(), uid), 0); + bf::path root_path = ci::GetRootAppPath(false, uid); + ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "res")); + ValidatePackageFS(pkgid, appids, uid, gid, false); + ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(), uid), 0); +} + +void ValidateExternalPackage(const std::string& pkgid, + const std::vector& appids) { + ASSERT_TRUE(ci::QueryIsPackageInstalled( + pkgid, ci::GetRequestMode(kTestUserId), + kTestUserId)); + std::string storage = ci::QueryStorageForPkgId(pkgid, kTestUserId); + bf::path ext_mount_path = ci::GetExternalCardPath(); + if (bf::is_empty(ext_mount_path)) { + LOG(INFO) << "Sdcard not exists!"; + ASSERT_EQ(storage, "installed_internal"); + } else { + ASSERT_EQ(storage, "installed_external"); + } + ValidateExternalPackageFS(pkgid, appids, kTestUserId, kTestGroupId); + if (kTestUserId == kGlobalUserUid) { + ci::UserList list = ci::GetUserList(); + for (auto& l : list) + ValidatePackageRWFS(pkgid, std::get<0>(l)); + } else { + ValidatePackageRWFS(pkgid, kTestUserId); + } +} + +void CheckPackageNonExistance(const std::string& pkgid, + const std::vector& appids) { + ASSERT_FALSE(ci::QueryIsPackageInstalled( + pkgid, ci::GetRequestMode(kTestUserId), + kTestUserId)); + 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; + ASSERT_FALSE(bf::exists(package_path)); + } + } +} + +void CheckPackageReadonlyNonExistance(const std::string& pkgid, + const std::vector& appids) { + ASSERT_FALSE(ci::QueryIsPackageInstalled( + pkgid, ci::GetRequestMode(kTestUserId), kTestUserId)); + PackageCheckCleanup(pkgid, appids, true); +} + +std::unique_ptr CreateQueryInterface() { + std::unique_ptr query_interface( + new wgt::WgtAppQueryInterface()); + return query_interface; +} + +std::unique_ptr CreateInstaller(ci::PkgMgrPtr pkgmgr, + PackageType type) { + switch (type) { + case PackageType::WGT: + return std::unique_ptr(new wgt::WgtInstaller(pkgmgr)); + case PackageType::HYBRID: + return std::unique_ptr( + new hybrid::HybridInstaller(pkgmgr)); + default: + LOG(ERROR) << "Unknown installer type"; + return nullptr; + } +} + +ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr, + PackageType type, + RequestResult mode) { + std::unique_ptr installer = CreateInstaller(pkgmgr, type); + switch (mode) { + case RequestResult::FAIL: + installer->AddStep(); + break; + default: + break; + } + return installer->Run(); +} +ci::AppInstaller::Result CallBackend(int argc, + const char* argv[], + PackageType type, + RequestResult mode) { + TestPkgmgrInstaller pkgmgr_installer; + std::unique_ptr query_interface = + CreateQueryInterface(); + auto pkgmgr = + ci::PkgMgrInterface::Create(argc, const_cast(argv), + &pkgmgr_installer, query_interface.get()); + if (!pkgmgr) { + LOG(ERROR) << "Failed to initialize pkgmgr interface"; + return ci::AppInstaller::Result::UNKNOWN; + } + return RunInstallerWithPkgrmgr(pkgmgr, type, mode); +} + +ci::AppInstaller::Result Install(const bf::path& path, + PackageType type, + RequestResult mode) { + const char* argv[] = {"", "-i", path.c_str(), "-u", kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +ci::AppInstaller::Result InstallPreload(const bf::path& path, PackageType type, + RequestResult mode) { + const char* argv[] = {"", "-i", path.c_str(), "--preload"}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +bool CheckAvailableExternalPath() { + bf::path ext_mount_path = ci::GetExternalCardPath(); + LOG(DEBUG) << "ext_mount_path :" << ext_mount_path; + if (ext_mount_path.empty()) { + LOG(ERROR) << "Sdcard not exists!"; + return false; + } + return true; +} + +ci::AppInstaller::Result InstallExternal(const bf::path& path, + PackageType type, + RequestResult mode) { + int default_storage = 0; + vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, + &default_storage); + vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, 1); + + const char* argv[] = {"", "-i", path.c_str(), "-u", kTestUserIdStr.c_str()}; + ci::AppInstaller::Result result = + CallBackend(SIZEOFARRAY(argv), argv, type, mode); + + vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, + default_storage); + return result; +} + +ci::AppInstaller::Result MigrateLegacyExternalImage(const std::string& pkgid, + const bf::path& path, + const bf::path& legacy_path, + PackageType type, + RequestResult mode) { + if (InstallExternal(path, type) != ci::AppInstaller::Result::OK) { + LOG(ERROR) << "Failed to install application. Cannot perform Migrate"; + return ci::AppInstaller::Result::ERROR; + } + + bf::path ext_mount_path = ci::GetExternalCardPath(); + if (bf::is_empty(ext_mount_path)) { + LOG(ERROR) << "Sdcard not exists!"; + return ci::AppInstaller::Result::ERROR; + } + bf::path app2sd_path = ext_mount_path / "app2sd"; + + char* image_name = app2ext_usr_getname_image(pkgid.c_str(), + kGlobalUserUid); + if (!image_name) { + LOG(ERROR) << "Failed to get external image name"; + return ci::AppInstaller::Result::ERROR; + } + bf::path org_image = app2sd_path / image_name; + free(image_name); + + bs::error_code error; + bf::remove(org_image, error); + if (error) { + LOG(ERROR) << "Failed to remove org image"; + return ci::AppInstaller::Result::ERROR; + } + + bf::path db_path = tzplatform_getenv(TZ_SYS_DB); + bf::path app2sd_db = db_path / ".app2sd.db"; + bf::path app2sd_db_journal = db_path / ".app2sd.db-journal"; + bf::remove(app2sd_db, error); + if (error) { + LOG(ERROR) << "Failed to remove app2sd db"; + return ci::AppInstaller::Result::ERROR; + } + bf::remove(app2sd_db_journal, error); + if (error) { + LOG(ERROR) << "Failed to remove app2sd journal db"; + return ci::AppInstaller::Result::ERROR; + } + + bf::path app2sd_migrate_db = legacy_path / kMigrateTestDBName; + if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) { + LOG(ERROR) << "Failed to copy test db"; + return ci::AppInstaller::Result::ERROR; + } + + bf::path legacy_src = legacy_path / pkgid; + bf::path legacy_dst = app2sd_path / pkgid; + if (!ci::CopyFile(legacy_src, legacy_dst)) { + LOG(ERROR) << "Failed to copy test image"; + return ci::AppInstaller::Result::ERROR; + } + const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(), + "-u", kDefaultUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +ci::AppInstaller::Result MountInstall(const bf::path& path, + PackageType type, RequestResult mode) { + const char* argv[] = {"", "-w", path.c_str(), "-u", kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +ci::AppInstaller::Result Uninstall(const std::string& pkgid, + PackageType type, + bool is_preload, + RequestResult mode) { + if (is_preload) { + const char* argv[] = {"", "-d", pkgid.c_str(), "--preload", + "--force-remove"}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); + } else { + const char* argv[] = {"", "-d", pkgid.c_str(), "-u", + kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); + } +} + +ci::AppInstaller::Result RDSUpdate(const bf::path& path, + const std::string& pkgid, + PackageType type, + RequestResult mode) { + if (Install(path, type) != ci::AppInstaller::Result::OK) { + LOG(ERROR) << "Failed to install application. Cannot perform RDS"; + return ci::AppInstaller::Result::UNKNOWN; + } + const char* argv[] = {"", "-r", pkgid.c_str(), "-u", + kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +ci::AppInstaller::Result DeltaInstall(const bf::path& path, + const bf::path& delta_package, PackageType type) { + if (Install(path, type) != ci::AppInstaller::Result::OK) { + LOG(ERROR) << "Failed to install application. Cannot perform delta update"; + return ci::AppInstaller::Result::UNKNOWN; + } + return Install(delta_package, type); +} + +ci::AppInstaller::Result EnablePackage(const std::string& pkgid, + PackageType type, + RequestResult mode) { + const char* argv[] = {"", "-A", pkgid.c_str(), "-u", kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +ci::AppInstaller::Result DisablePackage(const std::string& pkgid, + PackageType type, + RequestResult mode) { + const char* argv[] = {"", "-D", pkgid.c_str(), "-u", kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +ci::AppInstaller::Result Recover(const bf::path& recovery_file, + PackageType type, + RequestResult mode) { + const char* argv[] = {"", "-b", recovery_file.c_str(), "-u", + kTestUserIdStr.c_str()}; + return CallBackend(SIZEOFARRAY(argv), argv, type, mode); +} + +void BackupPath(const bf::path& path) { + bf::path backup_path = path.string() + ".bck"; + std::cout << "Backup path: " << path << " to " << backup_path << std::endl; + bs::error_code error; + bf::remove_all(backup_path, error); + if (error) + LOG(ERROR) << "Remove failed: " << backup_path + << " (" << error.message() << ")"; + if (bf::exists(path)) { + bf::rename(path, backup_path, error); + if (error) + LOG(ERROR) << "Failed to setup test environment. Does some previous" + << " test crashed? Path: " + << backup_path << " should not exist."; + assert(!error); + } +} + +void RestorePath(const bf::path& path) { + bf::path backup_path = path.string() + ".bck"; + std::cout << "Restore path: " << path << " from " << backup_path << std::endl; + bs::error_code error; + bf::remove_all(path, error); + if (error) + LOG(ERROR) << "Remove failed: " << path + << " (" << error.message() << ")"; + if (bf::exists(backup_path)) { + bf::rename(backup_path, path, error); + if (error) + LOG(ERROR) << "Failed to restore backup path: " << backup_path + << " (" << error.message() << ")"; + } +} + +std::vector SetupBackupDirectories() { + std::vector entries; + bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB)); + 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); + } + + if (getuid() == 0) { + entries.emplace_back(kPreloadApps); + entries.emplace_back(kPreloadManifestDir); + entries.emplace_back(kPreloadIcons); + } + + if (kTestUserId == kGlobalUserUid) { + entries.emplace_back(kSkelDir); + entries.emplace_back(kGlobalManifestDir); + ci::UserList list = ci::GetUserList(); + for (auto l : list) { + bf::path apps = std::get<2>(l) / "apps_rw"; + entries.emplace_back(apps); + } + } else { + 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, kTestUserId); + entries.emplace_back(apps_rw); + + return entries; +} + +void UninstallAllAppsInDirectory(bf::path dir, bool is_preload) { + if (bf::exists(dir)) { + for (auto& dir_entry : boost::make_iterator_range( + bf::directory_iterator(dir), bf::directory_iterator())) { + if (dir_entry.path().string().find("smoke") != std::string::npos && + bf::is_directory(dir_entry)) { + 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(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, kTestUserId); + UninstallAllAppsInDirectory(apps_rw, false); +} diff --git a/src/unit_tests/smoke_utils.h b/src/unit_tests/smoke_utils.h new file mode 100644 index 0000000..efc2551 --- /dev/null +++ b/src/unit_tests/smoke_utils.h @@ -0,0 +1,242 @@ +// Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by an apache-2.0 license that can be +// found in the LICENSE file. + +#ifndef UNIT_TESTS_SMOKE_UTILS_H_ +#define UNIT_TESTS_SMOKE_UTILS_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hybrid/hybrid_installer.h" +#include "wgt/wgt_app_query_interface.h" + +#define SIZEOFARRAY(ARR) \ + sizeof(ARR) / sizeof(ARR[0]) \ + +namespace bf = boost::filesystem; +namespace bs = boost::system; +namespace ci = common_installer; + +extern const uid_t kGlobalUserUid; +extern const uid_t kGlobalUserGid; +extern const uid_t kDefaultUserUid; +extern uid_t kTestUserId; +extern gid_t kTestGroupId; +extern std::string kTestUserIdStr; +extern const char kNormalUserName[]; +extern const char kSystemShareGroupName[]; +extern const std::string& kDefaultUserIdStr; +extern const char kLegacyExtImageDir[]; +extern const char kMigrateTestDBName[]; + +extern const bf::path kSmokePackagesDirectory; + +enum RWDirectory { + DATA, + CACHE, + SHARED_CACHE, + SHARED_DATA, + SHARED_TRUSTED +}; + +extern const char* rwDirectories[]; + +// common entries +extern const std::vector kDBEntries; +// globaluser entries +extern const char kGlobalManifestDir[]; +extern const char kSkelDir[]; +extern const char kPreloadApps[]; +extern const char kPreloadManifestDir[]; +extern const char kPreloadIcons[]; + +enum class RequestResult { + NORMAL, + FAIL +}; + +class ScopedTzipInterface { + public: + explicit ScopedTzipInterface(const std::string& pkgid) + : pkg_path_(bf::path(ci::GetRootAppPath(false, + kTestUserId)) / pkgid), + interface_(ci::GetMountLocation(pkg_path_)), + mounted_(true) { + interface_.MountZip(ci::GetZipPackageLocation(pkg_path_, pkgid)); + } + + void Release() { + if (mounted_) { + interface_.UnmountZip(); + mounted_ = false; + } + } + + ~ScopedTzipInterface() { + Release(); + } + + private: + bf::path pkg_path_; + ci::TzipInterface interface_; + bool mounted_; +}; + +class TestPkgmgrInstaller : public ci::PkgmgrInstallerInterface { + public: + bool CreatePkgMgrInstaller(pkgmgr_installer** installer, + ci::InstallationMode* mode) { + *installer = pkgmgr_installer_offline_new(); + if (!*installer) + return false; + *mode = ci::InstallationMode::ONLINE; + return true; + } + + bool ShouldCreateSignal() const { + return false; + } +}; + +enum class PackageType { + WGT, + HYBRID +}; + +ci::RequestMode ParseRequestMode(int argc, char** argv); + +bool TouchFile(const bf::path& path); + +bool AddUser(const char *user_name); + +bool DeleteUser(const char *user_name, bool rem_home_dir); + +bool AddTestUser(const char *user_name); + +bool DeleteTestUser(const char *user_name); + +void RemoveAllRecoveryFiles(); + +bf::path FindRecoveryFile(); + +bf::path GetPackageRoot(const std::string& pkgid, uid_t uid); + +bool ValidateFileContentInPackage(const std::string& pkgid, + const std::string& relative, + const std::string& expected, + bool is_readonly = false); + +void AddDataFiles(const std::string& pkgid, uid_t uid); + +void ValidateDataFiles(const std::string& pkgid, uid_t uid); + +void ValidatePackageRWFS(const std::string& pkgid, uid_t uid); + +void ValidatePackageFS(const std::string& pkgid, + const std::vector& appids, + uid_t uid, gid_t gid, bool is_readonly); + +void PackageCheckCleanup(const std::string& pkgid, + const std::vector&, bool is_readonly = false); + +void ValidatePackage(const std::string& pkgid, + const std::vector& appids, bool is_readonly = false); + +void ValidateExternalPackageFS(const std::string& pkgid, + const std::vector& appids, + uid_t uid, gid_t gid); + +void ValidateExternalPackage(const std::string& pkgid, + const std::vector& appids); + +void CheckPackageNonExistance(const std::string& pkgid, + const std::vector& appids); + +void CheckPackageReadonlyNonExistance(const std::string& pkgid, + const std::vector& appids); + +std::unique_ptr CreateQueryInterface(); + +std::unique_ptr CreateInstaller(ci::PkgMgrPtr pkgmgr, + PackageType type); + +ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr, + PackageType type, + RequestResult mode); +ci::AppInstaller::Result CallBackend(int argc, + const char* argv[], + PackageType type, + RequestResult mode + = RequestResult::NORMAL); + +ci::AppInstaller::Result Install(const bf::path& path, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result InstallPreload(const bf::path& path, PackageType type, + RequestResult mode = RequestResult::NORMAL); + +bool CheckAvailableExternalPath(); + +ci::AppInstaller::Result InstallExternal(const bf::path& path, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result MigrateLegacyExternalImage(const std::string& pkgid, + const bf::path& path, + const bf::path& legacy_path, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result MountInstall(const bf::path& path, + PackageType type, RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result Uninstall(const std::string& pkgid, + PackageType type, + bool is_preload, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result RDSUpdate(const bf::path& path, + const std::string& pkgid, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result DeltaInstall(const bf::path& path, + const bf::path& delta_package, PackageType type); + +ci::AppInstaller::Result EnablePackage(const std::string& pkgid, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result DisablePackage(const std::string& pkgid, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +ci::AppInstaller::Result Recover(const bf::path& recovery_file, + PackageType type, + RequestResult mode = RequestResult::NORMAL); + +void BackupPath(const bf::path& path); + +void RestorePath(const bf::path& path); + +std::vector SetupBackupDirectories(); + +void UninstallAllAppsInDirectory(bf::path dir, bool is_preload); + +void UninstallAllSmokeApps(ci::RequestMode request_mode); + + +#endif // UNIT_TESTS_SMOKE_UTILS_H_