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