--- /dev/null
+// Copyright (c) 2020 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 <common/dependency_checker.h>
+#include <common/pkgmgr_interface.h>
+#include <unit_tests/common/smoke_utils.h>
+
+#include <gtest/gtest.h>
+
+#include "smoke_test/smoke_utils.h"
+
+namespace ci = common_installer;
+
+namespace smoke_test {
+
+class SmokeEnvironment : public testing::Environment {
+ public:
+ explicit SmokeEnvironment(ci::RequestMode mode) : request_mode_(mode) { }
+
+ void SetUp() override {
+ if (request_mode_ == ci::RequestMode::USER) {
+ ASSERT_TRUE(AddTestUser(&test_user));
+ }
+ backups_ = SetupBackupDirectories(test_user.uid);
+ for (auto& path : backups_)
+ ASSERT_TRUE(BackupPath(path));
+ }
+ void TearDown() override {
+ ASSERT_TRUE(request_mode_ == ci::RequestMode::GLOBAL ||
+ (request_mode_ == ci::RequestMode::USER &&
+ kGlobalUserUid != test_user.uid));
+ for (auto& path : backups_)
+ ASSERT_TRUE(RestorePath(path));
+ if (request_mode_ == ci::RequestMode::USER) {
+ ASSERT_TRUE(DeleteTestUser());
+ }
+ }
+ User test_user;
+ ci::RequestMode request_mode_;
+
+ private:
+ std::vector<bf::path> backups_;
+};
+
+} // namespace smoke_test
+
+
+namespace {
+
+smoke_test::SmokeEnvironment *env = nullptr;
+void signalHandler(int signum) {
+ env->TearDown();
+ exit(signum);
+}
+
+} // namespace
+
+namespace smoke_test {
+
+ci::PkgMgrPtr CreatePkgmgrPtr(const std::vector<std::string>& args,
+ ci::PkgmgrInstallerInterface* pkgmgr_installer_interface) {
+ 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();
+ return ci::PkgMgrInterface::Create(
+ args.size(), const_cast<char**>(argv.get()), pkgmgr_installer_interface);
+}
+
+class DependencyValidator {
+ public:
+ using AppInstallerPtr = std::unique_ptr<ci::AppInstaller>;
+
+ explicit DependencyValidator(ci::PkgMgrPtr pkgmgr) : pkgmgr_(pkgmgr) {}
+
+ void AddDependencyInfo(std::string from, std::string to) {
+ dependency_list_.emplace_back(std::make_pair(from, to));
+ }
+
+ bool SortInstallers() {
+ ci::DependencyChecker dep_checker(pkgmgr_);
+ UnifiedSmokeInstallerFactory factory;
+ for (int i = 0; i < pkgmgr_->GetRequestInfoCount(); i++) {
+ std::unique_ptr<ci::AppInstaller> installer =
+ factory.CreateInstaller(i, pkgmgr_);
+ if (!installer) {
+ return false;
+ }
+ if (!dep_checker.AddInstaller(std::move(installer))) {
+ std::cout << dep_checker.GetErrorMessage() << std::endl;
+ return false;
+ }
+ }
+ installer_list_ = dep_checker.GetSortedAppInstallers();
+ if (installer_list_.size() == 0) {
+ std::cout << dep_checker.GetErrorMessage() << std::endl;
+ return false;
+ }
+ return true;
+ }
+
+ bool IsSatisfyDependency() {
+ std::list<std::string> request_info_list;
+ for (const AppInstallerPtr& installer : installer_list_) {
+ request_info_list.emplace_back(
+ pkgmgr_->GetRequestInfo(installer->GetIndex()));
+ }
+
+ std::map<std::string, int> list_dic;
+ for (const std::string& pkg : request_info_list)
+ list_dic.emplace(pkg, list_dic.size());
+
+ for (const auto& dependency_info : dependency_list_) {
+ std::string from = dependency_info.first;
+ std::string to = dependency_info.second;
+ if (list_dic.count(from) == 0 || list_dic.count(to) == 0) {
+ std::cout << "Package is not exist in list" << std::endl;
+ return false;
+ }
+ int order_from = list_dic.at(from);
+ int order_to = list_dic.at(to);
+ if (order_to < order_from) {
+ std::cout << "Dependency order is not met" << std::endl;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ ci::PkgMgrPtr pkgmgr_;
+ std::vector<std::pair<std::string, std::string>> dependency_list_;
+ std::list<AppInstallerPtr> installer_list_;
+};
+
+const bf::path kUnifiedSmokePackagesDirectory =
+ "/usr/share/unified-installer-ut/test_samples/smoke/";
+
+class DependencyCheckerTest : public testing::Test {
+ public:
+ using AppInstallerPtr = std::unique_ptr<ci::AppInstaller>;
+
+ DependencyCheckerTest()
+ : backend(BackendInterface::SmokeInstallerFactoryPtr(
+ new UnifiedSmokeInstallerFactory()),
+ std::to_string(env->test_user.uid)),
+ params({PackageType::TPK, false}) {
+ params.test_user.uid = env->test_user.uid;
+ params.test_user.gid = env->test_user.gid;
+ }
+ virtual ~DependencyCheckerTest() {}
+
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ BackendInterface::SmokeInstallerFactoryPtr factory(
+ new UnifiedSmokeInstallerFactory());
+ UnifiedBackendInterface backend(
+ std::move(factory), std::to_string(params.test_user.uid));
+ UninstallAllSmokeApps(env->request_mode_, params.test_user.uid, &backend);
+ }
+
+ protected:
+ UnifiedBackendInterface backend;
+ TestParameters params;
+};
+
+TEST_F(DependencyCheckerTest, CircularDependency) {
+ bf::path path1 = kUnifiedSmokePackagesDirectory / "smokedep01.tpk";
+ bf::path path2 = kUnifiedSmokePackagesDirectory / "smokedep02.tpk";
+ bf::path path3 = kUnifiedSmokePackagesDirectory / "smokedep03.tpk";
+
+ std::vector<std::string> pkgmgr_args =
+ {"", "-i", path1.string(), path2.string(), path3.string()};
+
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ validator.AddDependencyInfo(path1.string(), path2.string());
+ validator.AddDependencyInfo(path2.string(), path3.string());
+ validator.AddDependencyInfo(path3.string(), path1.string());
+
+ ASSERT_FALSE(validator.SortInstallers());
+}
+
+TEST_F(DependencyCheckerTest, SortInstallRequest) {
+ bf::path path4 = kUnifiedSmokePackagesDirectory / "smokedep04.tpk";
+ bf::path path5 = kUnifiedSmokePackagesDirectory / "smokedep05.tpk";
+ bf::path path6 = kUnifiedSmokePackagesDirectory / "smokedep06.tpk";
+ bf::path path7 = kUnifiedSmokePackagesDirectory / "smokedep07.tpk";
+ bf::path path8 = kUnifiedSmokePackagesDirectory / "smokedep08.tpk";
+
+ std::vector<std::string> pkgmgr_args = {"", "-i", path4.string(),
+ path5.string(), path6.string(), path7.string(), path8.string()};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ validator.AddDependencyInfo(path4.string(), path5.string());
+ validator.AddDependencyInfo(path4.string(), path8.string());
+ validator.AddDependencyInfo(path6.string(), path4.string());
+ validator.AddDependencyInfo(path6.string(), path7.string());
+ validator.AddDependencyInfo(path8.string(), path7.string());
+
+ ASSERT_TRUE(validator.SortInstallers());
+ ASSERT_TRUE(validator.IsSatisfyDependency());
+}
+
+TEST_F(DependencyCheckerTest, SortUninstallRequest) {
+ bf::path path4 = kUnifiedSmokePackagesDirectory / "smokedep04.tpk";
+ bf::path path5 = kUnifiedSmokePackagesDirectory / "smokedep05.tpk";
+ bf::path path6 = kUnifiedSmokePackagesDirectory / "smokedep06.tpk";
+ bf::path path7 = kUnifiedSmokePackagesDirectory / "smokedep07.tpk";
+ bf::path path8 = kUnifiedSmokePackagesDirectory / "smokedep08.tpk";
+
+ std::string pkg4 = "smokedep04";
+ std::string pkg5 = "smokedep05";
+ std::string pkg6 = "smokedep06";
+ std::string pkg7 = "smokedep07";
+ std::string pkg8 = "smokedep08";
+
+ std::vector<bf::path> install_args = {path4, path5, path6, path7, path8};
+ ASSERT_EQ(backend.Install(install_args), ci::AppInstaller::Result::OK);
+
+ std::vector<std::string> pkgmgr_args = {"", "-d", "smokedep04",
+ "smokedep05", "smokedep06", "smokedep07", "smokedep08"};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ validator.AddDependencyInfo(pkg4, pkg5);
+ validator.AddDependencyInfo(pkg4, pkg8);
+ validator.AddDependencyInfo(pkg6, pkg4);
+ validator.AddDependencyInfo(pkg6, pkg7);
+ validator.AddDependencyInfo(pkg8, pkg7);
+
+ ASSERT_TRUE(validator.SortInstallers());
+ ASSERT_TRUE(validator.IsSatisfyDependency());
+}
+
+TEST_F(DependencyCheckerTest, InvalidDependency_RequiredPkgNotExist) {
+ bf::path path9 = kUnifiedSmokePackagesDirectory / "smokedep09.tpk";
+
+ std::vector<std::string> pkgmgr_args = {"", "-i", path9.string()};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ ASSERT_FALSE(validator.SortInstallers());
+}
+
+TEST_F(DependencyCheckerTest, InvalidDependency_RequiredPkgVersionLow) {
+ bf::path path9 = kUnifiedSmokePackagesDirectory / "smokedep09.tpk";
+ bf::path path10 = kUnifiedSmokePackagesDirectory / "smokedep10-1.0.0.tpk";
+
+ ASSERT_EQ(backend.Install(path10), ci::AppInstaller::Result::OK);
+
+ std::vector<std::string> pkgmgr_args = {"", "-i", path9.string()};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ ASSERT_FALSE(validator.SortInstallers());
+}
+
+TEST_F(DependencyCheckerTest, InvalidDependency_RequiredPkgVersionDown_1) {
+ bf::path path9 = kUnifiedSmokePackagesDirectory / "smokedep09.tpk";
+ bf::path path10_1 = kUnifiedSmokePackagesDirectory / "smokedep10-1.0.0.tpk";
+ bf::path path10_2 = kUnifiedSmokePackagesDirectory / "smokedep10-2.0.0.tpk";
+
+ ASSERT_EQ(backend.Install(std::vector<bf::path>({path9, path10_2})),
+ ci::AppInstaller::Result::OK);
+
+ std::vector<std::string> pkgmgr_args = {"", "-i", path10_1.string()};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ ASSERT_FALSE(validator.SortInstallers());
+}
+
+TEST_F(DependencyCheckerTest, InvalidDependency_RequiredPkgVersionDown_2) {
+ bf::path path9 = kUnifiedSmokePackagesDirectory / "smokedep09.tpk";
+ bf::path path10_1 = kUnifiedSmokePackagesDirectory / "smokedep10-1.0.0.tpk";
+ bf::path path10_2 = kUnifiedSmokePackagesDirectory / "smokedep10-2.0.0.tpk";
+ std::string pkgid10 = "smokedep10";
+
+ ASSERT_EQ(backend.InstallPreload(path10_1), ci::AppInstaller::Result::OK);
+ ASSERT_EQ(backend.Install(std::vector<bf::path>({path9, path10_2})),
+ ci::AppInstaller::Result::OK);
+
+ std::vector<std::string> pkgmgr_args = {"", "-d", pkgid10};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ ASSERT_FALSE(validator.SortInstallers());
+}
+
+TEST_F(DependencyCheckerTest, InvalidDependency_RequiredPkgUninstall) {
+ bf::path path9 = kUnifiedSmokePackagesDirectory / "smokedep09.tpk";
+ bf::path path10_2 = kUnifiedSmokePackagesDirectory / "smokedep10-2.0.0.tpk";
+ std::string pkgid10 = "smokedep10";
+
+ ASSERT_EQ(backend.Install(std::vector<bf::path>({path9, path10_2})),
+ ci::AppInstaller::Result::OK);
+
+ std::vector<std::string> pkgmgr_args = {"", "-d", pkgid10};
+ TestPkgmgrInstaller pkgmgr_installer;
+ ci::PkgMgrPtr pkgmgr = CreatePkgmgrPtr(pkgmgr_args, &pkgmgr_installer);
+
+ ASSERT_EQ(pkgmgr->GetRequestInfoCount(), pkgmgr_args.size() - 2);
+
+ DependencyValidator validator(pkgmgr);
+ ASSERT_FALSE(validator.SortInstallers());
+}
+
+} // namespace smoke_test
+
+int main(int argc, char** argv) {
+ try {
+ ci::RequestMode request_mode = smoke_test::ParseRequestMode(argc, argv);
+ if (getuid() != 0 || request_mode != ci::RequestMode::GLOBAL) {
+ std::cout << "Skip tests for preload request" << std::endl;
+ ::testing::GTEST_FLAG(filter) = "SmokeTest.*";
+ }
+ testing::InitGoogleTest(&argc, argv);
+ ::env = static_cast<smoke_test::SmokeEnvironment*>(
+ testing::AddGlobalTestEnvironment(
+ new smoke_test::SmokeEnvironment(request_mode)));
+ signal(SIGINT, ::signalHandler);
+ signal(SIGSEGV, ::signalHandler);
+ return RUN_ALL_TESTS();
+ } catch (...) {
+ std::cout << "Exception occurred during testing" << std::endl;
+ return -1;
+ }
+}