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