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