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