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