Export Smoke Utils
[platform/core/appfw/wgt-backend.git] / src / unit_tests / smoke_utils.cc
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.
4
5 #include <boost/filesystem/operations.hpp>
6 #include <boost/range/iterator_range.hpp>
7 #include <boost/format.hpp>
8 #include <boost/program_options.hpp>
9 #include <boost/system/error_code.hpp>
10
11 #include <common/step/configuration/step_fail.h>
12 #include <common/utils/user_util.h>
13 #include <common/utils/file_util.h>
14 #include <common/request.h>
15
16 #include <gtest/gtest.h>
17 #include <gtest/gtest-death-test.h>
18
19 #include <pkgmgr-info.h>
20 #include <signal.h>
21 #include <unistd.h>
22 #include <tzplatform_config.h>
23 #include <vconf.h>
24 #include <vconf-internal-keys.h>
25
26 #include <array>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <regex>
30
31 #include "wgt/wgt_installer.h"
32
33 #include "unit_tests/smoke_utils.h"
34
35 namespace bo = boost::program_options;
36
37 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
38 const uid_t kGlobalUserGid = tzplatform_getgid(TZ_SYS_GLOBALAPP_USER);
39 const uid_t kDefaultUserUid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
40 uid_t kTestUserId = kGlobalUserUid;
41 gid_t kTestGroupId = kGlobalUserGid;
42 const char kNormalUserName[] = "smokeuser";
43 const char kSystemShareGroupName[] = "system_share";
44 std::string kTestUserIdStr = std::to_string(kTestUserId);
45 const std::string& kDefaultUserIdStr = std::to_string(kDefaultUserUid);
46 const char kLegacyExtImageDir[] = "legacy_extimage_dir";
47 const char kMigrateTestDBName[] = "app2sd_migrate.db";
48
49 const bf::path kSmokePackagesDirectory =
50     "/usr/share/wgt-backend-ut/test_samples/smoke/";
51
52
53 const char* rwDirectories[] = {
54   "data",
55   "cache",
56   "shared/cache",
57   "shared/data",
58   "shared/trusted",
59 };
60
61 // common entries
62 const std::vector<std::string> kDBEntries = {
63   {".pkgmgr_parser.db"},
64   {".pkgmgr_parser.db-journal"},
65   {".pkgmgr_cert.db"},
66   {".pkgmgr_cert.db-journal"},
67   {".app2sd.db"},
68   {".app2sd.db-journal"},
69 };
70 // globaluser entries
71 const char kGlobalManifestDir[] = "/opt/share/packages";
72 const char kSkelDir[] = "/etc/skel/apps_rw";
73 const char kPreloadApps[] = "/usr/apps";
74 const char kPreloadManifestDir[] = "/usr/share/packages";
75 const char kPreloadIcons[] = "/usr/share/icons";
76
77
78 ci::RequestMode ParseRequestMode(int argc,  char** argv) {
79   bo::options_description desc("Available options");
80   desc.add_options()
81       ("request-mode", bo::value<std::string>(), "set request mode")
82       ("global-request,g", "set request mode to global")
83       ("user-request,u", "set request mode to user");
84
85   bo::variables_map vm;
86   bo::store(bo::parse_command_line(argc, argv, desc), vm);
87   bo::notify(vm);
88
89   if (vm.count("global-request")) {
90     std::cout << "Request mode was set to global." << std::endl;
91     return ci::RequestMode::GLOBAL;
92   }
93   if (vm.count("user-request")) {
94     std::cout << "Request mode was set to user." << std::endl;
95     return ci::RequestMode::USER;
96   }
97   if (vm.count("request-mode")) {
98     if (vm["request-mode"].as<std::string>() == "global") {
99       std::cout << "Request mode was set to global." << std::endl;
100       return ci::RequestMode::GLOBAL;
101     }
102     if (vm["request-mode"].as<std::string>() == "user") {
103       std::cout << "Request mode was set to user." << std::endl;
104       return ci::RequestMode::USER;
105     }
106     std::cout << "Cannot set request mode to "
107               << vm["request-mode"].as<std::string>() << std::endl;
108     std::cout << "Request mode was set to global." << std::endl;
109     return ci::RequestMode::GLOBAL;
110   }
111 }
112
113 bool TouchFile(const bf::path& path) {
114   FILE* f = fopen(path.c_str(), "w+");
115   if (!f)
116     return false;
117   fclose(f);
118   return true;
119 }
120
121 bool AddUser(const char *user_name) {
122   GumUser* user = nullptr;
123   user = gum_user_create_sync(FALSE);
124   if (user == nullptr)
125     LOG(WARNING) << "Failed to create gum user! (user name: "
126                  << user_name << ")";
127   g_object_set(G_OBJECT(user), "username", user_name, "usertype",
128       GUM_USERTYPE_NORMAL, NULL);
129   gboolean rval = FALSE;
130   rval = gum_user_add_sync(user);
131   g_object_unref(user);
132   return rval;
133 }
134
135 bool DeleteUser(const char *user_name, bool rem_home_dir) {
136   bool rval = FALSE;
137   GumUser* guser = gum_user_get_by_name_sync(user_name, FALSE);
138   if (guser)
139     rval = gum_user_delete_sync(guser, rem_home_dir);
140   return rval;
141 }
142
143 bool AddTestUser(const char *user_name) {
144   std::cout << "Adding test user: " << user_name << std::endl;
145   bool ret = AddUser(user_name);
146   if (boost::optional<uid_t> uid = ci::GetUidByUserName(user_name)) {
147     kTestUserId = *uid;
148     kTestUserIdStr = std::to_string(kTestUserId);
149     std::cout << "User created properly: uid=" << *uid;
150     if (boost::optional<gid_t> gid = ci::GetGidByUid(*uid)) {
151       kTestGroupId = *gid;
152       std::cout << " gid=" << *gid;
153     }
154     std::cout << std::endl;
155     return true;
156   }
157   LOG(ERROR) << "Adding test user failed";
158   return false;
159 }
160
161 bool DeleteTestUser(const char *user_name) {
162   std::cout << "Deleting test user: " << user_name << std::endl;
163   uid_t test_uid;
164   if (boost::optional<uid_t> uid = ci::GetUidByUserName(user_name))
165     test_uid = *uid;
166   bool ret = DeleteUser(user_name, true);
167   if (!ci::GetUidByUserName(user_name)) {
168     std::cout << "User deleted properly: user_name=" << user_name
169               << " uid=" << test_uid << std::endl;
170     return true;
171   }
172   LOG(ERROR) << "Deleting test user failed";
173   return false;
174 }
175
176 void RemoveAllRecoveryFiles() {
177   bf::path root_path = ci::GetRootAppPath(false,
178       kTestUserId);
179   if (!bf::exists(root_path))
180     return;
181   for (auto& dir_entry : boost::make_iterator_range(
182          bf::directory_iterator(root_path), bf::directory_iterator())) {
183     if (bf::is_regular_file(dir_entry)) {
184       if (dir_entry.path().string().find("/wgt-recovery")
185           != std::string::npos) {
186         bs::error_code error;
187         bf::remove(dir_entry.path(), error);
188       }
189     }
190   }
191 }
192
193 bf::path FindRecoveryFile() {
194   bf::path root_path = ci::GetRootAppPath(false,
195       kTestUserId);
196   for (auto& dir_entry : boost::make_iterator_range(
197          bf::directory_iterator(root_path), bf::directory_iterator())) {
198     if (bf::is_regular_file(dir_entry)) {
199       if (dir_entry.path().string().find("/wgt-recovery")
200           != std::string::npos) {
201         return dir_entry.path();
202       }
203     }
204   }
205   return {};
206 }
207
208 bf::path GetPackageRoot(const std::string& pkgid, uid_t uid) {
209   bf::path root_path = ci::GetRootAppPath(false, uid);
210   return root_path / pkgid;
211 }
212
213 bool ValidateFileContentInPackage(const std::string& pkgid,
214                                   const std::string& relative,
215                                   const std::string& expected,
216                                   bool is_readonly) {
217   bf::path file_path = ci::GetRootAppPath(is_readonly, kTestUserId);
218   file_path = file_path / pkgid / relative;
219   if (!bf::exists(file_path)) {
220     LOG(ERROR) << file_path << " doesn't exist";
221     return false;
222   }
223   FILE* handle = fopen(file_path.c_str(), "r");
224   if (!handle) {
225     LOG(ERROR) << file_path << " cannot  be open";
226     return false;
227   }
228   std::string content;
229   std::array<char, 200> buffer;
230   while (fgets(buffer.data(), buffer.size(), handle)) {
231     content += buffer.data();
232   }
233   fclose(handle);
234   return content == expected;
235 }
236
237 void AddDataFiles(const std::string& pkgid, uid_t uid) {
238   if (uid == kGlobalUserUid) {
239     ci::UserList list = ci::GetUserList();
240     for (auto l : list) {
241       auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
242       ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt"));
243       ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt"));
244     }
245   } else {
246     auto pkg_path = GetPackageRoot(pkgid, uid);
247     ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt"));
248     ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt"));
249   }
250 }
251
252 void ValidateDataFiles(const std::string& pkgid, uid_t uid) {
253   if (uid == kGlobalUserUid) {
254     ci::UserList list = ci::GetUserList();
255     for (auto l : list) {
256       auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
257       ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
258       ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
259     }
260   } else {
261     auto pkg_path = GetPackageRoot(pkgid, uid);
262     ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
263     ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
264   }
265 }
266
267 void ValidatePackageRWFS(const std::string& pkgid, uid_t uid) {
268   bf::path root_path = ci::GetRootAppPath(false, uid);
269   bf::path package_path = root_path / pkgid;
270   bf::path data_path = package_path / rwDirectories[DATA];
271   bf::path cache_path = package_path / rwDirectories[CACHE];
272   bf::path shared_data_path = package_path / rwDirectories[SHARED_DATA];
273
274   ASSERT_TRUE(bf::exists(data_path));
275   ASSERT_TRUE(bf::exists(cache_path));
276
277   struct stat stats;
278   stat(data_path.c_str(), &stats);
279   // gid of RW dirs should be system_share
280   boost::optional<gid_t> system_share =
281     ci::GetGidByGroupName(kSystemShareGroupName);
282   ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << data_path;
283   ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " << data_path;
284   if (bf::exists(shared_data_path)) {
285     stat(shared_data_path.c_str(), &stats);
286     ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << shared_data_path;
287     ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: "
288       << shared_data_path;
289   }
290
291   stat(cache_path.c_str(), &stats);
292   ASSERT_EQ(uid, stats.st_uid) << "Invalid gid: " << cache_path;
293   ASSERT_EQ(*system_share, stats.st_gid) << "Invalid gid: " << cache_path;
294 }
295
296 void ValidatePackageFS(const std::string& pkgid,
297                        const std::vector<std::string>& appids,
298                        uid_t uid, gid_t gid, bool is_readonly) {
299   bf::path root_path = ci::GetRootAppPath(is_readonly, uid);
300   bf::path package_path = root_path / pkgid;
301   bf::path shared_path = package_path / "shared";
302   ASSERT_TRUE(bf::exists(root_path));
303   ASSERT_TRUE(bf::exists(package_path));
304   ASSERT_TRUE(bf::exists(shared_path));
305
306   bf::path manifest_path =
307       bf::path(getUserManifestPath(uid, is_readonly)) / (pkgid + ".xml");
308   ASSERT_TRUE(bf::exists(manifest_path));
309
310   for (auto& appid : appids) {
311     bf::path binary_path = package_path / "bin" / appid;
312     ASSERT_TRUE(bf::exists(binary_path));
313   }
314
315   bf::path widget_root_path = package_path / "res" / "wgt";
316   bf::path config_path = widget_root_path / "config.xml";
317   ASSERT_TRUE(bf::exists(widget_root_path));
318   ASSERT_TRUE(bf::exists(config_path));
319
320   bf::path private_tmp_path = package_path / "tmp";
321   ASSERT_TRUE(bf::exists(private_tmp_path));
322
323   // backups should not exist
324   bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
325   bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
326   ASSERT_FALSE(bf::exists(package_backup));
327   ASSERT_FALSE(bf::exists(manifest_backup));
328
329   for (bf::recursive_directory_iterator iter(package_path);
330       iter != bf::recursive_directory_iterator(); ++iter) {
331     if (bf::is_symlink(symlink_status(iter->path())))
332       continue;
333     bool is_rw_dir = false;
334     for (const auto rw_dir : rwDirectories) {
335       bf::path rw_dir_path = rw_dir;
336       is_rw_dir |= ci::MakeRelativePath(iter->path(), package_path)
337           == rw_dir_path;
338     }
339     if (is_rw_dir || iter->path().filename() == ".mmc") {
340       iter.no_push();
341       continue;
342     }
343     struct stat stats;
344     stat(iter->path().c_str(), &stats);
345     ASSERT_EQ(uid, stats.st_uid) << "Invalid uid: " << iter->path();
346     ASSERT_EQ(gid, stats.st_gid) << "Invalid gid: " << iter->path();
347   }
348 }
349
350 void PackageCheckCleanup(const std::string& pkgid,
351     const std::vector<std::string>&, bool is_readonly) {
352   bf::path root_path = ci::GetRootAppPath(is_readonly, kTestUserId);
353   bf::path package_path = root_path / pkgid;
354   ASSERT_FALSE(bf::exists(package_path));
355
356   bf::path manifest_path = bf::path(getUserManifestPath(kTestUserId,
357       is_readonly)) / (pkgid + ".xml");
358   ASSERT_FALSE(bf::exists(manifest_path));
359
360   // backups should not exist
361   bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
362   bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
363   ASSERT_FALSE(bf::exists(package_backup));
364   ASSERT_FALSE(bf::exists(manifest_backup));
365 }
366
367 void ValidatePackage(const std::string& pkgid,
368     const std::vector<std::string>& appids, bool is_readonly) {
369   ASSERT_TRUE(ci::QueryIsPackageInstalled(
370       pkgid, ci::GetRequestMode(kTestUserId), kTestUserId));
371   ValidatePackageFS(pkgid, appids, kTestUserId, kTestGroupId, is_readonly);
372   if (kTestUserId == kGlobalUserUid) {
373     ci::UserList list = ci::GetUserList();
374     for (auto& l : list)
375       ValidatePackageRWFS(pkgid, std::get<0>(l));
376   } else {
377     ValidatePackageRWFS(pkgid, kTestUserId);
378   }
379 }
380
381 void ValidateExternalPackageFS(const std::string& pkgid,
382                                const std::vector<std::string>& appids,
383                                uid_t uid, gid_t gid) {
384   ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(), uid), 0);
385   bf::path root_path = ci::GetRootAppPath(false, uid);
386   ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "res"));
387   ValidatePackageFS(pkgid, appids, uid, gid, false);
388   ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(), uid), 0);
389 }
390
391 void ValidateExternalPackage(const std::string& pkgid,
392                              const std::vector<std::string>& appids) {
393   ASSERT_TRUE(ci::QueryIsPackageInstalled(
394       pkgid, ci::GetRequestMode(kTestUserId),
395       kTestUserId));
396   std::string storage = ci::QueryStorageForPkgId(pkgid, kTestUserId);
397   bf::path ext_mount_path = ci::GetExternalCardPath();
398   if (bf::is_empty(ext_mount_path)) {
399     LOG(INFO) << "Sdcard not exists!";
400     ASSERT_EQ(storage, "installed_internal");
401   } else {
402     ASSERT_EQ(storage, "installed_external");
403   }
404   ValidateExternalPackageFS(pkgid, appids, kTestUserId, kTestGroupId);
405   if (kTestUserId == kGlobalUserUid) {
406     ci::UserList list = ci::GetUserList();
407     for (auto& l : list)
408       ValidatePackageRWFS(pkgid, std::get<0>(l));
409   } else {
410     ValidatePackageRWFS(pkgid, kTestUserId);
411   }
412 }
413
414 void CheckPackageNonExistance(const std::string& pkgid,
415                               const std::vector<std::string>& appids) {
416   ASSERT_FALSE(ci::QueryIsPackageInstalled(
417       pkgid, ci::GetRequestMode(kTestUserId),
418       kTestUserId));
419   PackageCheckCleanup(pkgid, appids);
420   if (kTestUserId == kGlobalUserUid) {
421       ci::UserList list = ci::GetUserList();
422       bf::path skel_path(kSkelDir);
423       ASSERT_FALSE(bf::exists(skel_path / pkgid));
424       for (auto& l : list) {
425         bf::path root_path = ci::GetRootAppPath(false, std::get<0>(l));
426         bf::path package_path = root_path / pkgid;
427         ASSERT_FALSE(bf::exists(package_path));
428       }
429   }
430 }
431
432 void CheckPackageReadonlyNonExistance(const std::string& pkgid,
433                                       const std::vector<std::string>& appids) {
434   ASSERT_FALSE(ci::QueryIsPackageInstalled(
435       pkgid, ci::GetRequestMode(kTestUserId), kTestUserId));
436   PackageCheckCleanup(pkgid, appids, true);
437 }
438
439 std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
440   std::unique_ptr<ci::AppQueryInterface> query_interface(
441       new wgt::WgtAppQueryInterface());
442   return query_interface;
443 }
444
445 std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr,
446                                                   PackageType type) {
447   switch (type) {
448     case PackageType::WGT:
449       return std::unique_ptr<ci::AppInstaller>(new wgt::WgtInstaller(pkgmgr));
450     case PackageType::HYBRID:
451       return std::unique_ptr<ci::AppInstaller>(
452           new hybrid::HybridInstaller(pkgmgr));
453     default:
454       LOG(ERROR) << "Unknown installer type";
455       return nullptr;
456   }
457 }
458
459 ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
460                                                  PackageType type,
461                                                  RequestResult mode) {
462   std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr, type);
463   switch (mode) {
464   case RequestResult::FAIL:
465     installer->AddStep<ci::configuration::StepFail>();
466     break;
467   default:
468     break;
469   }
470   return installer->Run();
471 }
472 ci::AppInstaller::Result CallBackend(int argc,
473                                      const char* argv[],
474                                      PackageType type,
475                                      RequestResult mode) {
476   TestPkgmgrInstaller pkgmgr_installer;
477   std::unique_ptr<ci::AppQueryInterface> query_interface =
478       CreateQueryInterface();
479   auto pkgmgr =
480       ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
481                                   &pkgmgr_installer, query_interface.get());
482   if (!pkgmgr) {
483     LOG(ERROR) << "Failed to initialize pkgmgr interface";
484     return ci::AppInstaller::Result::UNKNOWN;
485   }
486   return RunInstallerWithPkgrmgr(pkgmgr, type, mode);
487 }
488
489 ci::AppInstaller::Result Install(const bf::path& path,
490                                  PackageType type,
491                                  RequestResult mode) {
492   const char* argv[] = {"", "-i", path.c_str(), "-u", kTestUserIdStr.c_str()};
493   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
494 }
495
496 ci::AppInstaller::Result InstallPreload(const bf::path& path, PackageType type,
497     RequestResult mode) {
498   const char* argv[] = {"", "-i", path.c_str(), "--preload"};
499   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
500 }
501
502 bool CheckAvailableExternalPath() {
503   bf::path ext_mount_path = ci::GetExternalCardPath();
504   LOG(DEBUG) << "ext_mount_path :" << ext_mount_path;
505   if (ext_mount_path.empty()) {
506     LOG(ERROR) << "Sdcard not exists!";
507     return false;
508   }
509   return true;
510 }
511
512 ci::AppInstaller::Result InstallExternal(const bf::path& path,
513                                  PackageType type,
514                                  RequestResult mode) {
515   int default_storage = 0;
516   vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
517                 &default_storage);
518   vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, 1);
519
520   const char* argv[] = {"", "-i", path.c_str(), "-u", kTestUserIdStr.c_str()};
521   ci::AppInstaller::Result result =
522                           CallBackend(SIZEOFARRAY(argv), argv, type, mode);
523
524   vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
525                 default_storage);
526   return result;
527 }
528
529 ci::AppInstaller::Result MigrateLegacyExternalImage(const std::string& pkgid,
530                                  const bf::path& path,
531                                  const bf::path& legacy_path,
532                                  PackageType type,
533                                  RequestResult mode) {
534   if (InstallExternal(path, type) != ci::AppInstaller::Result::OK) {
535     LOG(ERROR) << "Failed to install application. Cannot perform Migrate";
536     return ci::AppInstaller::Result::ERROR;
537   }
538
539   bf::path ext_mount_path = ci::GetExternalCardPath();
540   if (bf::is_empty(ext_mount_path)) {
541     LOG(ERROR) << "Sdcard not exists!";
542     return ci::AppInstaller::Result::ERROR;
543   }
544   bf::path app2sd_path = ext_mount_path / "app2sd";
545
546   char* image_name = app2ext_usr_getname_image(pkgid.c_str(),
547                      kGlobalUserUid);
548   if (!image_name) {
549     LOG(ERROR) << "Failed to get external image name";
550     return ci::AppInstaller::Result::ERROR;
551   }
552   bf::path org_image = app2sd_path / image_name;
553   free(image_name);
554
555   bs::error_code error;
556   bf::remove(org_image, error);
557   if (error) {
558     LOG(ERROR) << "Failed to remove org image";
559     return ci::AppInstaller::Result::ERROR;
560   }
561
562   bf::path db_path = tzplatform_getenv(TZ_SYS_DB);
563   bf::path app2sd_db = db_path / ".app2sd.db";
564   bf::path app2sd_db_journal = db_path / ".app2sd.db-journal";
565   bf::remove(app2sd_db, error);
566   if (error) {
567     LOG(ERROR) << "Failed to remove app2sd db";
568     return ci::AppInstaller::Result::ERROR;
569   }
570   bf::remove(app2sd_db_journal, error);
571   if (error) {
572     LOG(ERROR) << "Failed to remove app2sd journal db";
573     return ci::AppInstaller::Result::ERROR;
574   }
575
576   bf::path app2sd_migrate_db = legacy_path / kMigrateTestDBName;
577   if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) {
578     LOG(ERROR) << "Failed to copy test db";
579     return ci::AppInstaller::Result::ERROR;
580   }
581
582   bf::path legacy_src = legacy_path / pkgid;
583   bf::path legacy_dst = app2sd_path / pkgid;
584   if (!ci::CopyFile(legacy_src, legacy_dst)) {
585     LOG(ERROR) << "Failed to copy test image";
586     return ci::AppInstaller::Result::ERROR;
587   }
588   const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(),
589                        "-u", kDefaultUserIdStr.c_str()};
590   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
591 }
592
593 ci::AppInstaller::Result MountInstall(const bf::path& path,
594     PackageType type, RequestResult mode) {
595   const char* argv[] = {"", "-w", path.c_str(), "-u", kTestUserIdStr.c_str()};
596   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
597 }
598
599 ci::AppInstaller::Result Uninstall(const std::string& pkgid,
600                                    PackageType type,
601                                    bool is_preload,
602                                    RequestResult mode) {
603   if (is_preload) {
604     const char* argv[] = {"", "-d", pkgid.c_str(), "--preload",
605         "--force-remove"};
606     return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
607   } else {
608     const char* argv[] = {"", "-d", pkgid.c_str(), "-u",
609         kTestUserIdStr.c_str()};
610     return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
611   }
612 }
613
614 ci::AppInstaller::Result RDSUpdate(const bf::path& path,
615                                    const std::string& pkgid,
616                                    PackageType type,
617                                    RequestResult mode) {
618   if (Install(path, type) != ci::AppInstaller::Result::OK) {
619     LOG(ERROR) << "Failed to install application. Cannot perform RDS";
620     return ci::AppInstaller::Result::UNKNOWN;
621   }
622   const char* argv[] = {"", "-r", pkgid.c_str(), "-u",
623                         kTestUserIdStr.c_str()};
624   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
625 }
626
627 ci::AppInstaller::Result DeltaInstall(const bf::path& path,
628     const bf::path& delta_package, PackageType type) {
629   if (Install(path, type) != ci::AppInstaller::Result::OK) {
630     LOG(ERROR) << "Failed to install application. Cannot perform delta update";
631     return ci::AppInstaller::Result::UNKNOWN;
632   }
633   return Install(delta_package, type);
634 }
635
636 ci::AppInstaller::Result EnablePackage(const std::string& pkgid,
637                                   PackageType type,
638                                   RequestResult mode) {
639   const char* argv[] = {"", "-A", pkgid.c_str(), "-u", kTestUserIdStr.c_str()};
640   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
641 }
642
643 ci::AppInstaller::Result DisablePackage(const std::string& pkgid,
644                                   PackageType type,
645                                   RequestResult mode) {
646   const char* argv[] = {"", "-D", pkgid.c_str(), "-u", kTestUserIdStr.c_str()};
647   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
648 }
649
650 ci::AppInstaller::Result Recover(const bf::path& recovery_file,
651                                  PackageType type,
652                                  RequestResult mode) {
653   const char* argv[] = {"", "-b", recovery_file.c_str(), "-u",
654                         kTestUserIdStr.c_str()};
655   return CallBackend(SIZEOFARRAY(argv), argv, type, mode);
656 }
657
658 void BackupPath(const bf::path& path) {
659   bf::path backup_path = path.string() + ".bck";
660   std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
661   bs::error_code error;
662   bf::remove_all(backup_path, error);
663   if (error)
664     LOG(ERROR) << "Remove failed: " << backup_path
665                << " (" << error.message() << ")";
666   if (bf::exists(path)) {
667     bf::rename(path, backup_path, error);
668     if (error)
669       LOG(ERROR) << "Failed to setup test environment. Does some previous"
670                  << " test crashed? Path: "
671                  << backup_path << " should not exist.";
672     assert(!error);
673   }
674 }
675
676 void RestorePath(const bf::path& path) {
677   bf::path backup_path = path.string() + ".bck";
678   std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
679   bs::error_code error;
680   bf::remove_all(path, error);
681   if (error)
682     LOG(ERROR) << "Remove failed: " << path
683                << " (" << error.message() << ")";
684   if (bf::exists(backup_path)) {
685     bf::rename(backup_path, path, error);
686     if (error)
687       LOG(ERROR) << "Failed to restore backup path: " << backup_path
688                  << " (" << error.message() << ")";
689   }
690 }
691
692 std::vector<bf::path> SetupBackupDirectories() {
693   std::vector<bf::path> entries;
694   bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB));
695   if (kTestUserId != kGlobalUserUid)
696     db_dir = db_dir / "user" / std::to_string(kTestUserId);
697   for (auto e : kDBEntries) {
698     bf::path path = db_dir / e;
699     entries.emplace_back(path);
700   }
701
702   if (getuid() == 0) {
703     entries.emplace_back(kPreloadApps);
704     entries.emplace_back(kPreloadManifestDir);
705     entries.emplace_back(kPreloadIcons);
706   }
707
708   if (kTestUserId == kGlobalUserUid) {
709     entries.emplace_back(kSkelDir);
710     entries.emplace_back(kGlobalManifestDir);
711     ci::UserList list = ci::GetUserList();
712     for (auto l : list) {
713       bf::path apps = std::get<2>(l) / "apps_rw";
714       entries.emplace_back(apps);
715     }
716   } else {
717     tzplatform_set_user(kTestUserId);
718     bf::path approot = tzplatform_getenv(TZ_USER_APPROOT);
719     tzplatform_reset_user();
720     entries.emplace_back(approot);
721   }
722
723   bf::path apps_rw = ci::GetRootAppPath(false, kTestUserId);
724   entries.emplace_back(apps_rw);
725
726   return entries;
727 }
728
729 void UninstallAllAppsInDirectory(bf::path dir, bool is_preload) {
730   if (bf::exists(dir)) {
731     for (auto& dir_entry : boost::make_iterator_range(
732         bf::directory_iterator(dir), bf::directory_iterator())) {
733       if (dir_entry.path().string().find("smoke") != std::string::npos &&
734           bf::is_directory(dir_entry)) {
735         std::string package = dir_entry.path().filename().string();
736         std::regex pkg_regex("smoke[a-zA-Z]{3,}[1-9]{2,}");
737         if (std::regex_match(package, pkg_regex)) {
738           if (Uninstall(dir_entry.path().filename().string(), PackageType::WGT,
739               is_preload, RequestResult::NORMAL) !=
740               ci::AppInstaller::Result::OK) {
741             LOG(ERROR) << "Cannot uninstall smoke test app: "
742                 << dir_entry.path().filename().string();
743           }
744         }
745       }
746     }
747   }
748 }
749
750 void UninstallAllSmokeApps(ci::RequestMode request_mode) {
751   if (getuid() == 0 && request_mode == ci::RequestMode::GLOBAL) {
752     bf::path root_path = kPreloadApps;
753     UninstallAllAppsInDirectory(root_path, true);
754   }
755   bf::path apps_rw = ci::GetRootAppPath(false, kTestUserId);
756   UninstallAllAppsInDirectory(apps_rw, false);
757 }