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