1 // Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
5 #include "smoke_tests/common/smoke_utils.h"
7 #include <gum/gum-user.h>
8 #include <gum/gum-user-service.h>
9 #include <gum/common/gum-user-types.h>
10 #include <manifest_parser/utils/version_number.h>
11 #include <sys/smack.h>
13 #include <vconf-internal-keys.h>
15 #include <boost/filesystem/path.hpp>
16 #include <gtest/gtest.h>
18 #include <common/installer/app_installer.h>
19 #include <common/utils/paths.h>
20 #include <common/pkgmgr_interface.h>
21 #include <common/utils/pkgmgr_query.h>
22 #include <common/tzip_interface.h>
24 #include "pkgmgr_parser_db.h"
32 namespace bf = boost::filesystem;
33 namespace bs = boost::system;
34 namespace ci = common_installer;
35 namespace bo = boost::program_options;
39 const uid_t kDefaultUserUid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
40 const gid_t kDefaultUserGid = tzplatform_getgid(TZ_SYS_DEFAULT_USER);
41 const char kNormalUserName[] = "smokeuser";
42 const char kSystemShareGroupName[] = "system_share";
43 const char kMigrateTestDBName[] = "app2sd_migrate.db";
45 const std::vector<std::string> kDBEntries = {
46 {".pkgmgr_parser.db"},
47 {".pkgmgr_parser.db-journal"},
49 {".pkgmgr_cert.db-journal"},
51 {".app2sd.db-journal"},
54 const char kGlobalManifestDir[] = "/opt/share/packages";
55 const char kSkelDir[] = "/etc/skel/apps_rw";
56 const char kPreloadApps[] = "/usr/apps";
57 const char kPreloadManifestDir[] = "/usr/share/packages";
58 const char kPreloadIcons[] = "/usr/share/icons";
59 const char kData[] = "data";
60 const char kShared[] = ".shared";
61 const char kSharedTmp[] = ".shared_tmp";
71 const char* rwDirectories[] = {
81 namespace smoke_test {
83 const char kLegacyExtImageDir[] = "legacy_extimage_dir";
84 const std::string& kDefaultUserIdStr = std::to_string(kDefaultUserUid);
85 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
86 const uid_t kGlobalUserGid = tzplatform_getgid(TZ_SYS_GLOBALAPP_USER);
87 extern const bf::path kSdkDirectory = "/home/owner/share/tmp/sdk_tools";
89 ci::RequestMode ParseRequestMode(int argc, char** argv) {
90 bo::options_description desc("Available options");
92 ("request-mode", bo::value<std::string>(), "set request mode")
93 ("global-request,g", "set request mode to global")
94 ("user-request,u", "set request mode to user");
97 bo::store(bo::command_line_parser(argc, argv).
98 options(desc).allow_unregistered().run(), vm);
101 if (vm.count("global-request")) {
102 std::cout << "Request mode was set to global." << std::endl;
103 return ci::RequestMode::GLOBAL;
105 if (vm.count("user-request")) {
106 std::cout << "Request mode was set to user." << std::endl;
107 return ci::RequestMode::USER;
109 if (vm.count("request-mode")) {
110 if (vm["request-mode"].as<std::string>() == "global") {
111 std::cout << "Request mode was set to global." << std::endl;
112 return ci::RequestMode::GLOBAL;
114 if (vm["request-mode"].as<std::string>() == "user") {
115 std::cout << "Request mode was set to user." << std::endl;
116 return ci::RequestMode::USER;
118 std::cout << "Cannot set request mode to "
119 << vm["request-mode"].as<std::string>() << std::endl;
121 std::cout << "Request mode was set to global." << std::endl;
122 return ci::RequestMode::GLOBAL;
125 static bool AddUser(const char* user_name) {
126 GumUser* user = nullptr;
127 user = gum_user_create_sync(FALSE);
129 LOG(WARNING) << "Failed to create gum user! (user name: "
131 g_object_set(G_OBJECT(user), "username", user_name, "usertype",
132 GUM_USERTYPE_NORMAL, NULL);
133 gboolean rval = FALSE;
134 rval = gum_user_add_sync(user);
135 g_object_unref(user);
139 static bool DeleteUser(const char* user_name, bool rem_home_dir) {
141 GumUser* guser = gum_user_get_by_name_sync(user_name, FALSE);
143 rval = gum_user_delete_sync(guser, rem_home_dir);
147 bool AddTestUser(User* test_user) {
148 std::cout << "Adding test user: " << kNormalUserName << std::endl;
149 AddUser(kNormalUserName);
150 if (boost::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName)) {
151 test_user->uid = *uid;
152 std::cout << "User created properly: uid=" << *uid;
153 if (boost::optional<gid_t> gid = ci::GetGidByUid(*uid)) {
154 test_user->gid = *gid;
155 std::cout << " gid=" << *gid;
157 std::cout << std::endl;
160 LOG(ERROR) << "Adding test user failed";
164 bool DeleteTestUser() {
165 std::cout << "Deleting test user: " << kNormalUserName << std::endl;
167 if (boost::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName))
171 DeleteUser(kNormalUserName, true);
172 if (!ci::GetUidByUserName(kNormalUserName)) {
173 std::cout << "User deleted properly: user_name=" << kNormalUserName
174 << " uid=" << test_uid << std::endl;
177 LOG(ERROR) << "Deleting test user failed";
181 bool TouchFile(const bf::path& path) {
182 FILE* f = fopen(path.c_str(), "w+");
189 void AddDataFiles(const std::string& pkgid, uid_t uid,
190 std::vector<bf::path>* result) {
191 std::vector<bf::path> files;
193 if (uid == kGlobalUserUid) {
194 ci::UserList list = ci::GetUserList();
195 for (auto l : list) {
196 auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
197 files.emplace_back(pkg_path / "data" / "file1.txt");
198 files.emplace_back(pkg_path / "data" / "file2.txt");
201 auto pkg_path = GetPackageRoot(pkgid, uid);
202 files.emplace_back(pkg_path / "data" / "file1.txt");
203 files.emplace_back(pkg_path / "data" / "file2.txt");
206 for (const auto& path : files)
207 ASSERT_TRUE(TouchFile(path));
210 *result = std::move(files);
213 void RemoveAllRecoveryFiles(const std::string& prefix, uid_t uid) {
214 bf::path root_path = ci::GetRootAppPath(false, uid);
215 if (!bf::exists(root_path))
217 for (auto& dir_entry : boost::make_iterator_range(
218 bf::directory_iterator(root_path), bf::directory_iterator())) {
219 if (bf::is_regular_file(dir_entry)) {
220 if (dir_entry.path().string().find(prefix) != std::string::npos) {
221 bs::error_code error;
222 bf::remove(dir_entry.path(), error);
224 LOG(ERROR) << "Failed to remove " << dir_entry.path()
225 << ": " << error.message();
231 bf::path FindRecoveryFile(const std::string& prefix, uid_t uid) {
232 bf::path root_path = ci::GetRootAppPath(false, uid);
233 if (!bf::exists(root_path))
236 for (auto& dir_entry : boost::make_iterator_range(
237 bf::directory_iterator(root_path), bf::directory_iterator())) {
238 if (bf::is_regular_file(dir_entry)) {
239 if (dir_entry.path().string().find(prefix) != std::string::npos) {
240 return dir_entry.path();
247 std::unique_ptr<ci::recovery::RecoveryFile> GetRecoverFileInfo(
248 const bf::path& recovery_file_path) {
249 return ci::recovery::RecoveryFile::OpenRecoveryFile(recovery_file_path);
252 bf::path GetPackageRoot(const std::string& pkgid, uid_t uid) {
253 bf::path root_path = ci::GetRootAppPath(false, uid);
254 return root_path / pkgid;
257 bool ValidateFileContentInPackage(const std::string& pkgid,
258 const std::string& relative,
259 const std::string& expected,
260 const TestParameters& params) {
261 bf::path file_path = ci::GetRootAppPath(params.is_readonly,
262 params.test_user.uid);
263 file_path = file_path / pkgid / relative;
264 if (!bf::exists(file_path)) {
265 LOG(ERROR) << file_path << " doesn't exist";
268 FILE* handle = fopen(file_path.c_str(), "r");
270 LOG(ERROR) << file_path << " cannot be open";
274 std::array<char, 200> buffer;
275 while (fgets(buffer.data(), buffer.size(), handle)) {
276 content += buffer.data();
279 return content == expected;
282 static bool ValidatePackageRWFS(const std::string& pkgid, uid_t uid) {
283 bf::path root_path = ci::GetRootAppPath(false, uid);
284 bf::path package_path = root_path / pkgid;
285 bf::path data_path = package_path / rwDirectories[DATA];
286 bf::path cache_path = package_path / rwDirectories[CACHE];
287 bf::path shared_data_path = package_path / rwDirectories[SHARED_DATA];
289 EXTENDED_ASSERT_TRUE(bf::exists(data_path));
290 EXTENDED_ASSERT_TRUE(bf::exists(cache_path));
293 stat(data_path.c_str(), &stats);
294 // gid of RW dirs should be system_share
295 boost::optional<gid_t> system_share =
296 ci::GetGidByGroupName(kSystemShareGroupName);
297 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
298 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
299 if (bf::exists(shared_data_path)) {
300 stat(shared_data_path.c_str(), &stats);
301 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
302 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
305 stat(cache_path.c_str(), &stats);
306 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
307 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
311 static bool ValidatePackageFS(const std::string& pkgid, const Apps& apps,
312 const TestParameters& params) {
313 bf::path root_path = ci::GetRootAppPath(params.is_readonly,
314 params.test_user.uid);
315 bf::path package_path = root_path / pkgid;
316 bf::path shared_path = package_path / "shared";
317 EXTENDED_ASSERT_TRUE(bf::exists(root_path));
318 EXTENDED_ASSERT_TRUE(bf::exists(package_path));
319 EXTENDED_ASSERT_TRUE(bf::exists(shared_path));
321 bf::path manifest_path =
322 bf::path(getUserManifestPath(params.test_user.uid,
323 params.is_readonly)) / (pkgid + ".xml");
324 EXTENDED_ASSERT_TRUE(bf::exists(manifest_path));
326 for (auto& app : apps) {
327 const std::string &exec = app.second;
328 bf::path binary_path = package_path / "bin" / exec;
329 EXTENDED_ASSERT_TRUE(bf::exists(binary_path));
332 if (params.pkg_type == PackageType::WGT ||
333 params.pkg_type == PackageType::HYBRID) {
334 bf::path widget_root_path = package_path / "res" / "wgt";
335 bf::path config_path = widget_root_path / "config.xml";
336 EXTENDED_ASSERT_TRUE(bf::exists(widget_root_path));
337 EXTENDED_ASSERT_TRUE(bf::exists(config_path));
339 bf::path private_tmp_path = package_path / "tmp";
340 EXTENDED_ASSERT_TRUE(bf::exists(private_tmp_path));
343 // backups should not exist
344 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
345 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
346 EXTENDED_ASSERT_FALSE(bf::exists(package_backup));
347 EXTENDED_ASSERT_FALSE(bf::exists(manifest_backup));
349 for (bf::recursive_directory_iterator iter(package_path);
350 iter != bf::recursive_directory_iterator(); ++iter) {
351 if (bf::is_symlink(symlink_status(iter->path())))
353 bool is_rw_dir = false;
354 for (const auto rw_dir : rwDirectories) {
355 bf::path rw_dir_path = rw_dir;
356 is_rw_dir |= ci::MakeRelativePath(iter->path(), package_path)
359 if (is_rw_dir || iter->path().filename() == ".mmc") {
364 stat(iter->path().c_str(), &stats);
365 EXTENDED_ASSERT_EQ(params.test_user.uid, stats.st_uid);
366 EXTENDED_ASSERT_EQ(params.test_user.gid, stats.st_gid);
371 bool ValidatePackage(const std::string& pkgid, const Apps& apps,
372 const TestParameters& params) {
373 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
374 EXTENDED_ASSERT_TRUE(pkg_query.IsPackageInstalled(
375 ci::GetRequestMode(params.test_user.uid)));
376 EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, apps, params));
377 if (params.test_user.uid == kGlobalUserUid) {
378 ci::UserList list = ci::GetUserList();
380 EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, std::get<0>(l)));
382 EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, params.test_user.uid));
387 bool ValidateDataFiles(const std::string& pkgid, uid_t uid) {
388 if (uid == kGlobalUserUid) {
389 ci::UserList list = ci::GetUserList();
390 for (auto l : list) {
391 auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
392 EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
393 EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
396 auto pkg_path = GetPackageRoot(pkgid, uid);
397 EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
398 EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
403 static bool ValidateExternalPackageFS(const std::string& pkgid,
404 const Apps& apps, const TestParameters& params) {
405 EXTENDED_ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(),
406 params.test_user.uid), 0);
407 bf::path root_path = ci::GetRootAppPath(false, params.test_user.uid);
408 if (params.pkg_type == PackageType::TPK) {
409 EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "bin"));
410 EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "lib"));
412 EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "res"));
413 EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, apps, params));
414 EXTENDED_ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(),
415 params.test_user.uid), 0);
419 bool ValidateExternalPackage(const std::string& pkgid, const Apps& apps,
420 const TestParameters& params) {
421 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
422 std::string storage = pkg_query.StorageForPkgId();
423 bf::path ext_mount_path = ci::GetExternalCardPath();
424 if (bf::is_empty(ext_mount_path)) {
425 LOG(INFO) << "Sdcard not exists!";
426 EXTENDED_ASSERT_EQ(storage, "installed_internal");
428 EXTENDED_ASSERT_EQ(storage, "installed_external");
430 EXTENDED_ASSERT_TRUE(ValidateExternalPackageFS(pkgid, apps, params));
434 bool ValidateExtendedPackage(const std::string& pkgid, const Apps& apps,
435 const TestParameters& params) {
436 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
437 std::string storage = pkg_query.StorageForPkgId();
438 bf::path extended_path =
439 bf::path(ci::GetExtendedRootAppPath(params.test_user.uid)) / pkgid;
440 if (!bf::exists(extended_path)) {
441 LOG(INFO) << "Extended storage not exists!";
442 EXTENDED_ASSERT_EQ(storage, "installed_internal");
444 EXTENDED_ASSERT_EQ(storage, "installed_extended");
446 EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, apps, params));
450 static bool PackageCheckCleanup(const std::string& pkgid,
451 const TestParameters& params) {
452 bf::path root_path = ci::GetRootAppPath(params.is_readonly,
453 params.test_user.uid);
454 bf::path package_path = root_path / pkgid;
455 EXTENDED_ASSERT_FALSE(bf::exists(package_path));
457 bf::path manifest_path = bf::path(getUserManifestPath(params.test_user.uid,
458 params.is_readonly)) / (pkgid + ".xml");
459 EXTENDED_ASSERT_FALSE(bf::exists(manifest_path));
461 // backups should not exist
462 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
463 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
464 EXTENDED_ASSERT_FALSE(bf::exists(package_backup));
465 EXTENDED_ASSERT_FALSE(bf::exists(manifest_backup));
469 bool CheckPackageNonExistance(const std::string& pkgid,
470 const TestParameters& params) {
471 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
472 EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
473 ci::GetRequestMode(params.test_user.uid)));
474 EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
475 if (params.test_user.uid == kGlobalUserUid) {
476 bf::path skel_path(kSkelDir);
477 EXTENDED_ASSERT_FALSE(bf::exists(skel_path / pkgid));
478 EXTENDED_ASSERT_FALSE(bf::exists(skel_path / kShared / pkgid));
479 EXTENDED_ASSERT_FALSE(bf::exists(skel_path / kSharedTmp / pkgid));
480 ci::UserList list = ci::GetUserList();
481 for (auto& l : list) {
482 bf::path root_path = ci::GetRootAppPath(false, std::get<0>(l));
483 EXTENDED_ASSERT_FALSE(bf::exists(root_path / kShared / pkgid));
484 EXTENDED_ASSERT_FALSE(bf::exists(root_path / kSharedTmp / pkgid));
485 bf::path package_path = root_path / pkgid;
486 EXTENDED_ASSERT_FALSE(bf::exists(package_path));
492 bool CheckAvailableExternalPath() {
493 bf::path ext_mount_path = ci::GetExternalCardPath();
494 LOG(DEBUG) << "ext_mount_path :" << ext_mount_path;
495 if (ext_mount_path.empty()) {
496 LOG(ERROR) << "Sdcard not exists!";
502 bool CheckAvailableExtendedPath() {
503 bf::path extended_path = bf::path(tzplatform_getenv(TZ_SYS_EXTENDEDSD));
504 LOG(DEBUG) << "extended_path :" << extended_path;
505 // TODO(jeremy.jang): It should be checked by libstorage API.
506 if (!bf::exists(extended_path)) {
507 LOG(ERROR) << "Extended storage not exists!";
513 bool CheckPackageReadonlyNonExistance(const std::string& pkgid,
514 const TestParameters& params) {
515 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
516 EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
517 ci::GetRequestMode(params.test_user.uid)));
518 EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
522 static bool CheckSharedDataExistanceForPath(const bf::path& apps_rw,
523 const std::string& pkgid) {
524 bf::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
525 bf::path shared = apps_rw / kShared / pkgid / kData;
526 bf::path shared_tmp = apps_rw / kSharedTmp / pkgid;
527 EXTENDED_ASSERT_TRUE(bf::exists(shared_data_path));
528 EXTENDED_ASSERT_TRUE(bf::exists(shared));
529 EXTENDED_ASSERT_TRUE(bf::exists(shared_tmp));
533 static bool CheckSharedDataPermissions(const bf::path& apps_rw,
534 const std::string& pkgid, uid_t uid) {
535 bf::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
536 bf::path shared = apps_rw / kShared / pkgid / kData;
537 bf::path shared_tmp = apps_rw / kSharedTmp / pkgid;
538 // gid of RW dirs should be system_share
539 boost::optional<gid_t> system_share =
540 ci::GetGidByGroupName(kSystemShareGroupName);
542 stat(shared_data_path.c_str(), &stats);
543 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
544 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
545 stat(shared.c_str(), &stats);
546 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
547 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
548 stat(shared_tmp.c_str(), &stats);
549 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
550 EXTENDED_ASSERT_EQ(kDefaultUserGid, stats.st_gid);
554 bool CheckSharedDataExistance(const std::string& pkgid,
555 const TestParameters& params) {
556 if (params.test_user.uid == kGlobalUserUid) {
557 bf::path skel_path(kSkelDir);
558 EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(kSkelDir, pkgid));
559 ci::UserList list = ci::GetUserList();
560 for (auto& l : list) {
561 uid_t uid = std::get<0>(l);
562 bf::path apps_rw = ci::GetRootAppPath(false, uid);
563 EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(apps_rw, pkgid));
564 EXTENDED_ASSERT_TRUE(CheckSharedDataPermissions(apps_rw, pkgid, uid));
567 bf::path apps_rw = ci::GetRootAppPath(false, params.test_user.uid);
568 EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(apps_rw, pkgid));
569 EXTENDED_ASSERT_TRUE(
570 CheckSharedDataPermissions(apps_rw, pkgid, params.test_user.uid));
575 static bool CheckSharedDataNonExistanceForPath(const bf::path& apps_rw,
576 const std::string pkgid) {
577 bf::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
578 bf::path shared = apps_rw / kShared / pkgid / kData;
579 bf::path shared_tmp = apps_rw / kSharedTmp / pkgid;
580 EXTENDED_ASSERT_FALSE(bf::exists(shared_data_path));
581 EXTENDED_ASSERT_FALSE(bf::exists(shared));
582 EXTENDED_ASSERT_FALSE(bf::exists(shared_tmp));
586 bool CheckSharedDataNonExistance(const std::string& pkgid,
587 const TestParameters& params) {
588 if (params.test_user.uid == kGlobalUserUid) {
589 bf::path skel_path(kSkelDir);
590 EXTENDED_ASSERT_TRUE(
591 CheckSharedDataNonExistanceForPath(skel_path, pkgid));
593 ci::UserList list = ci::GetUserList();
594 for (auto& l : list) {
595 uid_t uid = std::get<0>(l);
596 bf::path apps_rw = ci::GetRootAppPath(false, uid);
597 EXTENDED_ASSERT_TRUE(CheckSharedDataNonExistanceForPath(apps_rw, pkgid));
600 bf::path apps_rw = ci::GetRootAppPath(false, params.test_user.uid);
601 EXTENDED_ASSERT_TRUE(CheckSharedDataNonExistanceForPath(apps_rw, pkgid));
606 void FileInfoCollector::AddPath(const bf::path& path) {
607 root_paths_.emplace_back(path);
610 bool FileInfoCollector::CollectFileInfoRecursive() {
611 for (const auto& path : root_paths_) {
612 if (!bf::exists(path) && !bf::is_symlink(path))
615 if (!GetFileListTraversal(path))
622 bool FileInfoCollector::GetFileListTraversal(const bf::path& cur) {
623 bs::error_code error;
624 bf::file_status file_status = bf::symlink_status(cur, error);
626 LOG(ERROR) << "Fail to get symlink_status, " << error.message();
631 if (lstat(cur.c_str(), &info) != 0) {
632 LOG(ERROR) << "Fail to lstat from [" << cur << "]";
636 std::string owner = ci::GetUsernameByUid(info.st_uid);
637 std::string group = ci::GetGroupNameByGid(info.st_gid);
639 char* access_label = nullptr;
640 if (smack_lgetlabel(cur.c_str(), &access_label, SMACK_LABEL_ACCESS) < 0) {
641 LOG(ERROR) << "Fail to get access label from [" << cur << "]";
645 if (access_label == nullptr) {
646 LOG(ERROR) << "Fail to get access label from [" << cur << "]";
650 FileInfos_.emplace_back(cur, file_status.type(),
651 file_status.permissions(), owner, group, access_label);
653 if (!bf::is_directory(cur) || bf::is_symlink(cur))
656 for (bf::directory_iterator file(cur);
657 file != bf::directory_iterator();
659 if (!GetFileListTraversal(file->path())) {
668 bool FileInfoCollector::FileInfoToFile(const bf::path& path) const {
669 std::ofstream out(path.string());
671 for (const auto& info : FileInfos_)
672 out << FileInfoToString(info) << std::endl;
679 bool FileInfoCollector::Init() {
680 bf::path skel_apps_rw = bf::path(kSkelDir);
682 ci::GetRootAppPath(params_.is_readonly, params_.test_user.uid);
684 AddPath(root_path / pkgid_);
685 AddPath(skel_apps_rw / pkgid_);
687 if (params_.test_user.uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) {
689 ci::UserList list = ci::GetUserList();
690 for (auto l : list) {
691 bf::path apps_rw = std::get<2>(l) / "apps_rw";
692 AddPath(apps_rw / pkgid_);
693 AddPath(apps_rw / kShared / pkgid_);
694 AddPath(apps_rw / kSharedTmp / pkgid_);
697 AddPath(root_path / kShared / pkgid_);
698 AddPath(root_path / kSharedTmp / pkgid_);
701 if (!CollectFileInfoRecursive())
704 std::sort(FileInfos_.begin(), FileInfos_.end(),
705 [](const FileInfo& l, const FileInfo& r) -> bool {
706 return std::get<0>(l) < std::get<0>(r);
712 bool FileInfoCollector::LoadFromFile(const bf::path& path) {
713 std::ifstream readFile;
714 readFile.open(path.c_str());
716 if (!readFile.is_open()) {
717 LOG(ERROR) << "Fail to read file : " << path;
723 while (std::getline(readFile, line)) {
724 std::istringstream iss(line);
730 std::string access_label;
732 iss >> p >> file_type >> std::oct >> file_permission
733 >> owner >> group >> access_label;
735 FileInfos_.emplace_back(p, bf::file_type(file_type),
736 bf::perms(file_permission), owner, group, access_label);
744 std::string FileInfoCollector::FileInfoToString(
745 const FileInfo& file_info) const {
746 bf::path p = std::get<0>(file_info);
747 bf::file_type file_type = std::get<1>(file_info);
748 std::string file_permission;
749 std::string owner = std::get<3>(file_info);
750 std::string group = std::get<4>(file_info);
751 std::string access_label = std::get<5>(file_info);
752 std::stringstream ss;
753 ss << std::oct << std::get<2>(file_info);
754 ss >> file_permission;
759 res += std::to_string(file_type);
761 res += file_permission;
772 bool FileInfoCollector::IsEqual(const FileInfoCollector& that,
773 const std::vector<bf::path>* exception_list) const {
774 auto it_l = FileInfos_.begin();
775 auto it_r = that.FileInfos_.begin();
778 while (it_l != FileInfos_.end() && it_r != that.FileInfos_.end()) {
779 if (*it_l == *it_r) {
785 bf::path path_l = std::get<0>(*it_l);
786 bf::path path_r = std::get<0>(*it_r);
787 if (exception_list && path_l == path_r &&
788 std::find(exception_list->begin(), exception_list->end(), path_r)
789 != exception_list->end()) {
797 if (path_l > path_r) {
798 LOG(ERROR) << "There is an unexpected file [" << path_r << "]";
800 } else if (path_l < path_r) {
801 LOG(ERROR) << "There is not exists an expected file [" << path_l << "]";
804 LOG(ERROR) << "There is a different status file. expected ["
805 << FileInfoToString(*it_l) << "], result ["
806 << FileInfoToString(*it_r) << "]";
812 while (it_l != FileInfos_.end()) {
813 LOG(ERROR) << "There is an unexpected file [" << std::get<0>(*it_l) << "]";
818 while (it_r != that.FileInfos_.end()) {
819 LOG(ERROR) << "There is not exists an expected file ["
820 << std::get<0>(*it_r) << "]";
828 void BackendInterface::TestRollbackAfterEachStep(int argc, const char* argv[],
829 std::function<bool()> validator) const {
830 ci::Subprocess backend_helper = CreateSubprocess();
831 bool result = backend_helper.RunFunc({[&]() -> int {
832 TestPkgmgrInstaller pkgmgr_installer;
833 std::shared_ptr<ci::AppQueryInterface> query_interface =
834 CreateQueryInterface();
836 ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
840 LOG(ERROR) << "Failed to initialize pkgmgr interface";
843 AppInstallerPtr backend;
844 unsigned int insert_idx = 0;
846 backend = CreateFailExpectedInstaller(pkgmgr, insert_idx);
847 LOG(DEBUG) << "StepFail is inserted at: " << insert_idx;
848 ci::AppInstaller::Result ret = backend->Run();
849 if (ret != ci::AppInstaller::Result::ERROR) {
850 LOG(ERROR) << "StepFail not executed";
854 LOG(ERROR) << "Fail to validate. index of StepFail : " << insert_idx;
858 } while (insert_idx < backend->StepCount());
859 if (insert_idx != backend->StepCount())
864 ASSERT_EQ(result, true);
865 int status = backend_helper.Wait();
866 ASSERT_NE(WIFEXITED(status), 0);
867 ASSERT_EQ(WEXITSTATUS(status), 0);
870 void BackendInterface::CrashAfterEachStep(std::vector<std::string>* args,
871 std::function<bool(int iter)> validator, PackageType type) const {
872 ci::Subprocess backend_helper = CreateSubprocess();
873 bool result = backend_helper.RunFunc({[&]() {
874 std::unique_ptr<const char*[]> argv(new const char*[args->size()]);
875 for (size_t i = 0; i < args->size(); ++i) {
876 argv[i] = args->at(i).c_str();
878 TestPkgmgrInstaller pkgmgr_installer;
879 auto query_interface = CreateQueryInterface();
880 auto pkgmgr = ci::PkgMgrInterface::Create(args->size(),
881 const_cast<char**>(argv.get()), &pkgmgr_installer, query_interface);
883 LOG(ERROR) << "Failed to initialize pkgmgr interface";
886 auto backend = CreateFailExpectedInstaller(pkgmgr, 0);
887 if (backend->Run() != ci::AppInstaller::Result::ERROR) {
888 LOG(ERROR) << "StepFail not executed";
891 int stepCount = backend->StepCount();
893 args->push_back("-idx");
894 args->push_back(std::to_string(stepCount));
896 std::string prefix = (type == PackageType::TPK) ? "tpk" : "wgt";
897 for (insert_idx = 0; insert_idx < stepCount; insert_idx++) {
898 ci::Subprocess backend_crash(
899 "/usr/bin/" + prefix + "-installer-ut/smoke-test-helper");
900 args->back() = std::to_string(insert_idx);
901 backend_crash.Run(*args);
902 if (backend_crash.Wait() == 0) {
903 LOG(ERROR) << "Subprocess exit without crash";
906 if (!validator(insert_idx)) {
907 LOG(ERROR) << "Fail to validate. index of StepCrash : " << insert_idx;
911 if (stepCount != insert_idx)
914 args->push_back("-type_clean");
915 for (insert_idx = stepCount - 1; insert_idx >= 2; insert_idx--) {
916 ci::Subprocess backend_crash(
917 "/usr/bin/" + prefix + "-installer-ut/smoke-test-helper");
918 auto it = args->end();
920 *it = std::to_string(insert_idx);
921 backend_crash.Run(*args);
922 if (backend_crash.Wait() == 0) {
923 LOG(ERROR) << "Subprocess exit without crash";
926 if (!validator(insert_idx)) {
927 LOG(ERROR) << "Fail to validate. index of StepCrash : " << insert_idx;
937 ASSERT_EQ(result, true);
938 int status = backend_helper.Wait();
939 ASSERT_NE(WIFEXITED(status), 0);
940 ASSERT_EQ(WEXITSTATUS(status), 0);
943 BackendInterface::CommandResult BackendInterface::RunInstallersWithPkgmgr(
944 ci::PkgMgrPtr pkgmgr) const {
945 std::list<AppInstallerPtr> installers;
946 for (int i = 0; i < pkgmgr->GetRequestInfoCount(); i++) {
947 AppInstallerPtr installer;
948 if (mode_ == RequestResult::FAIL && i == pkgmgr->GetRequestInfoCount() - 1)
949 installer = factory_->CreateFailExpectedInstaller(i, pkgmgr);
951 installer = factory_->CreateInstaller(i, pkgmgr);
953 LOG(ERROR) << "Failed to create installer";
955 installers.emplace_back(std::move(installer));
958 // FIXME: I think we should not implement this logic here...
959 CommandResult result = CommandResult::OK;
960 std::list<AppInstallerPtr>::iterator it(installers.begin());
961 for (; it != installers.end(); ++it) {
962 result = (*it)->Process();
963 if (result != CommandResult::OK)
966 if (it != installers.end() && result == CommandResult::ERROR) {
968 CommandResult ret = (*it)->Undo();
969 if (ret != CommandResult::OK && ret != CommandResult::ERROR)
970 result = CommandResult::UNDO_ERROR;
971 } while (it-- != installers.begin());
975 if ((*it)->Clean() != CommandResult::OK)
976 result = CommandResult::CLEANUP_ERROR;
977 } while (it-- != installers.begin());
982 BackendInterface::CommandResult BackendInterface::CallBackendWithRunner(
983 int argc, const char* argv[]) const {
984 TestPkgmgrInstaller pkgmgr_installer;
985 auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
988 LOG(ERROR) << "Failed to initialize pkgmgr interface";
989 return BackendInterface::CommandResult::UNKNOWN;
991 return RunInstallersWithPkgmgr(pkgmgr);
994 BackendInterface::CommandResult BackendInterface::Install(
995 const std::vector<bf::path>& paths) const {
996 std::vector<const char*> argv;
997 argv.emplace_back("");
998 argv.emplace_back("-i");
999 for (const auto& p : paths)
1000 argv.emplace_back(p.string().c_str());
1001 return CallBackendWithRunner(argv.size(), argv.data());
1004 BackendInterface::CommandResult BackendInterface::Uninstall(
1005 const std::vector<std::string>& pkgids) const {
1006 std::vector<const char*> argv;
1007 argv.emplace_back("");
1008 argv.emplace_back("-d");
1009 for (const auto& p : pkgids)
1010 argv.emplace_back(p.c_str());
1011 return CallBackendWithRunner(argv.size(), argv.data());
1014 BackendInterface::CommandResult BackendInterface::InstallSuccess(
1015 const std::vector<bf::path>& paths) const {
1016 RequestResult tmp_mode = mode_;
1017 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1018 original_mode = RequestResult::NORMAL;
1019 if (Install(paths) != BackendInterface::CommandResult::OK) {
1020 LOG(ERROR) << "Failed to install application. Cannot update";
1021 return BackendInterface::CommandResult::UNKNOWN;
1023 original_mode = tmp_mode;
1024 return BackendInterface::CommandResult::OK;
1027 BackendInterface::CommandResult BackendInterface::RunInstallerWithPkgrmgr(
1028 ci::PkgMgrPtr pkgmgr) const {
1029 std::unique_ptr<ci::AppInstaller> installer;
1031 case RequestResult::FAIL:
1032 installer = CreateFailExpectedInstaller(pkgmgr);
1035 installer = CreateInstaller(pkgmgr);
1038 return installer->Run();
1041 BackendInterface::CommandResult BackendInterface::CallBackend(int argc,
1042 const char* argv[]) const {
1043 TestPkgmgrInstaller pkgmgr_installer;
1044 auto query_interface = CreateQueryInterface();
1045 auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
1046 &pkgmgr_installer, query_interface);
1048 LOG(ERROR) << "Failed to initialize pkgmgr interface";
1049 return BackendInterface::CommandResult::UNKNOWN;
1051 return RunInstallerWithPkgrmgr(pkgmgr);
1054 BackendInterface::CommandResult BackendInterface::Install(
1055 const bf::path& path) const {
1056 const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
1057 return CallBackend(SIZEOFARRAY(argv), argv);
1060 BackendInterface::CommandResult BackendInterface::InstallPreload(
1061 const bf::path& path) const {
1062 const char* argv[] = {"", "-i", path.c_str(), "--preload"};
1063 return CallBackend(SIZEOFARRAY(argv), argv);
1066 BackendInterface::CommandResult BackendInterface::InstallWithStorage(
1067 const bf::path& path, StorageType type) const {
1068 int default_storage = 0;
1071 case StorageType::EXTERNAL:
1074 case StorageType::EXTENDED:
1078 LOG(ERROR) << "Unknown storage type";
1081 if (vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
1082 &default_storage) != 0) {
1083 LOG(ERROR) << "Failed to get value of "
1084 "VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT";
1085 return BackendInterface::CommandResult::ERROR;
1087 if (vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
1089 LOG(ERROR) << "Failed to set value of "
1090 "VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT";
1091 return BackendInterface::CommandResult::ERROR;
1094 const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
1095 BackendInterface::CommandResult result = CallBackend(SIZEOFARRAY(argv), argv);
1097 if (vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
1098 default_storage) != 0) {
1099 LOG(ERROR) << "Failed to set value of "
1100 "VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT";
1101 return BackendInterface::CommandResult::ERROR;
1107 BackendInterface::CommandResult BackendInterface::MigrateLegacyExternalImage(
1108 const std::string& pkgid,
1109 const bf::path& path,
1110 const bf::path& legacy_path) const {
1111 if (InstallWithStorage(path, StorageType::EXTERNAL) !=
1112 BackendInterface::CommandResult::OK) {
1113 LOG(ERROR) << "Failed to install application. Cannot perform Migrate";
1114 return BackendInterface::CommandResult::ERROR;
1117 bf::path ext_mount_path = ci::GetExternalCardPath();
1118 if (bf::is_empty(ext_mount_path)) {
1119 LOG(ERROR) << "Sdcard not exists!";
1120 return BackendInterface::CommandResult::ERROR;
1122 bf::path app2sd_path = ext_mount_path / "app2sd";
1124 char* image_name = app2ext_usr_getname_image(pkgid.c_str(),
1127 LOG(ERROR) << "Failed to get external image name";
1128 return BackendInterface::CommandResult::ERROR;
1130 bf::path org_image = app2sd_path / image_name;
1133 bs::error_code error;
1134 bf::remove(org_image, error);
1136 LOG(ERROR) << "Failed to remove org image";
1137 return BackendInterface::CommandResult::ERROR;
1140 bf::path db_path = tzplatform_getenv(TZ_SYS_DB);
1141 bf::path app2sd_db = db_path / ".app2sd.db";
1142 bf::path app2sd_db_journal = db_path / ".app2sd.db-journal";
1143 bf::remove(app2sd_db, error);
1145 LOG(ERROR) << "Failed to remove app2sd db";
1146 return BackendInterface::CommandResult::ERROR;
1148 bf::remove(app2sd_db_journal, error);
1150 LOG(ERROR) << "Failed to remove app2sd journal db";
1151 return BackendInterface::CommandResult::ERROR;
1154 bf::path app2sd_migrate_db = legacy_path / kMigrateTestDBName;
1155 if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) {
1156 LOG(ERROR) << "Failed to copy test db";
1157 return BackendInterface::CommandResult::ERROR;
1160 bf::path legacy_src = legacy_path / pkgid;
1161 bf::path legacy_dst = app2sd_path / pkgid;
1162 if (!ci::CopyFile(legacy_src, legacy_dst)) {
1163 LOG(ERROR) << "Failed to copy test image";
1164 return BackendInterface::CommandResult::ERROR;
1166 const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(),
1167 "-u", uid_str_.c_str()};
1168 return CallBackend(SIZEOFARRAY(argv), argv);
1171 BackendInterface::CommandResult BackendInterface::RDSUpdate(
1172 const bf::path& path,
1173 const std::string& pkgid) const {
1174 RequestResult tmp_mode = mode_;
1175 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1176 original_mode = RequestResult::NORMAL;
1177 if (Install(path) != BackendInterface::CommandResult::OK) {
1178 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
1179 return BackendInterface::CommandResult::UNKNOWN;
1181 const char* argv[] = {"", "-r", pkgid.c_str(), "-u",
1183 original_mode = tmp_mode;
1184 return CallBackend(SIZEOFARRAY(argv), argv);
1187 BackendInterface::CommandResult BackendInterface::EnablePackage(
1188 const std::string& pkgid) const {
1189 const char* argv[] = {"", "-A", pkgid.c_str(), "-u", uid_str_.c_str()};
1190 return CallBackend(SIZEOFARRAY(argv), argv);
1193 BackendInterface::CommandResult BackendInterface::DisablePackage(
1194 const std::string& pkgid) const {
1195 const char* argv[] = {"", "-D", pkgid.c_str(), "-u", uid_str_.c_str()};
1196 return CallBackend(SIZEOFARRAY(argv), argv);
1199 BackendInterface::CommandResult BackendInterface::Recover(
1200 const bf::path& recovery_file) const {
1201 const char* argv[] = {"", "-b", recovery_file.c_str(), "-u",
1203 return CallBackend(SIZEOFARRAY(argv), argv);
1206 BackendInterface::CommandResult BackendInterface::ManifestDirectInstall(
1207 const std::string& pkgid) const {
1208 const char* argv[] = {"", "-y", pkgid.c_str(), "-u", uid_str_.c_str()};
1209 return CallBackend(SIZEOFARRAY(argv), argv);
1212 BackendInterface::CommandResult BackendInterface::Uninstall(
1213 const std::string& pkgid) const {
1214 const char* argv[] = {"", "-d", pkgid.c_str(), "-u", uid_str_.c_str()};
1215 return CallBackend(SIZEOFARRAY(argv), argv);
1218 BackendInterface::CommandResult BackendInterface::UninstallPreload(
1219 const std::string& pkgid) const {
1220 const char* argv[] = {"", "-d", pkgid.c_str(), "--preload",
1222 return CallBackend(SIZEOFARRAY(argv), argv);
1225 BackendInterface::CommandResult BackendInterface::InstallSuccess(
1226 const bf::path& path) const {
1227 RequestResult tmp_mode = mode_;
1228 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1229 original_mode = RequestResult::NORMAL;
1230 if (Install(path) != BackendInterface::CommandResult::OK) {
1231 LOG(ERROR) << "Failed to install application. Cannot update";
1232 return BackendInterface::CommandResult::UNKNOWN;
1234 original_mode = tmp_mode;
1235 return BackendInterface::CommandResult::OK;
1238 BackendInterface::CommandResult BackendInterface::InstallPreloadSuccess(
1239 const bf::path& path) const {
1240 RequestResult tmp_mode = mode_;
1241 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1242 original_mode = RequestResult::NORMAL;
1243 if (InstallPreload(path) != BackendInterface::CommandResult::OK) {
1244 LOG(ERROR) << "Failed to install application. Cannot update";
1245 return BackendInterface::CommandResult::UNKNOWN;
1247 original_mode = tmp_mode;
1248 return BackendInterface::CommandResult::OK;
1251 BackendInterface::CommandResult BackendInterface::MountInstall(
1252 const bf::path& path) const {
1253 const char* argv[] = {"", "-w", path.c_str(), "-u", uid_str_.c_str()};
1254 return CallBackend(SIZEOFARRAY(argv), argv);
1257 BackendInterface::CommandResult BackendInterface::MountInstallSuccess(
1258 const bf::path& path) const {
1259 RequestResult tmp_mode = mode_;
1260 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1261 original_mode = RequestResult::NORMAL;
1262 if (MountInstall(path) != BackendInterface::CommandResult::OK) {
1263 LOG(ERROR) << "Failed to mount-install application. Cannot mount-update";
1264 return BackendInterface::CommandResult::UNKNOWN;
1266 original_mode = tmp_mode;
1267 return BackendInterface::CommandResult::OK;
1270 static boost::filesystem::path GetTrashPath(
1271 const boost::filesystem::path& path) {
1272 return path.string() + ".trash";
1275 BackendInterface::SubProcessResult BackendInterface::RunSubprocess(
1276 std::vector<std::string> args) const {
1277 args.push_back("-remove_plugin_steps");
1278 ci::Subprocess backend = CreateSubprocess();
1279 backend.RunWithArgs(args);
1280 int status = backend.Wait();
1281 if (WIFEXITED(status)) {
1282 if (WEXITSTATUS(status) == 0)
1283 return BackendInterface::SubProcessResult::SUCCESS;
1285 return BackendInterface::SubProcessResult::FAIL;
1287 return BackendInterface::SubProcessResult::UnKnown;
1290 BackendInterface::SubProcessResult BackendInterface::RunSubprocessAndKill(
1291 std::vector<std::string> args, useconds_t delay) const {
1292 args.push_back("-remove_plugin_steps");
1293 ci::Subprocess backend = CreateSubprocess();
1294 backend.RunWithArgs(args);
1297 int status = backend.Wait();
1298 if (WIFEXITED(status)) {
1299 if (WEXITSTATUS(status) == 0)
1300 return BackendInterface::SubProcessResult::SUCCESS;
1302 return BackendInterface::SubProcessResult::FAIL;
1304 if (WTERMSIG(status) == SIGKILL)
1305 return BackendInterface::SubProcessResult::KILLED;
1307 return BackendInterface::SubProcessResult::UnKnown;
1311 BackendInterface::SubProcessResult BackendInterface::InstallWithSubprocess(
1312 const bf::path& path) const {
1313 std::vector<std::string> args =
1314 { "-i", path.string(), "-u", uid_str_ };
1315 return RunSubprocess(args);
1318 BackendInterface::SubProcessResult BackendInterface::MountInstallWithSubprocess(
1319 const bf::path& path) const {
1320 std::vector<std::string> args =
1321 { "-w", path.string(), "-u", uid_str_ };
1322 return RunSubprocess(args);
1325 BackendInterface::SubProcessResult BackendInterface::RecoverWithSubprocess(
1326 const bf::path& path) const {
1327 std::vector<std::string> args =
1328 { "-b", path.string(), "-u", uid_str_ };
1329 return RunSubprocess(args);
1332 BackendInterface::SubProcessResult BackendInterface::UninstallWithSubprocess(
1333 const std::string& pkgid) const {
1334 std::vector<std::string> args = { "-d", pkgid, "-u", uid_str_ };
1335 return RunSubprocess(args);
1338 BackendInterface::SubProcessResult
1339 BackendInterface::InstallPreloadWithSubprocess(
1340 const boost::filesystem::path& path) const {
1341 std::vector<std::string> args = { "", "-i", path.string(), "--preload" };
1342 return RunSubprocess(args);
1345 BackendInterface::SubProcessResult
1346 BackendInterface::InstallWithSubprocessAndKill(
1347 const bf::path& path, useconds_t delay) const {
1348 std::vector<std::string> args =
1349 { "-i", path.string(), "-u", uid_str_ };
1350 return RunSubprocessAndKill(args, delay);
1353 BackendInterface::SubProcessResult
1354 BackendInterface::MountInstallWithSubprocessAndKill(
1355 const bf::path& path, useconds_t delay) const {
1356 std::vector<std::string> args =
1357 { "-w", path.string(), "-u", uid_str_ };
1358 return RunSubprocessAndKill(args, delay);
1361 BackendInterface::SubProcessResult
1362 BackendInterface::UninstallWithSubprocessAndKill(
1363 const std::string& pkgid, useconds_t delay) const {
1364 std::vector<std::string> args =
1365 { "-d", pkgid, "-u", uid_str_ };
1366 return RunSubprocessAndKill(args, delay);
1369 BackendInterface::SubProcessResult BackendInterface::InstallPkgsWithSubprocess(
1370 const std::vector<bf::path>& paths) const {
1371 std::vector<std::string> args;
1372 args.emplace_back("-i");
1373 for (const bf::path& p : paths)
1374 args.emplace_back(p.string());
1375 args.emplace_back("-u");
1376 args.emplace_back(uid_str_);
1377 return RunSubprocess(args);
1380 BackendInterface::SubProcessResult
1381 BackendInterface::MountInstallPkgsWithSubprocess(
1382 const std::vector<bf::path>& paths) const {
1383 std::vector<std::string> args;
1384 args.emplace_back("-w");
1385 for (const bf::path& p : paths)
1386 args.emplace_back(p.string());
1387 args.emplace_back("-u");
1388 args.emplace_back(uid_str_);
1389 return RunSubprocess(args);
1392 BackendInterface::SubProcessResult BackendInterface::RecoverPkgsWithSubprocess(
1393 const std::vector<bf::path>& paths) const {
1394 std::vector<std::string> args;
1395 args.emplace_back("-b");
1396 for (const bf::path& p : paths)
1397 args.emplace_back(p.string());
1398 args.emplace_back("-u");
1399 args.emplace_back(uid_str_);
1400 return RunSubprocess(args);
1403 BackendInterface::SubProcessResult
1404 BackendInterface::UninstallPkgsWithSubprocess(
1405 const std::vector<std::string>& pkgids) const {
1406 std::vector<std::string> args;
1407 args.emplace_back("-d");
1408 args.insert(args.end(), pkgids.begin(), pkgids.end());
1409 args.emplace_back("-u");
1410 args.emplace_back(uid_str_);
1411 return RunSubprocess(args);
1414 BackendInterface::SubProcessResult
1415 BackendInterface::InstallPkgsWithSubprocessAndKill(
1416 const std::vector<bf::path>& paths, useconds_t delay) const {
1417 std::vector<std::string> args;
1418 args.emplace_back("-i");
1419 for (const bf::path& p : paths)
1420 args.emplace_back(p.string());
1421 args.emplace_back("-u");
1422 args.emplace_back(uid_str_);
1423 return RunSubprocessAndKill(args, delay);
1426 BackendInterface::SubProcessResult
1427 BackendInterface::MountInstallPkgsWithSubprocessAndKill(
1428 const std::vector<bf::path>& paths, useconds_t delay) const {
1429 std::vector<std::string> args;
1430 args.emplace_back("-w");
1431 for (const bf::path& p : paths)
1432 args.emplace_back(p.string());
1433 args.emplace_back("-u");
1434 args.emplace_back(uid_str_);
1435 return RunSubprocessAndKill(args, delay);
1438 bool CopySmackAccess(const boost::filesystem::path& src,
1439 const boost::filesystem::path& dst) {
1440 if (!bf::exists(src) && !bf::is_symlink(src)) {
1441 LOG(ERROR) << "Failed to copy smack access label";
1445 char* access_label = nullptr;
1446 ret = smack_lgetlabel(src.c_str(), &access_label, SMACK_LABEL_ACCESS);
1448 LOG(ERROR) << "get access label from [" << src << "] fail";
1453 ret = smack_lsetlabel(dst.c_str(), access_label, SMACK_LABEL_ACCESS);
1456 LOG(ERROR) << "set access label to [" << dst << "] fail";
1462 bool CopySmackExec(const boost::filesystem::path& src,
1463 const boost::filesystem::path& dst) {
1464 if (!bf::exists(src) && !bf::is_symlink(src)) {
1465 LOG(ERROR) << "Failed to copy smack exec label";
1469 char *exec_label = nullptr;
1470 ret = smack_lgetlabel(src.c_str(), &exec_label, SMACK_LABEL_EXEC);
1472 LOG(ERROR) << "get exec label from [" << src << "] fail";
1477 ret = smack_lsetlabel(dst.c_str(), exec_label, SMACK_LABEL_EXEC);
1480 LOG(ERROR) << "set exec label to [" << dst << "] fail";
1486 bool CopySmackMmap(const boost::filesystem::path& src,
1487 const boost::filesystem::path& dst) {
1488 if (!bf::exists(src) && !bf::is_symlink(src)) {
1489 LOG(ERROR) << "Failed to copy smack mmap label";
1493 char *mmap_label = nullptr;
1494 ret = smack_lgetlabel(src.c_str(), &mmap_label, SMACK_LABEL_MMAP);
1496 LOG(ERROR) << "get mmap label from [" << src << "] fail";
1501 ret = smack_lsetlabel(dst.c_str(), mmap_label, SMACK_LABEL_MMAP);
1504 LOG(ERROR) << "set mmap label to [" << dst << "] fail";
1510 bool CopySmackTransmute(const boost::filesystem::path& src,
1511 const boost::filesystem::path& dst) {
1512 if (!bf::exists(src)) {
1513 LOG(ERROR) << "Failed to copy smack tranmute label";
1517 char *transmute_label = nullptr;
1518 ret = smack_lgetlabel(src.c_str(), &transmute_label, SMACK_LABEL_TRANSMUTE);
1520 LOG(ERROR) << "get access label from [" << src << "] fail";
1523 if (!transmute_label) {
1524 ret = smack_lsetlabel(dst.c_str(), "0", SMACK_LABEL_TRANSMUTE);
1526 if (strcmp(transmute_label, "TRUE") == 0)
1527 ret = smack_lsetlabel(dst.c_str(), "1", SMACK_LABEL_TRANSMUTE);
1529 ret = smack_lsetlabel(dst.c_str(), "0", SMACK_LABEL_TRANSMUTE);
1530 free(transmute_label);
1532 LOG(ERROR) << "set access label to [" << dst << "] fail";
1540 bool CopySmackLabels(const boost::filesystem::path& src,
1541 const boost::filesystem::path& dst) {
1542 if (!CopySmackAccess(src, dst))
1544 if (!CopySmackExec(src, dst))
1546 if (!CopySmackMmap(src, dst))
1548 if (!bf::is_symlink(src) && bf::is_directory(src)) {
1549 if (!CopySmackTransmute(src, dst))
1555 bool CopyAndRemoveWithSmack(const bf::path& src, const bf::path& dst) {
1556 bs::error_code error;
1557 if (bf::exists(dst)) {
1559 bf::remove_all(dst, error);
1561 std::cout << "Exception occurred during remove [" << dst.string()
1562 << "], and skip this file"<< std::endl;
1565 if (!bf::is_directory(dst)) {
1566 LOG(ERROR) << "remove_all fail";
1572 if (bf::is_symlink(src)) {
1573 bf::copy_symlink(src, dst, error);
1575 LOG(ERROR) << "Failed to copy symlink: " << src << ", "
1579 if (!CopySmackLabels(src, dst)) {
1580 LOG(ERROR) << "copy smack label from [" << src.string()
1581 << "] to [" << dst.string() << "] fail";
1584 } else if (bf::is_directory(src)) {
1585 if (!bf::exists(dst)) {
1586 bf::create_directories(dst, error);
1588 LOG(ERROR) << "create directories fail";
1591 ci::CopyOwnershipAndPermissions(src, dst);
1592 if (!CopySmackLabels(src, dst)) {
1593 LOG(ERROR) << "copy smack label from [" << src.string()
1594 << "] to [" << dst.string() << "] fail";
1598 bool success = true;
1599 for (bf::directory_iterator file(src);
1600 file != bf::directory_iterator();
1602 bf::path current(file->path());
1603 bf::path target = dst / current.filename();
1604 success &= CopyAndRemoveWithSmack(current, target);
1606 bf::remove_all(src);
1610 bf::copy_file(src, dst);
1611 ci::CopyOwnershipAndPermissions(src, dst);
1612 if (!CopySmackLabels(src, dst)) {
1613 LOG(ERROR) << "copy smack label from [" << src.string()
1614 << "] to [" << dst.string() << "] fail";
1617 bf::remove_all(src);
1620 std::cout << "Exception occurred during copy [" << src.string()
1621 << "], and skip this file"<< std::endl;
1628 bool BackupPathCopyAndRemove(const bf::path& path) {
1629 if (!bf::exists(path))
1632 bf::path backup_path = path.string() + ".bck";
1633 std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
1634 if (!CopyAndRemoveWithSmack(path, backup_path)) {
1635 LOG(ERROR) << "Failed to setup test environment. Does some previous"
1636 << " test crashed? Path: "
1637 << backup_path << " should not exist.";
1643 bool BackupPath(const bf::path& path) {
1644 bf::path trash_path = GetTrashPath(path);
1645 if (bf::exists(trash_path)) {
1646 LOG(ERROR) << trash_path << " exists. Please remove "
1647 << trash_path << " manually!";
1650 bf::path backup_path = path.string() + ".bck";
1651 std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
1652 bs::error_code error;
1653 bf::remove_all(backup_path, error);
1655 LOG(ERROR) << "Remove failed: " << backup_path
1656 << " (" << error.message() << ")";
1657 if (bf::exists(path)) {
1658 bf::rename(path, backup_path, error);
1660 LOG(ERROR) << "Failed to setup test environment. Does some previous"
1661 << " test crashed? Path: "
1662 << backup_path << " should not exist.";
1666 if (bf::is_directory(backup_path))
1667 bf::create_directory(path);
1672 void CreateDatabase() {
1673 pkgmgr_parser_create_and_initialize_db(kGlobalUserUid);
1674 pkgmgr_parser_create_and_initialize_db(getuid());
1677 bool RestorePathCopyAndRemove(const bf::path& path) {
1678 bf::path backup_path = path.string() + ".bck";
1679 if (!bf::exists(backup_path))
1682 std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
1683 if (!CopyAndRemoveWithSmack(backup_path, path)) {
1684 LOG(ERROR) << "Failed to restore backup path: " << backup_path;
1690 bool RestorePath(const bf::path& path) {
1691 bf::path backup_path = path.string() + ".bck";
1692 std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
1693 bs::error_code error;
1694 bf::remove_all(path, error);
1696 bf::path trash_path = GetTrashPath(path);
1697 LOG(ERROR) << "Remove failed: " << path << " (" << error.message() << ")";
1698 std::cout << "Moving " << path << " to " << trash_path << std::endl;
1699 bf::rename(path, trash_path, error);
1701 LOG(ERROR) << "Failed to move " << path << " to " << trash_path
1702 << " (" << error.message() << ")";
1704 LOG(ERROR) << trash_path << " should be removed manually!";
1706 if (bf::exists(backup_path)) {
1707 bf::rename(backup_path, path, error);
1709 LOG(ERROR) << "Failed to restore backup path: " << backup_path
1710 << " (" << error.message() << ")";
1717 std::vector<bf::path> SetupBackupDirectories(uid_t test_uid) {
1718 std::vector<bf::path> entries;
1719 bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB));
1720 if (test_uid != kGlobalUserUid)
1721 db_dir = db_dir / "user" / std::to_string(test_uid);
1722 for (auto e : kDBEntries) {
1723 bf::path path = db_dir / e;
1724 entries.emplace_back(path);
1727 if (getuid() == 0) {
1728 entries.emplace_back(kPreloadApps);
1729 entries.emplace_back(kPreloadManifestDir);
1730 entries.emplace_back(kPreloadIcons);
1733 if (test_uid == kGlobalUserUid) {
1734 entries.emplace_back(kSkelDir);
1735 entries.emplace_back(kGlobalManifestDir);
1736 ci::UserList list = ci::GetUserList();
1737 for (auto l : list) {
1738 bf::path apps = std::get<2>(l) / "apps_rw";
1739 entries.emplace_back(apps);
1742 tzplatform_set_user(test_uid);
1743 bf::path approot = tzplatform_getenv(TZ_USER_APPROOT);
1744 tzplatform_reset_user();
1745 entries.emplace_back(approot);
1748 bf::path apps_rw = ci::GetRootAppPath(false, test_uid);
1749 entries.emplace_back(apps_rw);
1750 entries.emplace_back(kSdkDirectory);
1755 void UninstallAllAppsInDirectory(bf::path dir, bool is_preload,
1756 BackendInterface* backend) {
1757 if (bf::exists(dir)) {
1758 for (auto& dir_entry : boost::make_iterator_range(
1759 bf::directory_iterator(dir), bf::directory_iterator())) {
1760 if (dir_entry.path().string().find("smoke") != std::string::npos &&
1761 bf::is_directory(dir_entry)) {
1762 std::string package = dir_entry.path().filename().string();
1763 std::regex pkg_regex("smoke[a-zA-Z0-9]{5,}");
1764 if (std::regex_match(package, pkg_regex)) {
1765 BackendInterface::CommandResult result =
1766 BackendInterface::CommandResult::OK;
1768 result = backend->UninstallPreload(
1769 dir_entry.path().filename().string());
1771 result = backend->Uninstall(
1772 dir_entry.path().filename().string());
1773 if (result != BackendInterface::CommandResult::OK) {
1774 LOG(ERROR) << "Cannot uninstall smoke test app: "
1775 << dir_entry.path().filename().string();
1783 void UninstallAllSmokeApps(ci::RequestMode request_mode, uid_t test_uid,
1784 BackendInterface *backend) {
1785 std::cout << "Uninstalling all smoke apps" << std::endl;
1786 bf::path apps_rw = ci::GetRootAppPath(false, test_uid);
1787 UninstallAllAppsInDirectory(apps_rw, false, backend);
1788 if (getuid() == 0 && request_mode == ci::RequestMode::GLOBAL) {
1789 bf::path root_path = kPreloadApps;
1790 UninstallAllAppsInDirectory(root_path, true, backend);
1794 int GetAppInstalledTime(const char* appid, uid_t uid) {
1796 int installed_time = 0;
1797 pkgmgrinfo_appinfo_h handle = NULL;
1798 ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &handle);
1799 if (ret != PMINFO_R_OK)
1801 ret = pkgmgrinfo_appinfo_get_installed_time(handle, &installed_time);
1802 if (ret != PMINFO_R_OK) {
1803 pkgmgrinfo_appinfo_destroy_appinfo(handle);
1806 pkgmgrinfo_appinfo_destroy_appinfo(handle);
1807 return installed_time;
1810 bool CompareFileInfo(const std::string& pkgid, const TestParameters& params,
1811 const bf::path& file) {
1812 FileInfoCollector result(pkgid, params);
1816 bf::path p = "/tmp";
1817 p /= file.filename();
1819 if (!result.FileInfoToFile(p))
1822 FileInfoCollector expected(pkgid, params);
1823 if (!expected.LoadFromFile(file))
1826 return result.IsEqual(expected);
1829 } // namespace smoke_test