+// 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 <boost/filesystem/operations.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/format.hpp>
+#include <boost/program_options.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <common/step/configuration/step_fail.h>
+#include <common/utils/user_util.h>
+#include <common/utils/file_util.h>
+#include <common/request.h>
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-death-test.h>
+
+#include <pkgmgr-info.h>
+#include <signal.h>
+#include <unistd.h>
+#include <tzplatform_config.h>
+#include <vconf.h>
+#include <vconf-internal-keys.h>
+
+#include <array>
+#include <cstdio>
+#include <cstdlib>
+#include <regex>
+
+#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<std::string> 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<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;
+ }
+}
+
+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_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 (!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<char, 200> 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<gid_t> 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<std::string>& 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<std::string>&, 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& appids) {
+ ASSERT_FALSE(ci::QueryIsPackageInstalled(
+ pkgid, ci::GetRequestMode(kTestUserId), kTestUserId));
+ PackageCheckCleanup(pkgid, appids, true);
+}
+
+std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
+ std::unique_ptr<ci::AppQueryInterface> query_interface(
+ new wgt::WgtAppQueryInterface());
+ return query_interface;
+}
+
+std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr,
+ PackageType type) {
+ switch (type) {
+ case PackageType::WGT:
+ return std::unique_ptr<ci::AppInstaller>(new wgt::WgtInstaller(pkgmgr));
+ case PackageType::HYBRID:
+ return std::unique_ptr<ci::AppInstaller>(
+ 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<ci::AppInstaller> installer = CreateInstaller(pkgmgr, type);
+ switch (mode) {
+ case RequestResult::FAIL:
+ installer->AddStep<ci::configuration::StepFail>();
+ 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<ci::AppQueryInterface> query_interface =
+ CreateQueryInterface();
+ auto pkgmgr =
+ ci::PkgMgrInterface::Create(argc, const_cast<char**>(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<bf::path> SetupBackupDirectories() {
+ std::vector<bf::path> 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);
+}