76588e5e775d8b03803d14131a19847f2a6e4f04
[platform/core/appfw/app-installers.git] / src / unit_tests / common / 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 "unit_tests/common/smoke_utils.h"
6
7 #include <gum/gum-user.h>
8 #include <gum/gum-user-service.h>
9 #include <gum/common/gum-user-types.h>
10 #include <manifest_parser/utils/version_number.h>
11 #include <sys/smack.h>
12 #include <vconf.h>
13 #include <vconf-internal-keys.h>
14
15 #include <boost/filesystem/path.hpp>
16 #include <gtest/gtest.h>
17
18 #include <common/installer/app_installer.h>
19 #include <common/utils/paths.h>
20 #include <common/pkgmgr_interface.h>
21 #include <common/utils/pkgmgr_query.h>
22 #include <common/tzip_interface.h>
23
24 #include <list>
25 #include <memory>
26 #include <string>
27 #include <vector>
28
29 namespace bf = boost::filesystem;
30 namespace bs = boost::system;
31 namespace ci = common_installer;
32 namespace bo = boost::program_options;
33
34 namespace {
35
36 const uid_t kDefaultUserUid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
37 const gid_t kDefaultUserGid = tzplatform_getgid(TZ_SYS_DEFAULT_USER);
38 const char kNormalUserName[] = "smokeuser";
39 const char kSystemShareGroupName[] = "system_share";
40 const char kMigrateTestDBName[] = "app2sd_migrate.db";
41 // common entries
42 const std::vector<std::string> kDBEntries = {
43   {".pkgmgr_parser.db"},
44   {".pkgmgr_parser.db-journal"},
45   {".pkgmgr_cert.db"},
46   {".pkgmgr_cert.db-journal"},
47   {".app2sd.db"},
48   {".app2sd.db-journal"},
49 };
50 // globaluser entries
51 const char kGlobalManifestDir[] = "/opt/share/packages";
52 const char kSkelDir[] = "/etc/skel/apps_rw";
53 const char kPreloadApps[] = "/usr/apps";
54 const char kPreloadManifestDir[] = "/usr/share/packages";
55 const char kPreloadIcons[] = "/usr/share/icons";
56 const char kData[] = "data";
57 const char kShared[] = ".shared";
58 const char kSharedTmp[] = ".shared_tmp";
59
60 enum RWDirectory {
61   DATA,
62   CACHE,
63   SHARED_CACHE,
64   SHARED_DATA,
65   SHARED_TRUSTED
66 };
67
68 const char* rwDirectories[] = {
69   "data",
70   "cache",
71   "shared/cache",
72   "shared/data",
73   "shared/trusted",
74 };
75
76 }  // namespace
77
78 namespace smoke_test {
79
80 const char kLegacyExtImageDir[] = "legacy_extimage_dir";
81 const std::string& kDefaultUserIdStr = std::to_string(kDefaultUserUid);
82 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
83 const uid_t kGlobalUserGid = tzplatform_getgid(TZ_SYS_GLOBALAPP_USER);
84 extern const bf::path kSdkDirectory = "/home/owner/share/tmp/sdk_tools";
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 static bool AddUser(const char* user_name) {
123   GumUser* user = nullptr;
124   user = gum_user_create_sync(FALSE);
125   if (user == nullptr)
126     LOG(WARNING) << "Failed to create gum user! (user name: "
127                  << user_name << ")";
128   g_object_set(G_OBJECT(user), "username", user_name, "usertype",
129       GUM_USERTYPE_NORMAL, NULL);
130   gboolean rval = FALSE;
131   rval = gum_user_add_sync(user);
132   g_object_unref(user);
133   return rval;
134 }
135
136 static bool DeleteUser(const char* user_name, bool rem_home_dir) {
137   bool rval = FALSE;
138   GumUser* guser = gum_user_get_by_name_sync(user_name, FALSE);
139   if (guser)
140     rval = gum_user_delete_sync(guser, rem_home_dir);
141   return rval;
142 }
143
144 bool AddTestUser(User* test_user) {
145   std::cout << "Adding test user: " << kNormalUserName << std::endl;
146   AddUser(kNormalUserName);
147   if (boost::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName)) {
148     test_user->uid = *uid;
149     std::cout << "User created properly: uid=" << *uid;
150     if (boost::optional<gid_t> gid = ci::GetGidByUid(*uid)) {
151       test_user->gid = *gid;
152       std::cout << " gid=" << *gid;
153     }
154     std::cout << std::endl;
155     return true;
156   }
157   LOG(ERROR) << "Adding test user failed";
158   return false;
159 }
160
161 bool DeleteTestUser() {
162   std::cout << "Deleting test user: " << kNormalUserName << std::endl;
163   uid_t test_uid;
164   if (boost::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName))
165     test_uid = *uid;
166   else
167     return false;
168   DeleteUser(kNormalUserName, true);
169   if (!ci::GetUidByUserName(kNormalUserName)) {
170     std::cout << "User deleted properly: user_name=" << kNormalUserName
171               << " uid=" << test_uid << std::endl;
172     return true;
173   }
174   LOG(ERROR) << "Deleting test user failed";
175   return false;
176 }
177
178 bool TouchFile(const bf::path& path) {
179   FILE* f = fopen(path.c_str(), "w+");
180   if (!f)
181     return false;
182   fclose(f);
183   return true;
184 }
185
186 void AddDataFiles(const std::string& pkgid, uid_t uid) {
187   if (uid == kGlobalUserUid) {
188     ci::UserList list = ci::GetUserList();
189     for (auto l : list) {
190       auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
191       ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt"));
192       ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt"));
193     }
194   } else {
195     auto pkg_path = GetPackageRoot(pkgid, uid);
196     ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt"));
197     ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt"));
198   }
199 }
200
201 void RemoveAllRecoveryFiles(const std::string& prefix, uid_t uid) {
202   bf::path root_path = ci::GetRootAppPath(false, uid);
203   if (!bf::exists(root_path))
204     return;
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(prefix) != std::string::npos) {
209         bs::error_code error;
210         bf::remove(dir_entry.path(), error);
211         if (error)
212           LOG(ERROR) << "Failed to remove " << dir_entry.path()
213                      << ": " << error.message();
214       }
215     }
216   }
217 }
218
219 bf::path FindRecoveryFile(const std::string& prefix, uid_t uid) {
220   bf::path root_path = ci::GetRootAppPath(false, uid);
221   if (!bf::exists(root_path))
222     return {};
223
224   for (auto& dir_entry : boost::make_iterator_range(
225       bf::directory_iterator(root_path), bf::directory_iterator())) {
226     if (bf::is_regular_file(dir_entry)) {
227       if (dir_entry.path().string().find(prefix) != std::string::npos) {
228         return dir_entry.path();
229       }
230     }
231   }
232   return {};
233 }
234
235 std::unique_ptr<ci::recovery::RecoveryFile> GetRecoverFileInfo(
236     const bf::path& recovery_file_path) {
237   return ci::recovery::RecoveryFile::OpenRecoveryFile(recovery_file_path);
238 }
239
240 bf::path GetPackageRoot(const std::string& pkgid, uid_t uid) {
241   bf::path root_path = ci::GetRootAppPath(false, uid);
242   return root_path / pkgid;
243 }
244
245 bool ValidateFileContentInPackage(const std::string& pkgid,
246                                   const std::string& relative,
247                                   const std::string& expected,
248                                   const TestParameters& params) {
249   bf::path file_path = ci::GetRootAppPath(params.is_readonly,
250                                           params.test_user.uid);
251   file_path = file_path / pkgid / relative;
252   if (!bf::exists(file_path)) {
253     LOG(ERROR) << file_path << " doesn't exist";
254     return false;
255   }
256   FILE* handle = fopen(file_path.c_str(), "r");
257   if (!handle) {
258     LOG(ERROR) << file_path << " cannot be open";
259     return false;
260   }
261   std::string content;
262   std::array<char, 200> buffer;
263   while (fgets(buffer.data(), buffer.size(), handle)) {
264     content += buffer.data();
265   }
266   fclose(handle);
267   return content == expected;
268 }
269
270 static 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 static bool ValidatePackageFS(const std::string& pkgid, const Apps& apps,
300     const TestParameters& params) {
301   bf::path root_path = ci::GetRootAppPath(params.is_readonly,
302                                           params.test_user.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(params.test_user.uid,
311           params.is_readonly)) / (pkgid + ".xml");
312   EXTENDED_ASSERT_TRUE(bf::exists(manifest_path));
313
314   for (auto& app : apps) {
315     const std::string &exec = app.second;
316     bf::path binary_path = package_path / "bin" / exec;
317     EXTENDED_ASSERT_TRUE(bf::exists(binary_path));
318   }
319
320   if (params.pkg_type == PackageType::WGT ||
321       params.pkg_type == PackageType::HYBRID) {
322     bf::path widget_root_path = package_path / "res" / "wgt";
323     bf::path config_path = widget_root_path / "config.xml";
324     EXTENDED_ASSERT_TRUE(bf::exists(widget_root_path));
325     EXTENDED_ASSERT_TRUE(bf::exists(config_path));
326
327     bf::path private_tmp_path = package_path / "tmp";
328     EXTENDED_ASSERT_TRUE(bf::exists(private_tmp_path));
329   }
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(params.test_user.uid, stats.st_uid);
354     EXTENDED_ASSERT_EQ(params.test_user.gid, stats.st_gid);
355   }
356   return true;
357 }
358
359 bool ValidatePackage(const std::string& pkgid, const Apps& apps,
360     const TestParameters& params) {
361   ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
362   EXTENDED_ASSERT_TRUE(pkg_query.IsPackageInstalled(
363       ci::GetRequestMode(params.test_user.uid)));
364   EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, apps, params));
365   if (params.test_user.uid == kGlobalUserUid) {
366     ci::UserList list = ci::GetUserList();
367     for (auto& l : list)
368       EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, std::get<0>(l)));
369   } else {
370     EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, params.test_user.uid));
371   }
372   return true;
373 }
374
375 bool ValidateDataFiles(const std::string& pkgid, uid_t uid) {
376   if (uid == kGlobalUserUid) {
377     ci::UserList list = ci::GetUserList();
378     for (auto l : list) {
379       auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
380       EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
381       EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
382     }
383   } else {
384     auto pkg_path = GetPackageRoot(pkgid, uid);
385     EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
386     EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
387   }
388   return true;
389 }
390
391 static bool ValidateExternalPackageFS(const std::string& pkgid,
392     const Apps& apps, const TestParameters& params) {
393   EXTENDED_ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(),
394       params.test_user.uid), 0);
395   bf::path root_path = ci::GetRootAppPath(false, params.test_user.uid);
396   if (params.pkg_type == PackageType::TPK) {
397     EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "bin"));
398     EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "lib"));
399   }
400   EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "res"));
401   EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, apps, params));
402   EXTENDED_ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(),
403       params.test_user.uid), 0);
404   return true;
405 }
406
407 bool ValidateExternalPackage(const std::string& pkgid, const Apps& apps,
408     const TestParameters& params) {
409   ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
410   std::string storage = pkg_query.StorageForPkgId();
411   bf::path ext_mount_path = ci::GetExternalCardPath();
412   if (bf::is_empty(ext_mount_path)) {
413     LOG(INFO) << "Sdcard not exists!";
414     EXTENDED_ASSERT_EQ(storage, "installed_internal");
415   } else {
416     EXTENDED_ASSERT_EQ(storage, "installed_external");
417   }
418   EXTENDED_ASSERT_TRUE(ValidateExternalPackageFS(pkgid, apps, params));
419   return true;
420 }
421
422 bool ValidateExtendedPackage(const std::string& pkgid, const Apps& apps,
423     const TestParameters& params) {
424   ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
425   std::string storage = pkg_query.StorageForPkgId();
426   bf::path extended_path =
427       bf::path(ci::GetExtendedRootAppPath(params.test_user.uid)) / pkgid;
428   if (!bf::exists(extended_path)) {
429     LOG(INFO) << "Extended storage not exists!";
430     EXTENDED_ASSERT_EQ(storage, "installed_internal");
431   } else {
432     EXTENDED_ASSERT_EQ(storage, "installed_extended");
433   }
434   EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, apps, params));
435   return true;
436 }
437
438 static bool PackageCheckCleanup(const std::string& pkgid,
439     const TestParameters& params) {
440   bf::path root_path = ci::GetRootAppPath(params.is_readonly,
441                                           params.test_user.uid);
442   bf::path package_path = root_path / pkgid;
443   EXTENDED_ASSERT_FALSE(bf::exists(package_path));
444
445   bf::path manifest_path = bf::path(getUserManifestPath(params.test_user.uid,
446       params.is_readonly)) / (pkgid + ".xml");
447   EXTENDED_ASSERT_FALSE(bf::exists(manifest_path));
448
449   // backups should not exist
450   bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
451   bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
452   EXTENDED_ASSERT_FALSE(bf::exists(package_backup));
453   EXTENDED_ASSERT_FALSE(bf::exists(manifest_backup));
454   return true;
455 }
456
457 bool CheckPackageNonExistance(const std::string& pkgid,
458                               const TestParameters& params) {
459   ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
460   EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
461       ci::GetRequestMode(params.test_user.uid)));
462   EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
463   if (params.test_user.uid == kGlobalUserUid) {
464     bf::path skel_path(kSkelDir);
465     EXTENDED_ASSERT_FALSE(bf::exists(skel_path / pkgid));
466     EXTENDED_ASSERT_FALSE(bf::exists(skel_path / kShared / pkgid));
467     EXTENDED_ASSERT_FALSE(bf::exists(skel_path / kSharedTmp / pkgid));
468     ci::UserList list = ci::GetUserList();
469     for (auto& l : list) {
470       bf::path root_path = ci::GetRootAppPath(false, std::get<0>(l));
471       EXTENDED_ASSERT_FALSE(bf::exists(root_path / kShared / pkgid));
472       EXTENDED_ASSERT_FALSE(bf::exists(root_path / kSharedTmp / pkgid));
473       bf::path package_path = root_path / pkgid;
474       EXTENDED_ASSERT_FALSE(bf::exists(package_path));
475     }
476   }
477   return true;
478 }
479
480 bool CheckAvailableExternalPath() {
481   bf::path ext_mount_path = ci::GetExternalCardPath();
482   LOG(DEBUG) << "ext_mount_path :" << ext_mount_path;
483   if (ext_mount_path.empty()) {
484     LOG(ERROR) << "Sdcard not exists!";
485     return false;
486   }
487   return true;
488 }
489
490 bool CheckAvailableExtendedPath() {
491   bf::path extended_path = bf::path(tzplatform_getenv(TZ_SYS_EXTENDEDSD));
492   LOG(DEBUG) << "extended_path :" << extended_path;
493   // TODO(jeremy.jang): It should be checked by libstorage API.
494   if (!bf::exists(extended_path)) {
495     LOG(ERROR) << "Extended storage not exists!";
496     return false;
497   }
498   return true;
499 }
500
501 bool CheckPackageReadonlyNonExistance(const std::string& pkgid,
502                                       const TestParameters& params) {
503   ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
504   EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
505       ci::GetRequestMode(params.test_user.uid)));
506   EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
507   return true;
508 }
509
510 static bool CheckSharedDataExistanceForPath(const bf::path& apps_rw,
511     const std::string& pkgid) {
512   bf::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
513   bf::path shared = apps_rw / kShared / pkgid / kData;
514   bf::path shared_tmp = apps_rw / kSharedTmp / pkgid;
515   EXTENDED_ASSERT_TRUE(bf::exists(shared_data_path));
516   EXTENDED_ASSERT_TRUE(bf::exists(shared));
517   EXTENDED_ASSERT_TRUE(bf::exists(shared_tmp));
518   return true;
519 }
520
521 static bool CheckSharedDataPermissions(const bf::path& apps_rw,
522     const std::string& pkgid, uid_t uid) {
523   bf::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
524   bf::path shared = apps_rw / kShared / pkgid / kData;
525   bf::path shared_tmp = apps_rw / kSharedTmp / pkgid;
526   // gid of RW dirs should be system_share
527   boost::optional<gid_t> system_share =
528       ci::GetGidByGroupName(kSystemShareGroupName);
529   struct stat stats;
530   stat(shared_data_path.c_str(), &stats);
531   EXTENDED_ASSERT_EQ(uid, stats.st_uid);
532   EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
533   stat(shared.c_str(), &stats);
534   EXTENDED_ASSERT_EQ(uid, stats.st_uid);
535   EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
536   stat(shared_tmp.c_str(), &stats);
537   EXTENDED_ASSERT_EQ(uid, stats.st_uid);
538   EXTENDED_ASSERT_EQ(kDefaultUserGid, stats.st_gid);
539   return true;
540 }
541
542 bool CheckSharedDataExistance(const std::string& pkgid,
543     const TestParameters& params) {
544   if (params.test_user.uid == kGlobalUserUid) {
545     bf::path skel_path(kSkelDir);
546     EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(kSkelDir, pkgid));
547     ci::UserList list = ci::GetUserList();
548     for (auto& l : list) {
549       uid_t uid = std::get<0>(l);
550       bf::path apps_rw = ci::GetRootAppPath(false, uid);
551       EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(apps_rw, pkgid));
552       EXTENDED_ASSERT_TRUE(CheckSharedDataPermissions(apps_rw, pkgid, uid));
553     }
554   } else {
555     bf::path apps_rw = ci::GetRootAppPath(false, params.test_user.uid);
556     EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(apps_rw, pkgid));
557     EXTENDED_ASSERT_TRUE(
558         CheckSharedDataPermissions(apps_rw, pkgid, params.test_user.uid));
559   }
560   return true;
561 }
562
563 static bool CheckSharedDataNonExistanceForPath(const bf::path& apps_rw,
564     const std::string pkgid) {
565   bf::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
566   bf::path shared = apps_rw / kShared / pkgid / kData;
567   bf::path shared_tmp = apps_rw / kSharedTmp / pkgid;
568   EXTENDED_ASSERT_FALSE(bf::exists(shared_data_path));
569   EXTENDED_ASSERT_FALSE(bf::exists(shared));
570   EXTENDED_ASSERT_FALSE(bf::exists(shared_tmp));
571   return true;
572 }
573
574 bool CheckSharedDataNonExistance(const std::string& pkgid,
575     const TestParameters& params) {
576   if (params.test_user.uid == kGlobalUserUid) {
577     bf::path skel_path(kSkelDir);
578     EXTENDED_ASSERT_TRUE(
579         CheckSharedDataNonExistanceForPath(skel_path, pkgid));
580
581     ci::UserList list = ci::GetUserList();
582     for (auto& l : list) {
583       uid_t uid = std::get<0>(l);
584       bf::path apps_rw = ci::GetRootAppPath(false, uid);
585       EXTENDED_ASSERT_TRUE(CheckSharedDataNonExistanceForPath(apps_rw, pkgid));
586     }
587   } else {
588     bf::path apps_rw = ci::GetRootAppPath(false, params.test_user.uid);
589     EXTENDED_ASSERT_TRUE(CheckSharedDataNonExistanceForPath(apps_rw, pkgid));
590   }
591   return true;
592 }
593
594 void BackendInterface::TestRollbackAfterEachStep(int argc, const char* argv[],
595     std::function<bool()> validator) const {
596   TestPkgmgrInstaller pkgmgr_installer;
597   std::unique_ptr<ci::AppQueryInterface> query_interface =
598       CreateQueryInterface();
599   auto pkgmgr =
600       ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
601                                   &pkgmgr_installer,
602                                   query_interface.get());
603   if (!pkgmgr) {
604     LOG(ERROR) << "Failed to initialize pkgmgr interface";
605     return;
606   }
607   AppInstallerPtr backend;
608   unsigned int insert_idx = 0;
609   do {
610     backend = CreateFailExpectedInstaller(pkgmgr, insert_idx);
611     LOG(DEBUG) << "StepFail is inserted at: " << insert_idx;
612     ASSERT_EQ(ci::AppInstaller::Result::ERROR, backend->Run());
613     if (!validator())
614       break;
615     insert_idx++;
616   } while (insert_idx < backend->StepCount());
617   ASSERT_EQ(insert_idx, backend->StepCount());
618 }
619
620 void BackendInterface::CrashAfterEachStep(std::vector<std::string>* args,
621     std::function<bool(int iter)> validator, PackageType type) const {
622   std::unique_ptr<const char*[]> argv(new const char*[args->size()]);
623   for (size_t i = 0; i < args->size(); ++i) {
624     argv[i] = args->at(i).c_str();
625   }
626   TestPkgmgrInstaller pkgmgr_installer;
627   auto query_interface = CreateQueryInterface();
628   auto pkgmgr =
629       ci::PkgMgrInterface::Create(args->size(), const_cast<char**>(argv.get()),
630                                   &pkgmgr_installer,
631                                   query_interface.get());
632   if (!pkgmgr) {
633     LOG(ERROR) << "Failed to initialize pkgmgr interface";
634     return;
635   }
636   auto backend = CreateFailExpectedInstaller(pkgmgr, 0);
637   ASSERT_EQ(backend->Run(), ci::AppInstaller::Result::ERROR);
638   int stepCount = backend->StepCount();
639
640   args->push_back("-idx");
641   args->push_back(std::to_string(stepCount));
642   int i;
643   std::string prefix = (type == PackageType::TPK) ? "tpk" : "wgt";
644   for (i = 0; i < stepCount; i++) {
645     ci::Subprocess backend_crash(
646         "/usr/bin/" + prefix + "-installer-ut/smoke-test-helper");
647     args->back() = std::to_string(i);
648     backend_crash.Run(*args);
649     ASSERT_NE(backend_crash.Wait(), 0);
650     if (!validator(i))
651       break;
652   }
653   ASSERT_EQ(stepCount, i);
654
655   args->push_back("-type_clean");
656   for (i = stepCount - 1; i >= 2; i--) {
657     ci::Subprocess backend_crash(
658         "/usr/bin/" + prefix + "-installer-ut/smoke-test-helper");
659     auto it = args->end();
660     it -= 2;
661     *it = std::to_string(i);
662     backend_crash.Run(*args);
663     ASSERT_NE(backend_crash.Wait(), 0);
664     if (!validator(i))
665       break;
666   }
667   ASSERT_EQ(i , 1);
668 }
669
670 BackendInterface::CommandResult BackendInterface::RunInstallersWithPkgmgr(
671     ci::PkgMgrPtr pkgmgr) const {
672   std::list<AppInstallerPtr> installers;
673   for (int i = 0; i < pkgmgr->GetRequestInfoCount(); i++) {
674     AppInstallerPtr installer;
675     if (mode_ == RequestResult::FAIL && i == pkgmgr->GetRequestInfoCount() - 1)
676       installer = factory_->CreateFailExpectedInstaller(i, pkgmgr);
677     else
678       installer = factory_->CreateInstaller(i, pkgmgr);
679     if (!installer)
680       LOG(ERROR) << "Failed to create installer";
681     else
682       installers.emplace_back(std::move(installer));
683   }
684
685   // FIXME: I think we should not implement this logic here...
686   CommandResult result = CommandResult::OK;
687   std::list<AppInstallerPtr>::iterator it(installers.begin());
688   for (; it != installers.end(); ++it) {
689     result = (*it)->Process();
690     if (result != CommandResult::OK)
691       break;
692   }
693   if (it != installers.end() && result == CommandResult::ERROR) {
694     do {
695       CommandResult ret = (*it)->Undo();
696       if (ret != CommandResult::OK && ret != CommandResult::ERROR)
697         result = CommandResult::UNDO_ERROR;
698     } while (it-- != installers.begin());
699   } else {
700     --it;
701     do {
702       if ((*it)->Clean() != CommandResult::OK)
703         result = CommandResult::CLEANUP_ERROR;
704     } while (it-- != installers.begin());
705   }
706   return result;
707 }
708
709 BackendInterface::CommandResult BackendInterface::CallBackendWithRunner(
710     int argc, const char* argv[]) const {
711   TestPkgmgrInstaller pkgmgr_installer;
712   auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
713       &pkgmgr_installer);
714   if (!pkgmgr) {
715     LOG(ERROR) << "Failed to initialize pkgmgr interface";
716     return BackendInterface::CommandResult::UNKNOWN;
717   }
718   return RunInstallersWithPkgmgr(pkgmgr);
719 }
720
721 BackendInterface::CommandResult BackendInterface::Install(
722     const std::vector<bf::path>& paths) const {
723   std::vector<const char*> argv;
724   argv.emplace_back("");
725   argv.emplace_back("-i");
726   for (const auto& p : paths)
727     argv.emplace_back(p.string().c_str());
728   return CallBackendWithRunner(argv.size(), argv.data());
729 }
730
731 BackendInterface::CommandResult BackendInterface::Uninstall(
732     const std::vector<std::string>& pkgids) const {
733   std::vector<const char*> argv;
734   argv.emplace_back("");
735   argv.emplace_back("-d");
736   for (const auto& p : pkgids)
737     argv.emplace_back(p.c_str());
738   return CallBackendWithRunner(argv.size(), argv.data());
739 }
740
741 BackendInterface::CommandResult BackendInterface::InstallSuccess(
742     const std::vector<bf::path>& paths) const {
743   RequestResult tmp_mode = mode_;
744   RequestResult &original_mode = const_cast<RequestResult&>(mode_);
745   original_mode = RequestResult::NORMAL;
746   if (Install(paths) != BackendInterface::CommandResult::OK) {
747     LOG(ERROR) << "Failed to install application. Cannot update";
748     return BackendInterface::CommandResult::UNKNOWN;
749   }
750   original_mode = tmp_mode;
751   return BackendInterface::CommandResult::OK;
752 }
753
754 BackendInterface::CommandResult BackendInterface::RunInstallerWithPkgrmgr(
755     ci::PkgMgrPtr pkgmgr) const {
756   std::unique_ptr<ci::AppInstaller> installer;
757   switch (mode_) {
758   case RequestResult::FAIL:
759     installer = CreateFailExpectedInstaller(pkgmgr);
760     break;
761   default:
762     installer = CreateInstaller(pkgmgr);
763     break;
764   }
765   return installer->Run();
766 }
767
768 BackendInterface::CommandResult BackendInterface::CallBackend(int argc,
769     const char* argv[]) const {
770   TestPkgmgrInstaller pkgmgr_installer;
771   auto query_interface = CreateQueryInterface();
772   auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
773       &pkgmgr_installer, query_interface.get());
774   if (!pkgmgr) {
775     LOG(ERROR) << "Failed to initialize pkgmgr interface";
776     return BackendInterface::CommandResult::UNKNOWN;
777   }
778   return RunInstallerWithPkgrmgr(pkgmgr);
779 }
780
781 BackendInterface::CommandResult BackendInterface::Install(
782     const bf::path& path) const {
783   const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
784   return CallBackend(SIZEOFARRAY(argv), argv);
785 }
786
787 BackendInterface::CommandResult BackendInterface::InstallPreload(
788     const bf::path& path) const {
789   const char* argv[] = {"", "-i", path.c_str(), "--preload"};
790   return CallBackend(SIZEOFARRAY(argv), argv);
791 }
792
793 BackendInterface::CommandResult BackendInterface::InstallWithStorage(
794     const bf::path& path, StorageType type) const {
795   int default_storage = 0;
796   int storage = 0;
797   switch (type) {
798     case StorageType::EXTERNAL:
799       storage = 1;
800       break;
801     case StorageType::EXTENDED:
802       storage = 2;
803       break;
804     default:
805       LOG(ERROR) << "Unknown storage type";
806       break;
807   }
808   vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
809       &default_storage);
810   vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, storage);
811
812   const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
813   BackendInterface::CommandResult result = CallBackend(SIZEOFARRAY(argv), argv);
814
815   vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
816       default_storage);
817   return result;
818 }
819
820 BackendInterface::CommandResult BackendInterface::MigrateLegacyExternalImage(
821     const std::string& pkgid,
822     const bf::path& path,
823     const bf::path& legacy_path) const {
824   if (InstallWithStorage(path, StorageType::EXTERNAL) !=
825       BackendInterface::CommandResult::OK) {
826     LOG(ERROR) << "Failed to install application. Cannot perform Migrate";
827     return BackendInterface::CommandResult::ERROR;
828   }
829
830   bf::path ext_mount_path = ci::GetExternalCardPath();
831   if (bf::is_empty(ext_mount_path)) {
832     LOG(ERROR) << "Sdcard not exists!";
833     return BackendInterface::CommandResult::ERROR;
834   }
835   bf::path app2sd_path = ext_mount_path / "app2sd";
836
837   char* image_name = app2ext_usr_getname_image(pkgid.c_str(),
838                      kGlobalUserUid);
839   if (!image_name) {
840     LOG(ERROR) << "Failed to get external image name";
841     return BackendInterface::CommandResult::ERROR;
842   }
843   bf::path org_image = app2sd_path / image_name;
844   free(image_name);
845
846   bs::error_code error;
847   bf::remove(org_image, error);
848   if (error) {
849     LOG(ERROR) << "Failed to remove org image";
850     return BackendInterface::CommandResult::ERROR;
851   }
852
853   bf::path db_path = tzplatform_getenv(TZ_SYS_DB);
854   bf::path app2sd_db = db_path / ".app2sd.db";
855   bf::path app2sd_db_journal = db_path / ".app2sd.db-journal";
856   bf::remove(app2sd_db, error);
857   if (error) {
858     LOG(ERROR) << "Failed to remove app2sd db";
859     return BackendInterface::CommandResult::ERROR;
860   }
861   bf::remove(app2sd_db_journal, error);
862   if (error) {
863     LOG(ERROR) << "Failed to remove app2sd journal db";
864     return BackendInterface::CommandResult::ERROR;
865   }
866
867   bf::path app2sd_migrate_db = legacy_path / kMigrateTestDBName;
868   if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) {
869     LOG(ERROR) << "Failed to copy test db";
870     return BackendInterface::CommandResult::ERROR;
871   }
872
873   bf::path legacy_src = legacy_path / pkgid;
874   bf::path legacy_dst = app2sd_path / pkgid;
875   if (!ci::CopyFile(legacy_src, legacy_dst)) {
876     LOG(ERROR) << "Failed to copy test image";
877     return BackendInterface::CommandResult::ERROR;
878   }
879   const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(),
880                        "-u", uid_str_.c_str()};
881   return CallBackend(SIZEOFARRAY(argv), argv);
882 }
883
884 BackendInterface::CommandResult BackendInterface::RDSUpdate(
885     const bf::path& path,
886     const std::string& pkgid) const {
887   RequestResult tmp_mode = mode_;
888   RequestResult &original_mode = const_cast<RequestResult&>(mode_);
889   original_mode = RequestResult::NORMAL;
890   if (Install(path) != BackendInterface::CommandResult::OK) {
891     LOG(ERROR) << "Failed to install application. Cannot perform RDS";
892     return BackendInterface::CommandResult::UNKNOWN;
893   }
894   const char* argv[] = {"", "-r", pkgid.c_str(), "-u",
895                         uid_str_.c_str()};
896   original_mode = tmp_mode;
897   return CallBackend(SIZEOFARRAY(argv), argv);
898 }
899
900 BackendInterface::CommandResult BackendInterface::EnablePackage(
901     const std::string& pkgid) const {
902   const char* argv[] = {"", "-A", pkgid.c_str(), "-u", uid_str_.c_str()};
903   return CallBackend(SIZEOFARRAY(argv), argv);
904 }
905
906 BackendInterface::CommandResult BackendInterface::DisablePackage(
907     const std::string& pkgid) const {
908   const char* argv[] = {"", "-D", pkgid.c_str(), "-u", uid_str_.c_str()};
909   return CallBackend(SIZEOFARRAY(argv), argv);
910 }
911
912 BackendInterface::CommandResult BackendInterface::Recover(
913     const bf::path& recovery_file) const {
914   const char* argv[] = {"", "-b", recovery_file.c_str(), "-u",
915       uid_str_.c_str()};
916   return CallBackend(SIZEOFARRAY(argv), argv);
917 }
918
919 BackendInterface::CommandResult BackendInterface::ManifestDirectInstall(
920     const std::string& pkgid) const {
921   const char* argv[] = {"", "-y", pkgid.c_str(), "-u", uid_str_.c_str()};
922   return CallBackend(SIZEOFARRAY(argv), argv);
923 }
924
925 BackendInterface::CommandResult BackendInterface::Uninstall(
926     const std::string& pkgid) const {
927   const char* argv[] = {"", "-d", pkgid.c_str(), "-u", uid_str_.c_str()};
928   return CallBackend(SIZEOFARRAY(argv), argv);
929 }
930
931 BackendInterface::CommandResult BackendInterface::UninstallPreload(
932     const std::string& pkgid) const {
933   const char* argv[] = {"", "-d", pkgid.c_str(), "--preload",
934       "--force-remove"};
935   return CallBackend(SIZEOFARRAY(argv), argv);
936 }
937
938 BackendInterface::CommandResult BackendInterface::InstallSuccess(
939     const bf::path& path) const {
940   RequestResult tmp_mode = mode_;
941   RequestResult &original_mode = const_cast<RequestResult&>(mode_);
942   original_mode = RequestResult::NORMAL;
943   if (Install(path) != BackendInterface::CommandResult::OK) {
944     LOG(ERROR) << "Failed to install application. Cannot update";
945     return BackendInterface::CommandResult::UNKNOWN;
946   }
947   original_mode = tmp_mode;
948   return BackendInterface::CommandResult::OK;
949 }
950
951 BackendInterface::CommandResult BackendInterface::InstallPreloadSuccess(
952     const bf::path& path) const {
953   RequestResult tmp_mode = mode_;
954   RequestResult &original_mode = const_cast<RequestResult&>(mode_);
955   original_mode = RequestResult::NORMAL;
956   if (InstallPreload(path) != BackendInterface::CommandResult::OK) {
957     LOG(ERROR) << "Failed to install application. Cannot update";
958     return BackendInterface::CommandResult::UNKNOWN;
959   }
960   original_mode = tmp_mode;
961   return BackendInterface::CommandResult::OK;
962 }
963
964 BackendInterface::CommandResult BackendInterface::MountInstall(
965     const bf::path& path) const {
966   const char* argv[] = {"", "-w", path.c_str(), "-u", uid_str_.c_str()};
967   return CallBackend(SIZEOFARRAY(argv), argv);
968 }
969
970 BackendInterface::CommandResult BackendInterface::MountInstallSuccess(
971     const bf::path& path) const {
972   RequestResult tmp_mode = mode_;
973   RequestResult &original_mode = const_cast<RequestResult&>(mode_);
974   original_mode = RequestResult::NORMAL;
975   if (MountInstall(path) != BackendInterface::CommandResult::OK) {
976     LOG(ERROR) << "Failed to mount-install application. Cannot mount-update";
977     return BackendInterface::CommandResult::UNKNOWN;
978   }
979   original_mode = tmp_mode;
980   return BackendInterface::CommandResult::OK;
981 }
982
983 static boost::filesystem::path GetTrashPath(
984     const boost::filesystem::path& path) {
985   return path.string() + ".trash";
986 }
987
988 SmokeTestHelperRunner::Result SmokeTestHelperRunner::RunSubprocess(
989     std::vector<std::string> args) const {
990   args.push_back("-remove_plugin_steps");
991   ci::Subprocess backend = CreateSubprocess();
992   backend.RunWithArgs(args);
993   int status = backend.Wait();
994   if (WIFEXITED(status)) {
995     if (WEXITSTATUS(status) == 0)
996       return SmokeTestHelperRunner::Result::SUCCESS;
997     else
998       return SmokeTestHelperRunner::Result::FAIL;
999   }
1000   return SmokeTestHelperRunner::Result::UnKnown;
1001 }
1002
1003 SmokeTestHelperRunner::Result SmokeTestHelperRunner::RunSubprocessAndKill(
1004     std::vector<std::string> args, useconds_t delay) const {
1005   args.push_back("-remove_plugin_steps");
1006   ci::Subprocess backend = CreateSubprocess();
1007   backend.RunWithArgs(args);
1008   usleep(delay);
1009   backend.Kill();
1010   int status = backend.Wait();
1011   if (WIFEXITED(status)) {
1012     if (WEXITSTATUS(status) == 0)
1013       return SmokeTestHelperRunner::Result::SUCCESS;
1014     else
1015       return SmokeTestHelperRunner::Result::FAIL;
1016   } else {
1017     if (WTERMSIG(status) == SIGKILL)
1018       return SmokeTestHelperRunner::Result::KILLED;
1019     else
1020       return SmokeTestHelperRunner::Result::UnKnown;
1021   }
1022 }
1023
1024 SmokeTestHelperRunner::Result SmokeTestHelperRunner::InstallWithSubprocess(
1025     const bf::path& path, uid_t uid) const {
1026   std::vector<std::string> args =
1027       { "-i", path.string(), "-u", std::to_string(uid) };
1028   return RunSubprocess(args);
1029 }
1030
1031 SmokeTestHelperRunner::Result SmokeTestHelperRunner::MountInstallWithSubprocess(
1032     const bf::path& path, uid_t uid) const {
1033   std::vector<std::string> args =
1034       { "-w", path.string(), "-u", std::to_string(uid) };
1035   return RunSubprocess(args);
1036 }
1037
1038 SmokeTestHelperRunner::Result SmokeTestHelperRunner::RecoveryWithSubprocess(
1039     const bf::path& path, uid_t uid) const {
1040   std::vector<std::string> args =
1041       { "-b", path.string(), "-u", std::to_string(uid) };
1042   return RunSubprocess(args);
1043 }
1044
1045 SmokeTestHelperRunner::Result SmokeTestHelperRunner::UninstallWithSubprocess(
1046     const std::string& pkgid, uid_t uid) const {
1047   std::vector<std::string> args = { "-d", pkgid, "-u", std::to_string(uid) };
1048   return RunSubprocess(args);
1049 }
1050
1051 SmokeTestHelperRunner::Result
1052     SmokeTestHelperRunner::InstallWithSubprocessAndKill(
1053         const bf::path& path, uid_t uid, useconds_t delay) const {
1054   std::vector<std::string> args =
1055       { "-i", path.string(), "-u", std::to_string(uid) };
1056   return RunSubprocessAndKill(args, delay);
1057 }
1058
1059 SmokeTestHelperRunner::Result
1060     SmokeTestHelperRunner::MountInstallWithSubprocessAndKill(
1061         const bf::path& path, uid_t uid, useconds_t delay) const {
1062   std::vector<std::string> args =
1063       { "-w", path.string(), "-u", std::to_string(uid) };
1064   return RunSubprocessAndKill(args, delay);
1065 }
1066
1067 SmokeTestHelperRunner::Result
1068     SmokeTestHelperRunner::UninstallWithSubprocessAndKill(
1069         const std::string& pkgid, uid_t uid, useconds_t delay) const {
1070   std::vector<std::string> args =
1071       { "-d", pkgid, "-u", std::to_string(uid) };
1072   return RunSubprocessAndKill(args, delay);
1073 }
1074
1075 SmokeTestHelperRunner::Result SmokeTestHelperRunner::InstallPkgsWithSubprocess(
1076     const std::vector<bf::path>& paths, uid_t uid) const {
1077   std::vector<std::string> args;
1078   args.emplace_back("-i");
1079   for (const bf::path& p : paths)
1080     args.emplace_back(p.string());
1081   args.emplace_back("-u");
1082   args.emplace_back(std::to_string(uid));
1083   return RunSubprocess(args);
1084 }
1085
1086 SmokeTestHelperRunner::Result
1087     SmokeTestHelperRunner::MountInstallPkgsWithSubprocess(
1088     const std::vector<bf::path>& paths, uid_t uid) const {
1089   std::vector<std::string> args;
1090   args.emplace_back("-w");
1091   for (const bf::path& p : paths)
1092     args.emplace_back(p.string());
1093   args.emplace_back("-u");
1094   args.emplace_back(std::to_string(uid));
1095   return RunSubprocess(args);
1096 }
1097
1098 SmokeTestHelperRunner::Result SmokeTestHelperRunner::RecoveryPkgsWithSubprocess(
1099     const std::vector<bf::path>& paths, uid_t uid) const {
1100   std::vector<std::string> args;
1101   args.emplace_back("-b");
1102   for (const bf::path& p : paths)
1103     args.emplace_back(p.string());
1104   args.emplace_back("-u");
1105   args.emplace_back(std::to_string(uid));
1106   return RunSubprocess(args);
1107 }
1108
1109 SmokeTestHelperRunner::Result
1110     SmokeTestHelperRunner::UninstallPkgsWithSubprocess(
1111         const std::vector<std::string>& pkgids, uid_t uid) const {
1112   std::vector<std::string> args;
1113   args.emplace_back("-d");
1114   args.insert(args.end(), pkgids.begin(), pkgids.end());
1115   args.emplace_back("-u");
1116   args.emplace_back(std::to_string(uid));
1117   return RunSubprocess(args);
1118 }
1119
1120 SmokeTestHelperRunner::Result
1121     SmokeTestHelperRunner::InstallPkgsWithSubprocessAndKill(
1122         const std::vector<bf::path>& paths, uid_t uid, useconds_t delay) const {
1123   std::vector<std::string> args;
1124   args.emplace_back("-i");
1125   for (const bf::path& p : paths)
1126     args.emplace_back(p.string());
1127   args.emplace_back("-u");
1128   args.emplace_back(std::to_string(uid));
1129   return RunSubprocessAndKill(args, delay);
1130 }
1131
1132 SmokeTestHelperRunner::Result
1133     SmokeTestHelperRunner::MountInstallPkgsWithSubprocessAndKill(
1134         const std::vector<bf::path>& paths, uid_t uid, useconds_t delay) const {
1135   std::vector<std::string> args;
1136   args.emplace_back("-w");
1137   for (const bf::path& p : paths)
1138     args.emplace_back(p.string());
1139   args.emplace_back("-u");
1140   args.emplace_back(std::to_string(uid));
1141   return RunSubprocessAndKill(args, delay);
1142 }
1143
1144 bool CopySmackAccess(const boost::filesystem::path& src,
1145                      const boost::filesystem::path& dst) {
1146   if (!bf::exists(src) && !bf::is_symlink(src)) {
1147     LOG(ERROR) << "Failed to copy smack access label";
1148     return false;
1149   }
1150   int ret;
1151   char* access_label = nullptr;
1152   ret = smack_lgetlabel(src.c_str(), &access_label, SMACK_LABEL_ACCESS);
1153   if (ret < 0) {
1154     LOG(ERROR) << "get access label from [" << src << "] fail";
1155     return false;
1156   }
1157   if (!access_label)
1158     return true;
1159   ret = smack_lsetlabel(dst.c_str(), access_label, SMACK_LABEL_ACCESS);
1160   free(access_label);
1161   if (ret < 0) {
1162     LOG(ERROR) << "set access label to [" << dst << "] fail";
1163     return false;
1164   }
1165   return true;
1166 }
1167
1168 bool CopySmackExec(const boost::filesystem::path& src,
1169                    const boost::filesystem::path& dst) {
1170   if (!bf::exists(src) && !bf::is_symlink(src)) {
1171     LOG(ERROR) << "Failed to copy smack exec label";
1172     return false;
1173   }
1174   int ret;
1175   char *exec_label = nullptr;
1176   ret = smack_lgetlabel(src.c_str(), &exec_label, SMACK_LABEL_EXEC);
1177   if (ret < 0) {
1178     LOG(ERROR) << "get exec label from [" << src << "] fail";
1179     return false;
1180   }
1181   if (!exec_label)
1182     return true;
1183   ret = smack_lsetlabel(dst.c_str(), exec_label, SMACK_LABEL_EXEC);
1184   free(exec_label);
1185   if (ret < 0) {
1186     LOG(ERROR) << "set exec label to [" << dst << "] fail";
1187     return false;
1188   }
1189   return true;
1190 }
1191
1192 bool CopySmackMmap(const boost::filesystem::path& src,
1193                    const boost::filesystem::path& dst) {
1194   if (!bf::exists(src) && !bf::is_symlink(src)) {
1195     LOG(ERROR) << "Failed to copy smack mmap label";
1196     return false;
1197   }
1198   int ret;
1199   char *mmap_label = nullptr;
1200   ret = smack_lgetlabel(src.c_str(), &mmap_label, SMACK_LABEL_MMAP);
1201   if (ret < 0) {
1202     LOG(ERROR) << "get mmap label from [" << src << "] fail";
1203     return false;
1204   }
1205   if (!mmap_label)
1206     return true;
1207   ret = smack_lsetlabel(dst.c_str(), mmap_label, SMACK_LABEL_MMAP);
1208   free(mmap_label);
1209   if (ret < 0) {
1210     LOG(ERROR) << "set mmap label to [" << dst << "] fail";
1211     return false;
1212   }
1213   return true;
1214 }
1215
1216 bool CopySmackTransmute(const boost::filesystem::path& src,
1217                         const boost::filesystem::path& dst) {
1218   if (!bf::exists(src)) {
1219     LOG(ERROR) << "Failed to copy smack tranmute label";
1220     return false;
1221   }
1222   int ret;
1223   char *transmute_label = nullptr;
1224   ret = smack_lgetlabel(src.c_str(), &transmute_label, SMACK_LABEL_TRANSMUTE);
1225   if (ret < 0) {
1226     LOG(ERROR) << "get access label from [" << src << "] fail";
1227     return false;
1228   }
1229   if (!transmute_label) {
1230     ret = smack_lsetlabel(dst.c_str(), "0", SMACK_LABEL_TRANSMUTE);
1231   } else {
1232     if (strcmp(transmute_label, "TRUE") == 0)
1233       ret = smack_lsetlabel(dst.c_str(), "1", SMACK_LABEL_TRANSMUTE);
1234     else
1235       ret = smack_lsetlabel(dst.c_str(), "0", SMACK_LABEL_TRANSMUTE);
1236     free(transmute_label);
1237     if (ret < 0) {
1238       LOG(ERROR) << "set access label to [" << dst << "] fail";
1239       return false;
1240     }
1241   }
1242
1243   return true;
1244 }
1245
1246 bool CopySmackLabels(const boost::filesystem::path& src,
1247                      const boost::filesystem::path& dst) {
1248   if (!CopySmackAccess(src, dst))
1249     return false;
1250   if (!CopySmackExec(src, dst))
1251     return false;
1252   if (!CopySmackMmap(src, dst))
1253     return false;
1254   if (!bf::is_symlink(src) && bf::is_directory(src)) {
1255     if (!CopySmackTransmute(src, dst))
1256       return false;
1257   }
1258   return true;
1259 }
1260
1261 bool CopyAndRemoveWithSmack(const bf::path& src, const bf::path& dst) {
1262   bs::error_code error;
1263   if (bf::exists(dst)) {
1264     try {
1265       bf::remove_all(dst, error);
1266     } catch (...) {
1267       std::cout << "Exception occurred during remove [" << dst.string()
1268                 << "], and skip this file"<< std::endl;
1269     }
1270     if (error) {
1271       if (!bf::is_directory(dst)) {
1272         LOG(ERROR) << "remove_all fail";
1273         return false;
1274       }
1275     }
1276   }
1277   try {
1278     if (bf::is_symlink(src)) {
1279       bf::copy_symlink(src, dst, error);
1280       if (error) {
1281         LOG(ERROR) << "Failed to copy symlink: " << src << ", "
1282                    << error.message();
1283         return false;
1284       }
1285       if (!CopySmackLabels(src, dst)) {
1286         LOG(ERROR) << "copy smack label from [" << src.string()
1287                    << "] to [" << dst.string() << "] fail";
1288         return false;
1289       }
1290     } else if (bf::is_directory(src)) {
1291       if (!bf::exists(dst)) {
1292         bf::create_directories(dst, error);
1293         if (error) {
1294           LOG(ERROR) << "create directories fail";
1295           return false;
1296         }
1297         ci::CopyOwnershipAndPermissions(src, dst);
1298         if (!CopySmackLabels(src, dst)) {
1299           LOG(ERROR) << "copy smack label from [" << src.string()
1300                      << "] to [" << dst.string() << "] fail";
1301           return false;
1302         }
1303       }
1304       bool success = true;
1305       for (bf::directory_iterator file(src);
1306           file != bf::directory_iterator();
1307           ++file) {
1308         bf::path current(file->path());
1309         bf::path target = dst / current.filename();
1310         success &= CopyAndRemoveWithSmack(current, target);
1311       }
1312       bf::remove_all(src);
1313       if (!success)
1314         return false;
1315     } else {
1316       bf::copy_file(src, dst);
1317       ci::CopyOwnershipAndPermissions(src, dst);
1318       if (!CopySmackLabels(src, dst)) {
1319         LOG(ERROR) << "copy smack label from [" << src.string()
1320                    << "] to [" << dst.string() << "] fail";
1321         return false;
1322       }
1323       bf::remove_all(src);
1324     }
1325   } catch (...) {
1326     std::cout << "Exception occurred during copy [" << src.string()
1327               << "], and skip this file"<< std::endl;
1328     return true;
1329   }
1330
1331   return true;
1332 }
1333
1334 bool BackupPathCopyAndRemove(const bf::path& path) {
1335   if (!bf::exists(path))
1336     return true;
1337
1338   bf::path backup_path = path.string() + ".bck";
1339   std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
1340   if (!CopyAndRemoveWithSmack(path, backup_path)) {
1341     LOG(ERROR) << "Failed to setup test environment. Does some previous"
1342                << " test crashed? Path: "
1343                << backup_path << " should not exist.";
1344     return false;
1345   }
1346   return true;
1347 }
1348
1349 bool BackupPath(const bf::path& path) {
1350   bf::path trash_path = GetTrashPath(path);
1351   if (bf::exists(trash_path)) {
1352     LOG(ERROR) << trash_path << " exists. Please remove "
1353                << trash_path << " manually!";
1354     return false;
1355   }
1356   bf::path backup_path = path.string() + ".bck";
1357   std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
1358   bs::error_code error;
1359   bf::remove_all(backup_path, error);
1360   if (error)
1361     LOG(ERROR) << "Remove failed: " << backup_path
1362                << " (" << error.message() << ")";
1363   if (bf::exists(path)) {
1364     bf::rename(path, backup_path, error);
1365     if (error) {
1366       LOG(ERROR) << "Failed to setup test environment. Does some previous"
1367                  << " test crashed? Path: "
1368                  << backup_path << " should not exist.";
1369       return false;
1370     }
1371     assert(!error);
1372     if (bf::is_directory(backup_path))
1373       bf::create_directory(path);
1374   }
1375   return true;
1376 }
1377
1378 bool RestorePathCopyAndRemove(const bf::path& path) {
1379   bf::path backup_path = path.string() + ".bck";
1380   if (!bf::exists(backup_path))
1381     return true;
1382
1383   std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
1384   if (!CopyAndRemoveWithSmack(backup_path, path)) {
1385     LOG(ERROR) << "Failed to restore backup path: " << backup_path;
1386     return false;
1387   }
1388   return true;
1389 }
1390
1391 bool RestorePath(const bf::path& path) {
1392   bf::path backup_path = path.string() + ".bck";
1393   std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
1394   bs::error_code error;
1395   bf::remove_all(path, error);
1396   if (error) {
1397     bf::path trash_path = GetTrashPath(path);
1398     LOG(ERROR) << "Remove failed: " << path << " (" << error.message() << ")";
1399     std::cout << "Moving " << path << " to " << trash_path << std::endl;
1400     bf::rename(path, trash_path, error);
1401     if (error)
1402       LOG(ERROR) << "Failed to move " << path << " to " << trash_path
1403                  << " (" << error.message() << ")";
1404     else
1405       LOG(ERROR) << trash_path << " should be removed manually!";
1406   }
1407   if (bf::exists(backup_path)) {
1408     bf::rename(backup_path, path, error);
1409     if (error) {
1410       LOG(ERROR) << "Failed to restore backup path: " << backup_path
1411                  << " (" << error.message() << ")";
1412       return false;
1413     }
1414   }
1415   return true;
1416 }
1417
1418 std::vector<bf::path> SetupBackupDirectories(uid_t test_uid) {
1419   std::vector<bf::path> entries;
1420   bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB));
1421   if (test_uid != kGlobalUserUid)
1422     db_dir = db_dir / "user" / std::to_string(test_uid);
1423   for (auto e : kDBEntries) {
1424     bf::path path = db_dir / e;
1425     entries.emplace_back(path);
1426   }
1427
1428   if (getuid() == 0) {
1429     entries.emplace_back(kPreloadApps);
1430     entries.emplace_back(kPreloadManifestDir);
1431     entries.emplace_back(kPreloadIcons);
1432   }
1433
1434   if (test_uid == kGlobalUserUid) {
1435     entries.emplace_back(kSkelDir);
1436     entries.emplace_back(kGlobalManifestDir);
1437     ci::UserList list = ci::GetUserList();
1438     for (auto l : list) {
1439       bf::path apps = std::get<2>(l) / "apps_rw";
1440       entries.emplace_back(apps);
1441     }
1442   } else {
1443     tzplatform_set_user(test_uid);
1444     bf::path approot = tzplatform_getenv(TZ_USER_APPROOT);
1445     tzplatform_reset_user();
1446     entries.emplace_back(approot);
1447   }
1448
1449   bf::path apps_rw = ci::GetRootAppPath(false, test_uid);
1450   entries.emplace_back(apps_rw);
1451   entries.emplace_back(kSdkDirectory);
1452
1453   return entries;
1454 }
1455
1456 void UninstallAllAppsInDirectory(bf::path dir, bool is_preload,
1457     BackendInterface* backend) {
1458   if (bf::exists(dir)) {
1459     for (auto& dir_entry : boost::make_iterator_range(
1460         bf::directory_iterator(dir), bf::directory_iterator())) {
1461       if (dir_entry.path().string().find("smoke") != std::string::npos &&
1462           bf::is_directory(dir_entry)) {
1463         std::string package = dir_entry.path().filename().string();
1464         std::regex pkg_regex("smoke[a-zA-Z0-9]{5,}");
1465         if (std::regex_match(package, pkg_regex)) {
1466           BackendInterface::CommandResult result =
1467               BackendInterface::CommandResult::OK;
1468           if (is_preload)
1469             result = backend->UninstallPreload(
1470                 dir_entry.path().filename().string());
1471           else
1472             result = backend->Uninstall(
1473                 dir_entry.path().filename().string());
1474           if (result != BackendInterface::CommandResult::OK) {
1475             LOG(ERROR) << "Cannot uninstall smoke test app: "
1476                 << dir_entry.path().filename().string();
1477           }
1478         }
1479       }
1480     }
1481   }
1482 }
1483
1484 void UninstallAllSmokeApps(ci::RequestMode request_mode, uid_t test_uid,
1485     BackendInterface *backend) {
1486   std::cout << "Uninstalling all smoke apps" << std::endl;
1487   bf::path apps_rw = ci::GetRootAppPath(false, test_uid);
1488   UninstallAllAppsInDirectory(apps_rw, false, backend);
1489   if (getuid() == 0 && request_mode == ci::RequestMode::GLOBAL) {
1490     bf::path root_path = kPreloadApps;
1491     UninstallAllAppsInDirectory(root_path, true, backend);
1492   }
1493 }
1494
1495 int GetAppInstalledTime(const char* appid, uid_t uid) {
1496   int ret = 0;
1497   int installed_time = 0;
1498   pkgmgrinfo_appinfo_h handle = NULL;
1499   ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &handle);
1500   if (ret != PMINFO_R_OK)
1501     return -1;
1502   ret = pkgmgrinfo_appinfo_get_installed_time(handle, &installed_time);
1503   if (ret != PMINFO_R_OK) {
1504     pkgmgrinfo_appinfo_destroy_appinfo(handle);
1505     return -1;
1506   }
1507   pkgmgrinfo_appinfo_destroy_appinfo(handle);
1508   return installed_time;
1509 }
1510
1511 }  // namespace smoke_test