Add new lib with common smoke utils for tests 36/149136/7
authorDamian Pietruchowski <d.pietruchow@samsung.com>
Mon, 21 Aug 2017 09:27:35 +0000 (11:27 +0200)
committerBartlomiej Kunikowski <b.kunikowski@partner.samsung.com>
Wed, 25 Oct 2017 05:55:20 +0000 (05:55 +0000)
Wgt-backend and tpk-backend have common util functions for smoke tests.
They should be exported to lib in app-installers.

Submit together:
- https://review.tizen.org/gerrit/#/c/149137/
- https://review.tizen.org/gerrit/#/c/149601/

Change-Id: Ifef1e9f38790133c7337650c8641e0cd0bab57f1
Signed-off-by: Damian Pietruchowski <d.pietruchow@samsung.com>
CMakeLists.txt
packaging/app-installers.spec
src/unit_tests/CMakeLists.txt
src/unit_tests/common/CMakeLists.txt [new file with mode: 0644]
src/unit_tests/common/smoke_utils.cc [new file with mode: 0644]
src/unit_tests/common/smoke_utils.h [new file with mode: 0644]

index 911f052..c406144 100644 (file)
@@ -32,6 +32,7 @@ SET(TARGET_PKGDIR_TOOL "pkgdir-tool")
 SET(TARGET_PKG_INITDB "pkg_initdb")
 SET(TARGET_PKG_RECOVERY "pkg_recovery")
 SET(TARGET_PKG_RECOVERY_HELPER "pkg_recovery_helper")
+SET(TARGET_SMOKE_UTILS "smoke-utils")
 
 ADD_DEFINITIONS("-DPROJECT_TAG=\"APP_INSTALLERS\"")
 
@@ -65,6 +66,7 @@ PKG_CHECK_MODULES(STORAGE_DEPS REQUIRED storage)
 PKG_CHECK_MODULES(LIBSYSTEMD_DEPS REQUIRED libsystemd)
 PKG_CHECK_MODULES(TTRACE_DEPS REQUIRED ttrace)
 PKG_CHECK_MODULES(TRUST_ANCHOR_DEPS REQUIRED tanchor)
+PKG_CHECK_MODULES(GUM_DEPS REQUIRED libgum)
 
 FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem program_options)
 FIND_PACKAGE(GTest REQUIRED)
index 5116652..d7e379c 100644 (file)
@@ -63,7 +63,7 @@ Summary: Unit tests for app-installers
 Requires: %{name} = %{version}
 
 %description tests
-Unit tests for al modules of app-installers
+Unit tests for al modules of app-installers and common utils for smoke test
 
 %prep
 %setup -q
@@ -128,6 +128,8 @@ chsmack -a System %{unpackdir}
 %{_bindir}/app-installers-ut/*
 %{_datadir}/app-installers-ut/*
 %{_libdir}/libtest-assessor-lib.so*
+%{_libdir}/libsmoke-utils.so*
+%{_includedir}/app-installers/unit_tests/common/smoke_utils.h
 
 %changelog
 * Tue Sep 01 2015 Pawel Sikorski <p.sikorski@samsung.com> 1.8-1
index 7746348..f2ca8d8 100644 (file)
@@ -51,3 +51,4 @@ INSTALL(TARGETS ${TARGET_SIGNATURE_TEST} DESTINATION ${BINDIR}/${DESTINATION_DIR
 INSTALL(TARGETS ${TARGET_PLUGINS_TEST} DESTINATION ${BINDIR}/${DESTINATION_DIR})
 
 ADD_SUBDIRECTORY(libs)
+ADD_SUBDIRECTORY(common)
diff --git a/src/unit_tests/common/CMakeLists.txt b/src/unit_tests/common/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e200daa
--- /dev/null
@@ -0,0 +1,16 @@
+ADD_LIBRARY(${TARGET_SMOKE_UTILS} SHARED
+  smoke_utils.cc
+)
+
+APPLY_PKG_CONFIG(${TARGET_SMOKE_UTILS} PUBLIC
+  Boost
+  GTEST
+  GUM_DEPS
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_SMOKE_UTILS} PRIVATE
+  ${TARGET_LIBNAME_COMMON}
+)
+
+INSTALL(TARGETS ${TARGET_SMOKE_UTILS} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(FILES smoke_utils.h DESTINATION ${INCLUDEDIR}/app-installers/unit_tests/common/)
diff --git a/src/unit_tests/common/smoke_utils.cc b/src/unit_tests/common/smoke_utils.cc
new file mode 100644 (file)
index 0000000..30b49c0
--- /dev/null
@@ -0,0 +1,929 @@
+// Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "unit_tests/common/smoke_utils.h"
+
+#include <gum/gum-user.h>
+#include <gum/gum-user-service.h>
+#include <gum/common/gum-user-types.h>
+#include <manifest_parser/utils/version_number.h>
+
+#include <boost/filesystem/path.hpp>
+#include <gtest/gtest.h>
+
+#include <common/app_installer.h>
+#include <common/paths.h>
+#include <common/pkgmgr_interface.h>
+#include <common/pkgmgr_query.h>
+#include <common/tzip_interface.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
+namespace bo = boost::program_options;
+
+namespace {
+
+const uid_t kDefaultUserUid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+const char kNormalUserName[] = "smokeuser";
+const char kSystemShareGroupName[] = "system_share";
+const char kMigrateTestDBName[] = "app2sd_migrate.db";
+// common entries
+const std::vector<std::string> kDBEntries = {
+  {".pkgmgr_parser.db"},
+  {".pkgmgr_parser.db-journal"},
+  {".pkgmgr_cert.db"},
+  {".pkgmgr_cert.db-journal"},
+  {".app2sd.db"},
+  {".app2sd.db-journal"},
+};
+// globaluser entries
+const char kGlobalManifestDir[] = "/opt/share/packages";
+const char kSkelDir[] = "/etc/skel/apps_rw";
+const char kPreloadApps[] = "/usr/apps";
+const char kPreloadManifestDir[] = "/usr/share/packages";
+const char kPreloadIcons[] = "/usr/share/icons";
+
+enum RWDirectory {
+  DATA,
+  CACHE,
+  SHARED_CACHE,
+  SHARED_DATA,
+  SHARED_TRUSTED
+};
+
+const char* rwDirectories[] = {
+  "data",
+  "cache",
+  "shared/cache",
+  "shared/data",
+  "shared/trusted",
+};
+
+}  // namespace
+
+namespace smoke_test {
+
+const char kLegacyExtImageDir[] = "legacy_extimage_dir";
+const std::string& kDefaultUserIdStr = std::to_string(kDefaultUserUid);
+const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+const uid_t kGlobalUserGid = tzplatform_getgid(TZ_SYS_GLOBALAPP_USER);
+
+ci::RequestMode ParseRequestMode(int argc,  char** argv) {
+  bo::options_description desc("Available options");
+  desc.add_options()
+      ("request-mode", bo::value<std::string>(), "set request mode")
+      ("global-request,g", "set request mode to global")
+      ("user-request,u", "set request mode to user");
+
+  bo::variables_map vm;
+  bo::store(bo::command_line_parser(argc, argv).
+      options(desc).allow_unregistered().run(), vm);
+  bo::notify(vm);
+
+  if (vm.count("global-request")) {
+    std::cout << "Request mode was set to global." << std::endl;
+    return ci::RequestMode::GLOBAL;
+  }
+  if (vm.count("user-request")) {
+    std::cout << "Request mode was set to user." << std::endl;
+    return ci::RequestMode::USER;
+  }
+  if (vm.count("request-mode")) {
+    if (vm["request-mode"].as<std::string>() == "global") {
+      std::cout << "Request mode was set to global." << std::endl;
+      return ci::RequestMode::GLOBAL;
+    }
+    if (vm["request-mode"].as<std::string>() == "user") {
+      std::cout << "Request mode was set to user." << std::endl;
+      return ci::RequestMode::USER;
+    }
+    std::cout << "Cannot set request mode to "
+              << vm["request-mode"].as<std::string>() << std::endl;
+  }
+  std::cout << "Request mode was set to global." << std::endl;
+  return ci::RequestMode::GLOBAL;
+}
+
+static bool AddUser(const char* user_name) {
+  GumUser* user = nullptr;
+  user = gum_user_create_sync(FALSE);
+  if (user == nullptr)
+    LOG(WARNING) << "Failed to create gum user! (user name: "
+                 << user_name << ")";
+  g_object_set(G_OBJECT(user), "username", user_name, "usertype",
+      GUM_USERTYPE_NORMAL, NULL);
+  gboolean rval = FALSE;
+  rval = gum_user_add_sync(user);
+  g_object_unref(user);
+  return rval;
+}
+
+static bool DeleteUser(const char* user_name, bool rem_home_dir) {
+  bool rval = FALSE;
+  GumUser* guser = gum_user_get_by_name_sync(user_name, FALSE);
+  if (guser)
+    rval = gum_user_delete_sync(guser, rem_home_dir);
+  return rval;
+}
+
+bool AddTestUser(User* test_user) {
+  std::cout << "Adding test user: " << kNormalUserName << std::endl;
+  AddUser(kNormalUserName);
+  if (boost::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName)) {
+    test_user->uid = *uid;
+    std::cout << "User created properly: uid=" << *uid;
+    if (boost::optional<gid_t> gid = ci::GetGidByUid(*uid)) {
+      test_user->gid = *gid;
+      std::cout << " gid=" << *gid;
+    }
+    std::cout << std::endl;
+    return true;
+  }
+  LOG(ERROR) << "Adding test user failed";
+  return false;
+}
+
+bool DeleteTestUser() {
+  std::cout << "Deleting test user: " << kNormalUserName << std::endl;
+  uid_t test_uid;
+  if (boost::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName))
+    test_uid = *uid;
+  else
+    return false;
+  DeleteUser(kNormalUserName, true);
+  if (!ci::GetUidByUserName(kNormalUserName)) {
+    std::cout << "User deleted properly: user_name=" << kNormalUserName
+              << " uid=" << test_uid << std::endl;
+    return true;
+  }
+  LOG(ERROR) << "Deleting test user failed";
+  return false;
+}
+
+bool TouchFile(const bf::path& path) {
+  FILE* f = fopen(path.c_str(), "w+");
+  if (!f)
+    return false;
+  fclose(f);
+  return true;
+}
+
+void AddDataFiles(const std::string& pkgid, uid_t uid) {
+  if (uid == kGlobalUserUid) {
+    ci::UserList list = ci::GetUserList();
+    for (auto l : list) {
+      auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
+      ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt"));
+      ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt"));
+    }
+  } else {
+    auto pkg_path = GetPackageRoot(pkgid, uid);
+    ASSERT_TRUE(TouchFile(pkg_path / "data" / "file1.txt"));
+    ASSERT_TRUE(TouchFile(pkg_path / "data" / "file2.txt"));
+  }
+}
+
+void RemoveAllRecoveryFiles(const std::string& prefix, uid_t uid) {
+  bf::path root_path = ci::GetRootAppPath(false, uid);
+  if (!bf::exists(root_path))
+    return;
+  for (auto& dir_entry : boost::make_iterator_range(
+      bf::directory_iterator(root_path), bf::directory_iterator())) {
+    if (bf::is_regular_file(dir_entry)) {
+      if (dir_entry.path().string().find(prefix) != std::string::npos) {
+        bs::error_code error;
+        bf::remove(dir_entry.path(), error);
+        if (error)
+          LOG(ERROR) << "Failed to remove " << dir_entry.path()
+                     << ": " << error.message();
+      }
+    }
+  }
+}
+
+bf::path FindRecoveryFile(const std::string& prefix, uid_t uid) {
+  bf::path root_path = ci::GetRootAppPath(false, uid);
+  for (auto& dir_entry : boost::make_iterator_range(
+      bf::directory_iterator(root_path), bf::directory_iterator())) {
+    if (bf::is_regular_file(dir_entry)) {
+      if (dir_entry.path().string().find(prefix) != std::string::npos) {
+        return dir_entry.path();
+      }
+    }
+  }
+  return {};
+}
+
+bf::path GetPackageRoot(const std::string& pkgid, uid_t uid) {
+  bf::path root_path = ci::GetRootAppPath(false, uid);
+  return root_path / pkgid;
+}
+
+bool ValidateFileContentInPackage(const std::string& pkgid,
+                                  const std::string& relative,
+                                  const std::string& expected,
+                                  const TestParameters& params) {
+  bf::path file_path = ci::GetRootAppPath(params.is_readonly,
+                                          params.test_user.uid);
+  file_path = file_path / pkgid / relative;
+  if (!bf::exists(file_path)) {
+    LOG(ERROR) << file_path << " doesn't exist";
+    return false;
+  }
+  FILE* handle = fopen(file_path.c_str(), "r");
+  if (!handle) {
+    LOG(ERROR) << file_path << " cannot be open";
+    return false;
+  }
+  std::string content;
+  std::array<char, 200> buffer;
+  while (fgets(buffer.data(), buffer.size(), handle)) {
+    content += buffer.data();
+  }
+  fclose(handle);
+  return content == expected;
+}
+
+static bool ValidatePackageRWFS(const std::string& pkgid, uid_t uid) {
+  bf::path root_path = ci::GetRootAppPath(false, uid);
+  bf::path package_path = root_path / pkgid;
+  bf::path data_path = package_path / rwDirectories[DATA];
+  bf::path cache_path = package_path / rwDirectories[CACHE];
+  bf::path shared_data_path = package_path / rwDirectories[SHARED_DATA];
+
+  EXTENDED_ASSERT_TRUE(bf::exists(data_path));
+  EXTENDED_ASSERT_TRUE(bf::exists(cache_path));
+
+  struct stat stats;
+  stat(data_path.c_str(), &stats);
+  // gid of RW dirs should be system_share
+  boost::optional<gid_t> system_share =
+      ci::GetGidByGroupName(kSystemShareGroupName);
+  EXTENDED_ASSERT_EQ(uid, stats.st_uid);
+  EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
+  if (bf::exists(shared_data_path)) {
+    stat(shared_data_path.c_str(), &stats);
+    EXTENDED_ASSERT_EQ(uid, stats.st_uid);
+    EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
+  }
+
+  stat(cache_path.c_str(), &stats);
+  EXTENDED_ASSERT_EQ(uid, stats.st_uid);
+  EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
+  return true;
+}
+
+static bool ValidatePackageFS(const std::string& pkgid,
+                              const std::vector<std::string>& appids,
+                              const TestParameters& params) {
+  bf::path root_path = ci::GetRootAppPath(params.is_readonly,
+                                          params.test_user.uid);
+  bf::path package_path = root_path / pkgid;
+  bf::path shared_path = package_path / "shared";
+  EXTENDED_ASSERT_TRUE(bf::exists(root_path));
+  EXTENDED_ASSERT_TRUE(bf::exists(package_path));
+  EXTENDED_ASSERT_TRUE(bf::exists(shared_path));
+
+  bf::path manifest_path =
+      bf::path(getUserManifestPath(params.test_user.uid,
+          params.is_readonly)) / (pkgid + ".xml");
+  EXTENDED_ASSERT_TRUE(bf::exists(manifest_path));
+
+  for (auto& appid : appids) {
+    bf::path binary_path = package_path / "bin" / appid;
+    EXTENDED_ASSERT_TRUE(bf::exists(binary_path));
+  }
+
+  if (params.pkg_type == PackageType::WGT ||
+      params.pkg_type == PackageType::HYBRID) {
+    bf::path widget_root_path = package_path / "res" / "wgt";
+    bf::path config_path = widget_root_path / "config.xml";
+    EXTENDED_ASSERT_TRUE(bf::exists(widget_root_path));
+    EXTENDED_ASSERT_TRUE(bf::exists(config_path));
+
+    bf::path private_tmp_path = package_path / "tmp";
+    EXTENDED_ASSERT_TRUE(bf::exists(private_tmp_path));
+  }
+
+  // backups should not exist
+  bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
+  bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
+  EXTENDED_ASSERT_FALSE(bf::exists(package_backup));
+  EXTENDED_ASSERT_FALSE(bf::exists(manifest_backup));
+
+  for (bf::recursive_directory_iterator iter(package_path);
+      iter != bf::recursive_directory_iterator(); ++iter) {
+    if (bf::is_symlink(symlink_status(iter->path())))
+      continue;
+    bool is_rw_dir = false;
+    for (const auto rw_dir : rwDirectories) {
+      bf::path rw_dir_path = rw_dir;
+      is_rw_dir |= ci::MakeRelativePath(iter->path(), package_path)
+          == rw_dir_path;
+    }
+    if (is_rw_dir || iter->path().filename() == ".mmc") {
+      iter.no_push();
+      continue;
+    }
+    struct stat stats;
+    stat(iter->path().c_str(), &stats);
+    EXTENDED_ASSERT_EQ(params.test_user.uid, stats.st_uid);
+    EXTENDED_ASSERT_EQ(params.test_user.gid, stats.st_gid);
+  }
+  return true;
+}
+
+bool ValidatePackage(const std::string& pkgid,
+    const std::vector<std::string>& appids, const TestParameters& params) {
+  ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid);
+  EXTENDED_ASSERT_TRUE(pkg_query.IsPackageInstalled(
+      ci::GetRequestMode(params.test_user.uid)));
+  EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, appids, params));
+  if (params.test_user.uid == kGlobalUserUid) {
+    ci::UserList list = ci::GetUserList();
+    for (auto& l : list)
+      EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, std::get<0>(l)));
+  } else {
+    EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, params.test_user.uid));
+  }
+  return true;
+}
+
+bool ValidateDataFiles(const std::string& pkgid, uid_t uid) {
+  if (uid == kGlobalUserUid) {
+    ci::UserList list = ci::GetUserList();
+    for (auto l : list) {
+      auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
+      EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
+      EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
+    }
+  } else {
+    auto pkg_path = GetPackageRoot(pkgid, uid);
+    EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file1.txt"));
+    EXTENDED_ASSERT_TRUE(bf::exists(pkg_path / "data" / "file2.txt"));
+  }
+  return true;
+}
+
+static bool ValidateExternalPackageFS(const std::string& pkgid,
+                                      const std::vector<std::string>& appids,
+                                      const TestParameters& params) {
+  EXTENDED_ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(),
+      params.test_user.uid), 0);
+  bf::path root_path = ci::GetRootAppPath(false, params.test_user.uid);
+  if (params.pkg_type == PackageType::TPK) {
+    EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "bin"));
+    EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "lib"));
+  }
+  EXTENDED_ASSERT_TRUE(bf::exists(root_path / pkgid / ".mmc" / "res"));
+  EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, appids, params));
+  EXTENDED_ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(),
+      params.test_user.uid), 0);
+  return true;
+}
+
+bool ValidateExternalPackage(const std::string& pkgid,
+    const std::vector<std::string>& appids, const TestParameters& params) {
+  ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid);
+  std::string storage = pkg_query.StorageForPkgId();
+  bf::path ext_mount_path = ci::GetExternalCardPath();
+  if (bf::is_empty(ext_mount_path)) {
+    LOG(INFO) << "Sdcard not exists!";
+    EXTENDED_ASSERT_EQ(storage, "installed_internal");
+  } else {
+    EXTENDED_ASSERT_EQ(storage, "installed_external");
+  }
+  EXTENDED_ASSERT_TRUE(ValidateExternalPackageFS(pkgid, appids, params));
+  return true;
+}
+
+bool ValidateExtendedPackage(const std::string& pkgid,
+    const std::vector<std::string>& appids, const TestParameters& params) {
+  ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid);
+  std::string storage = pkg_query.StorageForPkgId();
+  bf::path extended_path =
+      bf::path(ci::GetExtendedRootAppPath(params.test_user.uid)) / pkgid;
+  if (!bf::exists(extended_path)) {
+    LOG(INFO) << "Extended storage not exists!";
+    EXTENDED_ASSERT_EQ(storage, "installed_internal");
+  } else {
+    EXTENDED_ASSERT_EQ(storage, "installed_extended");
+  }
+  EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, appids, params));
+  return true;
+}
+
+static bool PackageCheckCleanup(const std::string& pkgid,
+    const TestParameters& params) {
+  bf::path root_path = ci::GetRootAppPath(params.is_readonly,
+                                          params.test_user.uid);
+  bf::path package_path = root_path / pkgid;
+  EXTENDED_ASSERT_FALSE(bf::exists(package_path));
+
+  bf::path manifest_path = bf::path(getUserManifestPath(params.test_user.uid,
+      params.is_readonly)) / (pkgid + ".xml");
+  EXTENDED_ASSERT_FALSE(bf::exists(manifest_path));
+
+  // backups should not exist
+  bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
+  bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
+  EXTENDED_ASSERT_FALSE(bf::exists(package_backup));
+  EXTENDED_ASSERT_FALSE(bf::exists(manifest_backup));
+  return true;
+}
+
+bool CheckPackageNonExistance(const std::string& pkgid,
+                              const TestParameters& params) {
+  ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid);
+  EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
+      ci::GetRequestMode(params.test_user.uid)));
+  EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
+  if (params.test_user.uid == kGlobalUserUid) {
+    bf::path skel_path(kSkelDir);
+    EXTENDED_ASSERT_FALSE(bf::exists(skel_path / pkgid));
+    ci::UserList list = ci::GetUserList();
+    for (auto& l : list) {
+      bf::path root_path = ci::GetRootAppPath(false, std::get<0>(l));
+      bf::path package_path = root_path / pkgid;
+      EXTENDED_ASSERT_FALSE(bf::exists(package_path));
+    }
+  }
+  return true;
+}
+
+bool CheckAvailableExternalPath() {
+  bf::path ext_mount_path = ci::GetExternalCardPath();
+  LOG(DEBUG) << "ext_mount_path :" << ext_mount_path;
+  if (ext_mount_path.empty()) {
+    LOG(ERROR) << "Sdcard not exists!";
+    return false;
+  }
+  return true;
+}
+
+bool CheckAvailableExtendedPath() {
+  bf::path extended_path = bf::path(tzplatform_getenv(TZ_SYS_EXTENDEDSD));
+  LOG(DEBUG) << "extended_path :" << extended_path;
+  // TODO(jeremy.jang): It should be checked by libstorage API.
+  if (!bf::exists(extended_path)) {
+    LOG(ERROR) << "Extended storage not exists!";
+    return false;
+  }
+  return true;
+}
+
+bool CheckPackageReadonlyNonExistance(const std::string& pkgid,
+                                      const TestParameters& params) {
+  ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid);
+  EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
+      ci::GetRequestMode(params.test_user.uid)));
+  EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
+  return true;
+}
+
+void BackendInterface::TestRollbackAfterEachStep(int argc, const char* argv[],
+    std::function<bool()> validator) const {
+  TestPkgmgrInstaller pkgmgr_installer;
+  std::unique_ptr<ci::AppQueryInterface> query_interface =
+      CreateQueryInterface();
+  auto pkgmgr =
+      ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
+                                  &pkgmgr_installer,
+                                  query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return;
+  }
+  auto backend = CreateInstaller(pkgmgr);
+  int i;
+  for (i = backend->StepCount() - 1; i >= 0; i--) {
+    backend->AddStepAtIndex<ci::configuration::StepFail>(i);
+    LOG(DEBUG) << "StepFail is inserted at: " << i;
+    ASSERT_EQ(ci::AppInstaller::Result::ERROR, backend->Run());
+    if (!validator())
+      break;
+  }
+  ASSERT_EQ(-1, i);
+}
+
+void BackendInterface::CrashAfterEachStep(std::vector<std::string>* args,
+    std::function<bool(int iter)> validator, PackageType type) const {
+  std::unique_ptr<const char*[]> argv(new const char*[args->size()]);
+  for (size_t i = 0; i < args->size(); ++i) {
+    argv[i] = args->at(i).c_str();
+  }
+  TestPkgmgrInstaller pkgmgr_installer;
+  auto query_interface = CreateQueryInterface();
+  auto pkgmgr =
+      ci::PkgMgrInterface::Create(args->size(), const_cast<char**>(argv.get()),
+                                  &pkgmgr_installer,
+                                  query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return;
+  }
+  auto backend = CreateInstaller(pkgmgr);
+  int stepCount = backend->StepCount();
+
+  args->push_back("-idx");
+  args->push_back(std::to_string(stepCount));
+  int i;
+  std::string prefix = (type == PackageType::TPK) ? "tpk" : "wgt";
+  for (i = 0; i < stepCount; i++) {
+    ci::Subprocess backend_crash(
+        "/usr/bin/" + prefix + "-backend-ut/smoke-test-helper");
+    args->back() = std::to_string(i);
+    backend_crash.Run(*args);
+    ASSERT_NE(backend_crash.Wait(), 0);
+    if (!validator(i))
+      break;
+  }
+  ASSERT_EQ(stepCount, i);
+}
+
+BackendInterface::CommandResult BackendInterface::RunInstallerWithPkgrmgr(
+    ci::PkgMgrPtr pkgmgr) const {
+  std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
+  switch (mode_) {
+  case RequestResult::FAIL:
+    installer->AddStep<ci::configuration::StepFail>();
+    break;
+  default:
+    break;
+  }
+  return installer->Run();
+}
+
+BackendInterface::CommandResult BackendInterface::CallBackend(int argc,
+    const char* argv[]) const {
+  TestPkgmgrInstaller pkgmgr_installer;
+  auto query_interface = CreateQueryInterface();
+  auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
+      &pkgmgr_installer, query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return BackendInterface::CommandResult::UNKNOWN;
+  }
+  return RunInstallerWithPkgrmgr(pkgmgr);
+}
+
+BackendInterface::CommandResult BackendInterface::Install(
+    const bf::path& path) const {
+  const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::InstallPreload(
+    const bf::path& path) const {
+  const char* argv[] = {"", "-i", path.c_str(), "--preload"};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::InstallWithStorage(
+    const bf::path& path, StorageType type) const {
+  int default_storage = 0;
+  int storage = 0;
+  switch (type) {
+    case StorageType::EXTERNAL:
+      storage = 1;
+      break;
+    case StorageType::EXTENDED:
+      storage = 2;
+      break;
+    default:
+      LOG(ERROR) << "Unknown storage type";
+      break;
+  }
+  vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
+      &default_storage);
+  vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT, storage);
+
+  const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
+  BackendInterface::CommandResult result = CallBackend(SIZEOFARRAY(argv), argv);
+
+  vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
+      default_storage);
+  return result;
+}
+
+BackendInterface::CommandResult BackendInterface::MigrateLegacyExternalImage(
+    const std::string& pkgid,
+    const bf::path& path,
+    const bf::path& legacy_path) const {
+  if (InstallWithStorage(path, StorageType::EXTERNAL) !=
+      BackendInterface::CommandResult::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot perform Migrate";
+    return BackendInterface::CommandResult::ERROR;
+  }
+
+  bf::path ext_mount_path = ci::GetExternalCardPath();
+  if (bf::is_empty(ext_mount_path)) {
+    LOG(ERROR) << "Sdcard not exists!";
+    return BackendInterface::CommandResult::ERROR;
+  }
+  bf::path app2sd_path = ext_mount_path / "app2sd";
+
+  char* image_name = app2ext_usr_getname_image(pkgid.c_str(),
+                     kGlobalUserUid);
+  if (!image_name) {
+    LOG(ERROR) << "Failed to get external image name";
+    return BackendInterface::CommandResult::ERROR;
+  }
+  bf::path org_image = app2sd_path / image_name;
+  free(image_name);
+
+  bs::error_code error;
+  bf::remove(org_image, error);
+  if (error) {
+    LOG(ERROR) << "Failed to remove org image";
+    return BackendInterface::CommandResult::ERROR;
+  }
+
+  bf::path db_path = tzplatform_getenv(TZ_SYS_DB);
+  bf::path app2sd_db = db_path / ".app2sd.db";
+  bf::path app2sd_db_journal = db_path / ".app2sd.db-journal";
+  bf::remove(app2sd_db, error);
+  if (error) {
+    LOG(ERROR) << "Failed to remove app2sd db";
+    return BackendInterface::CommandResult::ERROR;
+  }
+  bf::remove(app2sd_db_journal, error);
+  if (error) {
+    LOG(ERROR) << "Failed to remove app2sd journal db";
+    return BackendInterface::CommandResult::ERROR;
+  }
+
+  bf::path app2sd_migrate_db = legacy_path / kMigrateTestDBName;
+  if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) {
+    LOG(ERROR) << "Failed to copy test db";
+    return BackendInterface::CommandResult::ERROR;
+  }
+
+  bf::path legacy_src = legacy_path / pkgid;
+  bf::path legacy_dst = app2sd_path / pkgid;
+  if (!ci::CopyFile(legacy_src, legacy_dst)) {
+    LOG(ERROR) << "Failed to copy test image";
+    return BackendInterface::CommandResult::ERROR;
+  }
+  const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(),
+                       "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::RDSUpdate(
+    const bf::path& path,
+    const std::string& pkgid) const {
+  RequestResult tmp_mode = mode_;
+  RequestResult &original_mode = const_cast<RequestResult&>(mode_);
+  original_mode = RequestResult::NORMAL;
+  if (Install(path) != BackendInterface::CommandResult::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot perform RDS";
+    return BackendInterface::CommandResult::UNKNOWN;
+  }
+  const char* argv[] = {"", "-r", pkgid.c_str(), "-u",
+                        uid_str_.c_str()};
+  original_mode = tmp_mode;
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::EnablePackage(
+    const std::string& pkgid) const {
+  const char* argv[] = {"", "-A", pkgid.c_str(), "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::DisablePackage(
+    const std::string& pkgid) const {
+  const char* argv[] = {"", "-D", pkgid.c_str(), "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::Recover(
+    const bf::path& recovery_file) const {
+  const char* argv[] = {"", "-b", recovery_file.c_str(), "-u",
+      uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::ManifestDirectInstall(
+    const std::string& pkgid) const {
+  const char* argv[] = {"", "-y", pkgid.c_str(), "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::Uninstall(
+    const std::string& pkgid) const {
+  const char* argv[] = {"", "-d", pkgid.c_str(), "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::UninstallPreload(
+    const std::string& pkgid) const {
+  const char* argv[] = {"", "-d", pkgid.c_str(), "--preload",
+      "--force-remove"};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::InstallSuccess(
+    const bf::path& path) const {
+  RequestResult tmp_mode = mode_;
+  RequestResult &original_mode = const_cast<RequestResult&>(mode_);
+  original_mode = RequestResult::NORMAL;
+  if (Install(path) != BackendInterface::CommandResult::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot update";
+    return BackendInterface::CommandResult::UNKNOWN;
+  }
+  original_mode = tmp_mode;
+  return BackendInterface::CommandResult::OK;
+}
+
+BackendInterface::CommandResult BackendInterface::InstallPreloadSuccess(
+    const bf::path& path) const {
+  RequestResult tmp_mode = mode_;
+  RequestResult &original_mode = const_cast<RequestResult&>(mode_);
+  original_mode = RequestResult::NORMAL;
+  if (InstallPreload(path) != BackendInterface::CommandResult::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot update";
+    return BackendInterface::CommandResult::UNKNOWN;
+  }
+  original_mode = tmp_mode;
+  return BackendInterface::CommandResult::OK;
+}
+
+BackendInterface::CommandResult BackendInterface::MountInstall(
+    const bf::path& path) const {
+  const char* argv[] = {"", "-w", path.c_str(), "-u", uid_str_.c_str()};
+  return CallBackend(SIZEOFARRAY(argv), argv);
+}
+
+BackendInterface::CommandResult BackendInterface::MountInstallSuccess(
+    const bf::path& path) const {
+  RequestResult tmp_mode = mode_;
+  RequestResult &original_mode = const_cast<RequestResult&>(mode_);
+  original_mode = RequestResult::NORMAL;
+  if (MountInstall(path) != BackendInterface::CommandResult::OK) {
+    LOG(ERROR) << "Failed to mount-install application. Cannot mount-update";
+    return BackendInterface::CommandResult::UNKNOWN;
+  }
+  original_mode = tmp_mode;
+  return BackendInterface::CommandResult::OK;
+}
+
+static boost::filesystem::path GetTrashPath(
+    const boost::filesystem::path& path) {
+  return path.string() + ".trash";
+}
+
+bool BackupPath(const bf::path& path) {
+  bf::path trash_path = GetTrashPath(path);
+  if (bf::exists(trash_path)) {
+    LOG(ERROR) << trash_path << " exists. Please remove "
+               << trash_path << " manually!";
+    return false;
+  }
+  bf::path backup_path = path.string() + ".bck";
+  std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
+  bs::error_code error;
+  bf::remove_all(backup_path, error);
+  if (error)
+    LOG(ERROR) << "Remove failed: " << backup_path
+               << " (" << error.message() << ")";
+  if (bf::exists(path)) {
+    bf::rename(path, backup_path, error);
+    if (error) {
+      LOG(ERROR) << "Failed to setup test environment. Does some previous"
+                 << " test crashed? Path: "
+                 << backup_path << " should not exist.";
+      return false;
+    }
+    assert(!error);
+  }
+  return true;
+}
+
+bool RestorePath(const bf::path& path) {
+  bf::path backup_path = path.string() + ".bck";
+  std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
+  bs::error_code error;
+  bf::remove_all(path, error);
+  if (error) {
+    bf::path trash_path = GetTrashPath(path);
+    LOG(ERROR) << "Remove failed: " << path << " (" << error.message() << ")";
+    std::cout << "Moving " << path << " to " << trash_path << std::endl;
+    bf::rename(path, trash_path, error);
+    if (error)
+      LOG(ERROR) << "Failed to move " << path << " to " << trash_path
+                 << " (" << error.message() << ")";
+    else
+      LOG(ERROR) << trash_path << " should be removed manually!";
+  }
+  if (bf::exists(backup_path)) {
+    bf::rename(backup_path, path, error);
+    if (error) {
+      LOG(ERROR) << "Failed to restore backup path: " << backup_path
+                 << " (" << error.message() << ")";
+      return false;
+    }
+  }
+  return true;
+}
+
+std::vector<bf::path> SetupBackupDirectories(uid_t test_uid) {
+  std::vector<bf::path> entries;
+  bf::path db_dir = bf::path(tzplatform_getenv(TZ_SYS_DB));
+  if (test_uid != kGlobalUserUid)
+    db_dir = db_dir / "user" / std::to_string(test_uid);
+  for (auto e : kDBEntries) {
+    bf::path path = db_dir / e;
+    entries.emplace_back(path);
+  }
+
+  if (getuid() == 0) {
+    entries.emplace_back(kPreloadApps);
+    entries.emplace_back(kPreloadManifestDir);
+    entries.emplace_back(kPreloadIcons);
+  }
+
+  if (test_uid == kGlobalUserUid) {
+    entries.emplace_back(kSkelDir);
+    entries.emplace_back(kGlobalManifestDir);
+    ci::UserList list = ci::GetUserList();
+    for (auto l : list) {
+      bf::path apps = std::get<2>(l) / "apps_rw";
+      entries.emplace_back(apps);
+    }
+  } else {
+    tzplatform_set_user(test_uid);
+    bf::path approot = tzplatform_getenv(TZ_USER_APPROOT);
+    tzplatform_reset_user();
+    entries.emplace_back(approot);
+  }
+
+  bf::path apps_rw = ci::GetRootAppPath(false, test_uid);
+  entries.emplace_back(apps_rw);
+
+  return entries;
+}
+
+void UninstallAllAppsInDirectory(bf::path dir, bool is_preload,
+    BackendInterface* backend) {
+  if (bf::exists(dir)) {
+    for (auto& dir_entry : boost::make_iterator_range(
+        bf::directory_iterator(dir), bf::directory_iterator())) {
+      if (dir_entry.path().string().find("smoke") != std::string::npos &&
+          bf::is_directory(dir_entry)) {
+        std::string package = dir_entry.path().filename().string();
+        std::regex pkg_regex("smoke[a-zA-Z0-9]{5,}");
+        if (std::regex_match(package, pkg_regex)) {
+          BackendInterface::CommandResult result =
+              BackendInterface::CommandResult::OK;
+          if (is_preload)
+            result = backend->UninstallPreload(
+                dir_entry.path().filename().string());
+          else
+            result = backend->Uninstall(
+                dir_entry.path().filename().string());
+          if (result != BackendInterface::CommandResult::OK) {
+            LOG(ERROR) << "Cannot uninstall smoke test app: "
+                << dir_entry.path().filename().string();
+          }
+        }
+      }
+    }
+  }
+}
+
+void UninstallAllSmokeApps(ci::RequestMode request_mode, uid_t test_uid,
+    BackendInterface *backend) {
+  std::cout << "Uninstalling all smoke apps" << std::endl;
+  bf::path apps_rw = ci::GetRootAppPath(false, test_uid);
+  UninstallAllAppsInDirectory(apps_rw, false, backend);
+  if (getuid() == 0 && request_mode == ci::RequestMode::GLOBAL) {
+    bf::path root_path = kPreloadApps;
+    UninstallAllAppsInDirectory(root_path, true, backend);
+  }
+}
+
+int GetAppInstalledTime(const char* appid, uid_t uid) {
+  int ret = 0;
+  int installed_time = 0;
+  pkgmgrinfo_appinfo_h handle = NULL;
+  ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &handle);
+  if (ret != PMINFO_R_OK)
+    return -1;
+  ret = pkgmgrinfo_appinfo_get_installed_time(handle, &installed_time);
+  if (ret != PMINFO_R_OK) {
+    pkgmgrinfo_appinfo_destroy_appinfo(handle);
+    return -1;
+  }
+  pkgmgrinfo_appinfo_destroy_appinfo(handle);
+  return installed_time;
+}
+
+}  // namespace smoke_test
diff --git a/src/unit_tests/common/smoke_utils.h b/src/unit_tests/common/smoke_utils.h
new file mode 100644 (file)
index 0000000..db78547
--- /dev/null
@@ -0,0 +1,269 @@
+// Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef UNIT_TESTS_COMMON_SMOKE_UTILS_H_
+#define UNIT_TESTS_COMMON_SMOKE_UTILS_H_
+
+#include <pkgmgr-info.h>
+#include <signal.h>
+#include <unistd.h>
+#include <tzplatform_config.h>
+#include <vconf.h>
+#include <vconf-internal-keys.h>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/format.hpp>
+#include <boost/program_options.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-death-test.h>
+
+#include <manifest_parser/utils/version_number.h>
+
+#include <common/utils/subprocess.h>
+#include <common/step/configuration/step_fail.h>
+#include <common/utils/user_util.h>
+#include <common/utils/file_util.h>
+#include <common/request.h>
+#include <common/tzip_interface.h>
+#include <common/app_installer.h>
+#include <common/paths.h>
+
+#include <array>
+#include <cstdio>
+#include <cstdlib>
+#include <regex>
+#include <string>
+#include <vector>
+
+#define SIZEOFARRAY(ARR)                                                       \
+  sizeof(ARR) / sizeof(ARR[0])                                                 \
+
+#define EXTENDED_ASSERT_TRUE(expression) do {                                  \
+    bool tmp = expression;                                                     \
+    EXPECT_TRUE(tmp) << #expression << " is not true";                         \
+    if (!tmp)                                                                  \
+        return false;                                                          \
+} while (0);
+
+#define EXTENDED_ASSERT_FALSE(expression) do {                                 \
+    bool tmp = expression;                                                     \
+    EXPECT_FALSE(tmp) << #expression << " is not false";                       \
+    if (tmp)                                                                   \
+        return false;                                                          \
+} while (0);
+
+#define EXTENDED_ASSERT_EQ(expression, value) do {                             \
+    auto ret = expression;                                                     \
+    EXPECT_EQ(ret, value) << #expression << " is not equal to " << #value;     \
+    if (ret != value)                                                          \
+        return false;                                                          \
+} while (0);
+
+namespace smoke_test {
+
+extern const bf::path kSmokePackagesDirectory;
+extern const uid_t kGlobalUserUid;
+extern const uid_t kGlobalUserGid;
+extern const char kLegacyExtImageDir[];
+extern const std::string& kDefaultUserIdStr;
+
+enum class RequestResult {
+  NORMAL,
+  FAIL
+};
+
+enum class StorageType {
+  INTERNAL,
+  EXTERNAL,
+  EXTENDED
+};
+
+class ScopedTzipInterface {
+ public:
+  explicit ScopedTzipInterface(const std::string& pkgid, uid_t test_user)
+      : pkg_path_(boost::filesystem::path(
+          common_installer::GetRootAppPath(false, test_user)) / pkgid),
+        interface_(common_installer::GetMountLocation(pkg_path_)),
+        mounted_(true) {
+    interface_.MountZip(common_installer::GetZipPackageLocation(pkg_path_,
+                                                                pkgid));
+  }
+
+  void Release() {
+    if (mounted_) {
+      interface_.UnmountZip();
+      mounted_ = false;
+    }
+  }
+
+  ~ScopedTzipInterface() {
+    Release();
+  }
+
+ private:
+  boost::filesystem::path pkg_path_;
+  common_installer::TzipInterface interface_;
+  bool mounted_;
+};
+
+class TestPkgmgrInstaller : public common_installer::PkgmgrInstallerInterface {
+ public:
+  bool CreatePkgMgrInstaller(pkgmgr_installer** installer,
+                             common_installer::InstallationMode* mode) {
+    *installer = pkgmgr_installer_offline_new();
+    if (!*installer)
+      return false;
+    *mode = common_installer::InstallationMode::ONLINE;
+    return true;
+  }
+
+  bool ShouldCreateSignal() const {
+    return false;
+  }
+};
+
+enum class PackageType {
+  TPK,
+  WGT,
+  HYBRID
+};
+
+struct User {
+  uid_t uid = kGlobalUserUid;
+  gid_t gid = kGlobalUserGid;
+};
+
+struct TestParameters {
+  TestParameters(PackageType type, bool readonly) :
+      pkg_type(type), is_readonly(readonly) {}
+  TestParameters(const TestParameters& other) : pkg_type(other.pkg_type),
+      is_readonly(other.is_readonly), test_user{other.test_user} {}
+  PackageType pkg_type;
+  bool is_readonly;
+  User test_user;
+};
+
+
+common_installer::RequestMode ParseRequestMode(int argc,  char** argv);
+
+bool TouchFile(const boost::filesystem::path& path);
+
+void AddDataFiles(const std::string& pkgid, uid_t uid);
+
+bool AddTestUser(User* test_user);
+
+bool DeleteTestUser();
+
+void RemoveAllRecoveryFiles(const std::string& prefix, uid_t uid);
+
+boost::filesystem::path FindRecoveryFile(const std::string& prefix, uid_t uid);
+
+boost::filesystem::path GetPackageRoot(const std::string& pkgid, uid_t uid);
+
+bool ValidateFileContentInPackage(const std::string& pkgid,
+                                  const std::string& relative,
+                                  const std::string& expected,
+                                  const TestParameters& params);
+
+bool ValidatePackage(const std::string& pkgid,
+                     const std::vector<std::string>& appids,
+                     const TestParameters& params);
+
+bool ValidateDataFiles(const std::string& pkgid, uid_t uid);
+
+bool ValidateExternalPackage(const std::string& pkgid,
+                             const std::vector<std::string>& appids,
+                             const TestParameters& params);
+bool ValidateExtendedPackage(const std::string& pkgid,
+                             const std::vector<std::string>& appid,
+                             const TestParameters& params);
+
+bool CheckPackageNonExistance(const std::string& pkgid,
+                              const TestParameters& params);
+
+bool CheckPackageReadonlyNonExistance(const std::string& pkgid,
+                                      const TestParameters& params);
+
+bool TouchFile(const boost::filesystem::path& path);
+
+class BackendInterface {
+ public:
+  using CommandResult = common_installer::AppInstaller::Result;
+  explicit BackendInterface(std::string uid,
+      RequestResult mode = RequestResult::NORMAL)
+      : uid_str_(uid), mode_(mode) {}
+  virtual ~BackendInterface() {}
+
+  void TestRollbackAfterEachStep(int argc, const char* argv[],
+                                 std::function<bool()> validator) const;
+  void CrashAfterEachStep(std::vector<std::string>* args,
+                          std::function<bool(int iter)> validator,
+                          PackageType type) const;
+  CommandResult Install(const boost::filesystem::path& path) const;
+  CommandResult InstallPreload(const boost::filesystem::path& path) const;
+  CommandResult InstallWithStorage(const boost::filesystem::path& path,
+      StorageType type = StorageType::INTERNAL) const;
+  CommandResult InstallSuccess(const bf::path& path) const;
+  CommandResult InstallPreloadSuccess(
+      const boost::filesystem::path& path) const;
+
+  CommandResult Uninstall(const std::string& pkgid) const;
+  CommandResult UninstallPreload(const std::string& pkgid) const;
+
+  CommandResult EnablePackage(const std::string& pkgid) const;
+  CommandResult DisablePackage(const std::string& pkgid) const;
+
+  CommandResult MountInstall(const boost::filesystem::path& path) const;
+  CommandResult MountInstallSuccess(const bf::path& path) const;
+  CommandResult ManifestDirectInstall(const std::string& pkgid) const;
+
+  CommandResult MigrateLegacyExternalImage(const std::string& pkgid,
+      const boost::filesystem::path& path,
+      const boost::filesystem::path& legacy_path) const;
+
+  CommandResult RDSUpdate(const boost::filesystem::path& path,
+      const std::string& pkgid) const;
+
+  CommandResult Recover(const boost::filesystem::path& recovery_file) const;
+
+ protected:
+  CommandResult CallBackend(int argc, const char* argv[]) const;
+  using AppQueryInterfacePtr =
+      std::unique_ptr<common_installer::AppQueryInterface>;
+  using AppInstallerPtr = std::unique_ptr<common_installer::AppInstaller>;
+  std::string uid_str_;
+  RequestResult mode_;
+
+ private:
+  CommandResult RunInstallerWithPkgrmgr(
+      common_installer::PkgMgrPtr pkgmgr) const;
+  virtual AppQueryInterfacePtr CreateQueryInterface() const = 0;
+  virtual AppInstallerPtr CreateInstaller(
+      common_installer::PkgMgrPtr pkgmgr) const = 0;
+};
+
+bool CheckAvailableExternalPath();
+
+bool CheckAvailableExtendedPath();
+
+bool BackupPath(const boost::filesystem::path& path);
+
+bool RestorePath(const boost::filesystem::path& path);
+
+std::vector<boost::filesystem::path> SetupBackupDirectories(uid_t test_uid);
+
+void UninstallAllAppsInDirectory(boost::filesystem::path dir, bool is_preload,
+    BackendInterface* backend);
+
+void UninstallAllSmokeApps(common_installer::RequestMode request_mode,
+    uid_t test_uid, BackendInterface* backend);
+
+int GetAppInstalledTime(const char* appid, uid_t uid);
+
+}  // namespace smoke_test
+
+#endif  // UNIT_TESTS_COMMON_SMOKE_UTILS_H_