1 // Copyright (c) 2015 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.
5 #include <boost/filesystem/operations.hpp>
6 #include <boost/filesystem/path.hpp>
7 #include <boost/range/iterator_range.hpp>
8 #include <boost/system/error_code.hpp>
9 #include <common/backup_paths.h>
10 #include <common/pkgmgr_interface.h>
11 #include <common/pkgmgr_registration.h>
12 #include <common/request.h>
13 #include <common/step/step_fail.h>
14 #include <gtest/gtest.h>
15 #include <gtest/gtest-death-test.h>
16 #include <pkgmgr-info.h>
19 #include <tzplatform_config.h>
25 #include "wgt/wgt_app_query_interface.h"
26 #include "wgt/wgt_installer.h"
28 #define SIZEOFARRAY(ARR) \
29 sizeof(ARR) / sizeof(ARR[0]) \
31 namespace bf = boost::filesystem;
32 namespace bs = boost::system;
33 namespace ci = common_installer;
37 const char kApplicationDir[] = ".applications";
38 const char kApplicationDirBackup[] = ".applications.bck";
39 const char KUserAppsDir[] = "apps_rw";
40 const char KUserAppsDirBackup[] = "apps_rw.bck";
42 enum class RequestResult {
48 class StepCrash : public ci::Step {
52 ci::Step::Status process() override {
56 ci::Step::Status clean() override { return ci::Step::Status::OK; }
57 ci::Step::Status undo() override { return ci::Step::Status::OK; }
58 ci::Step::Status precheck() override { return ci::Step::Status::OK; }
61 void RemoveAllRecoveryFiles() {
62 bf::path root_path = ci::GetRootAppPath();
63 for (auto& dir_entry : boost::make_iterator_range(
64 bf::directory_iterator(root_path), bf::directory_iterator())) {
65 if (bf::is_regular_file(dir_entry)) {
66 if (dir_entry.path().string().find("/recovery") != std::string::npos) {
68 bf::remove(dir_entry.path(), error);
74 bf::path FindRecoveryFile() {
75 bf::path root_path = ci::GetRootAppPath();
76 for (auto& dir_entry : boost::make_iterator_range(
77 bf::directory_iterator(root_path), bf::directory_iterator())) {
78 if (bf::is_regular_file(dir_entry)) {
79 if (dir_entry.path().string().find("/recovery") != std::string::npos) {
80 return dir_entry.path();
87 bool ValidateFileContentInPackage(const std::string& pkgid,
88 const std::string& relative,
89 const std::string& expected) {
90 bf::path root_path = ci::GetRootAppPath();
91 bf::path file_path = root_path / pkgid / relative;
92 if (!bf::exists(file_path)) {
93 LOG(ERROR) << file_path << " doesn't exist";
96 FILE* handle = fopen(file_path.c_str(), "r");
98 LOG(ERROR) << file_path << " cannot be open";
102 std::array<char, 200> buffer;
103 while (fgets(buffer.data(), buffer.size(), handle)) {
104 content += buffer.data();
107 return content == expected;
110 void ValidatePackageFS(const std::string& pkgid, const std::string& appid) {
111 bf::path root_path = ci::GetRootAppPath();
112 bf::path package_path = root_path / pkgid;
113 bf::path binary_path = package_path / "bin" / appid;
114 bf::path data_path = package_path / "data";
115 bf::path shared_path = package_path / "shared";
116 bf::path cache_path = package_path / "cache";
117 ASSERT_TRUE(bf::exists(root_path));
118 ASSERT_TRUE(bf::exists(package_path));
119 ASSERT_TRUE(bf::exists(binary_path));
120 ASSERT_TRUE(bf::exists(data_path));
121 ASSERT_TRUE(bf::exists(shared_path));
122 ASSERT_TRUE(bf::exists(cache_path));
124 bf::path manifest_path =
125 bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
126 bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
127 ASSERT_TRUE(bf::exists(manifest_path));
128 ASSERT_TRUE(bf::exists(icon_path));
130 bf::path widget_root_path = package_path / "res" / "wgt";
131 bf::path config_path = widget_root_path / "config.xml";
132 ASSERT_TRUE(bf::exists(widget_root_path));
133 ASSERT_TRUE(bf::exists(config_path));
135 bf::path private_tmp_path = package_path / "tmp";
136 ASSERT_TRUE(bf::exists(private_tmp_path));
138 // backups should not exist
139 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
140 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
141 bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
142 ASSERT_FALSE(bf::exists(package_backup));
143 ASSERT_FALSE(bf::exists(manifest_backup));
144 ASSERT_FALSE(bf::exists(icon_backup));
147 void PackageCheckCleanup(const std::string& pkgid, const std::string& appid) {
148 bf::path root_path = ci::GetRootAppPath();
149 bf::path package_path = root_path / pkgid;
150 ASSERT_FALSE(bf::exists(package_path));
152 bf::path manifest_path =
153 bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
154 bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
155 ASSERT_FALSE(bf::exists(manifest_path));
156 ASSERT_FALSE(bf::exists(icon_path));
158 // backups should not exist
159 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
160 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
161 bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
162 ASSERT_FALSE(bf::exists(package_backup));
163 ASSERT_FALSE(bf::exists(manifest_backup));
164 ASSERT_FALSE(bf::exists(icon_backup));
167 void ValidatePackage(const std::string& pkgid, const std::string& appid) {
168 ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
169 ValidatePackageFS(pkgid, appid);
172 void CheckPackageNonExistance(const std::string& pkgid,
173 const std::string& appid) {
174 ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
175 PackageCheckCleanup(pkgid, appid);
178 std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
179 std::unique_ptr<ci::AppQueryInterface> query_interface(
180 new wgt::WgtAppQueryInterface());
181 return query_interface;
184 std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr) {
185 std::unique_ptr<ci::AppInstaller> installer(new wgt::WgtInstaller(pkgmgr));
189 ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
190 RequestResult mode) {
191 std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
193 case RequestResult::FAIL:
194 installer->AddStep<ci::configuration::StepFail>();
196 case RequestResult::CRASH:
197 installer->AddStep<StepCrash>();
201 return installer->Run();
204 ci::AppInstaller::Result Install(const bf::path& path,
205 RequestResult mode = RequestResult::NORMAL) {
206 const char* argv[] = {"", "-i", path.c_str()};
207 std::unique_ptr<ci::AppQueryInterface> query_interface =
208 CreateQueryInterface();
210 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
211 query_interface.get());
213 LOG(ERROR) << "Failed to initialize pkgmgr interface";
214 return ci::AppInstaller::Result::UNKNOWN;
216 return RunInstallerWithPkgrmgr(pkgmgr, mode);
219 ci::AppInstaller::Result Update(const bf::path& path_old,
220 const bf::path& path_new,
221 RequestResult mode = RequestResult::NORMAL) {
222 if (Install(path_old) != ci::AppInstaller::Result::OK) {
223 LOG(ERROR) << "Failed to install application. Cannot update";
224 return ci::AppInstaller::Result::UNKNOWN;
226 return Install(path_new, mode);
229 ci::AppInstaller::Result Uninstall(const std::string& pkgid,
230 RequestResult mode = RequestResult::NORMAL) {
231 const char* argv[] = {"", "-d", pkgid.c_str()};
232 std::unique_ptr<ci::AppQueryInterface> query_interface =
233 CreateQueryInterface();
235 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
236 query_interface.get());
238 LOG(ERROR) << "Failed to initialize pkgmgr interface";
239 return ci::AppInstaller::Result::UNKNOWN;
241 return RunInstallerWithPkgrmgr(pkgmgr, mode);
244 ci::AppInstaller::Result Reinstall(const bf::path& path,
245 const bf::path& delta_dir,
246 RequestResult mode = RequestResult::NORMAL) {
247 if (Install(path) != ci::AppInstaller::Result::OK) {
248 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
249 return ci::AppInstaller::Result::UNKNOWN;
251 const char* argv[] = {"", "-r", delta_dir.c_str()};
252 std::unique_ptr<ci::AppQueryInterface> query_interface =
253 CreateQueryInterface();
255 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
256 query_interface.get());
258 LOG(ERROR) << "Failed to initialize pkgmgr interface";
259 return ci::AppInstaller::Result::UNKNOWN;
261 return RunInstallerWithPkgrmgr(pkgmgr, mode);
264 ci::AppInstaller::Result DeltaInstall(const bf::path& path,
265 const bf::path& delta_package) {
266 if (Install(path) != ci::AppInstaller::Result::OK) {
267 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
268 return ci::AppInstaller::Result::UNKNOWN;
270 return Install(delta_package);
273 ci::AppInstaller::Result Recover(const bf::path& recovery_file,
274 RequestResult mode = RequestResult::NORMAL) {
275 const char* argv[] = {"", "-e", recovery_file.c_str()};
276 std::unique_ptr<ci::AppQueryInterface> query_interface =
277 CreateQueryInterface();
279 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
280 query_interface.get());
282 LOG(ERROR) << "Failed to initialize pkgmgr interface";
283 return ci::AppInstaller::Result::UNKNOWN;
285 return RunInstallerWithPkgrmgr(pkgmgr, mode);
290 namespace common_installer {
292 class SmokeEnvironment : public testing::Environment {
294 explicit SmokeEnvironment(const bf::path& home) : home_(home) {
296 void SetUp() override {
297 bs::error_code error;
298 bf::remove_all(home_ / kApplicationDirBackup, error);
299 bf::remove_all(home_ / KUserAppsDirBackup, error);
300 if (bf::exists(home_ / KUserAppsDir)) {
301 bf::rename(home_ / KUserAppsDir, home_ / KUserAppsDirBackup, error);
304 if (bf::exists(home_ / kApplicationDir)) {
305 bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
309 void TearDown() override {
310 bs::error_code error;
311 bf::remove_all(home_ / kApplicationDir, error);
312 bf::remove_all(home_ / KUserAppsDir, error);
313 if (bf::exists(home_ / KUserAppsDirBackup))
314 bf::rename(home_ / KUserAppsDirBackup, home_ / KUserAppsDir, error);
315 if (bf::exists(home_ / kApplicationDirBackup))
316 bf::rename(home_ / kApplicationDirBackup, home_ / kApplicationDir, error);
323 class SmokeTest : public testing::Test {
326 TEST_F(SmokeTest, InstallationMode) {
327 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode.wgt"; // NOLINT
328 std::string pkgid = "smokeapp03";
329 std::string appid = "smokeapp03.InstallationMode";
330 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
331 ValidatePackage(pkgid, appid);
334 TEST_F(SmokeTest, UpdateMode) {
335 bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode.wgt"; // NOLINT
336 bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_2.wgt"; // NOLINT
337 std::string pkgid = "smokeapp04";
338 std::string appid = "smokeapp04.UpdateMode";
339 ASSERT_EQ(Update(path_old, path_new), ci::AppInstaller::Result::OK);
340 ValidatePackage(pkgid, appid);
342 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "2\n"));
345 TEST_F(SmokeTest, DeinstallationMode) {
346 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeinstallationMode.wgt"; // NOLINT
347 std::string pkgid = "smokeapp05";
348 std::string appid = "smokeapp05.DeinstallationMode";
349 ASSERT_EQ(Install(path),
350 ci::AppInstaller::Result::OK);
351 ASSERT_EQ(Uninstall(pkgid), ci::AppInstaller::Result::OK);
352 CheckPackageNonExistance(pkgid, appid);
355 TEST_F(SmokeTest, RDSMode) {
356 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/RDSMode.wgt"; // NOLINT
357 std::string delta_directory = "/usr/share/app-installers-ut/test_samples/smoke/delta_dir/"; // NOLINT
358 std::string pkgid = "smokeapp11";
359 std::string appid = "smokeapp11.RDSMode";
360 ASSERT_EQ(Reinstall(path, delta_directory),
361 ci::AppInstaller::Result::OK);
362 ValidatePackage(pkgid, appid);
364 // Check delta modifications
365 bf::path root_path = ci::GetRootAppPath();
366 ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
367 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
368 ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "2\n");
371 TEST_F(SmokeTest, DeltaMode) {
372 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeltaMode.wgt"; // NOLINT
373 std::string delta_package = "/usr/share/app-installers-ut/test_samples/smoke/DeltaMode.delta"; // NOLINT
374 std::string pkgid = "smokeapp17";
375 std::string appid = "smokeapp17.DeltaMode";
376 ASSERT_EQ(DeltaInstall(path, delta_package),
377 ci::AppInstaller::Result::OK);
378 ValidatePackage(pkgid, appid);
380 // Check delta modifications
381 bf::path root_path = ci::GetRootAppPath();
382 ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
383 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
384 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "css" / "style.css")); // NOLINT
385 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "images" / "tizen_32.png")); // NOLINT
386 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "js" / "main.js"));
387 ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "version 2\n");
390 TEST_F(SmokeTest, RecoveryMode_ForInstallation) {
391 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_ForInstallation.wgt"; // NOLINT
392 ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
394 std::string pkgid = "smokeapp09";
395 std::string appid = "smokeapp09.RecoveryModeForInstallation";
396 bf::path recovery_file = FindRecoveryFile();
397 ASSERT_FALSE(recovery_file.empty());
398 ASSERT_EQ(Recover(recovery_file),
399 ci::AppInstaller::Result::OK);
400 CheckPackageNonExistance(pkgid, appid);
403 TEST_F(SmokeTest, RecoveryMode_ForUpdate) {
404 bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_ForUpdate.wgt"; // NOLINT
405 bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_ForUpdate_2.wgt"; // NOLINT
406 RemoveAllRecoveryFiles();
407 ASSERT_DEATH(Update(path_old, path_new, RequestResult::CRASH), ".*");
409 std::string pkgid = "smokeapp10";
410 std::string appid = "smokeapp10.RecoveryModeForUpdate";
411 bf::path recovery_file = FindRecoveryFile();
412 ASSERT_FALSE(recovery_file.empty());
413 ASSERT_EQ(Recover(recovery_file),
414 ci::AppInstaller::Result::OK);
415 ValidatePackage(pkgid, appid);
417 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
420 TEST_F(SmokeTest, InstallationMode_GoodSignature) {
421 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_GoodSignature.wgt"; // NOLINT
422 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
425 TEST_F(SmokeTest, InstallationMode_WrongSignature) {
426 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_WrongSignature.wgt"; // NOLINT
427 ASSERT_EQ(Install(path), ci::AppInstaller::Result::ERROR);
430 TEST_F(SmokeTest, InstallationMode_Rollback) {
431 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_Rollback.wgt"; // NOLINT
432 std::string pkgid = "smokeapp06";
433 std::string appid = "smokeapp06.InstallationModeRollback";
434 ASSERT_EQ(Install(path, RequestResult::FAIL),
435 ci::AppInstaller::Result::ERROR);
436 CheckPackageNonExistance(pkgid, appid);
439 TEST_F(SmokeTest, UpdateMode_Rollback) {
440 bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_Rollback.wgt"; // NOLINT
441 bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_Rollback_2.wgt"; // NOLINT
442 std::string pkgid = "smokeapp07";
443 std::string appid = "smokeapp07.UpdateModeRollback";
444 ASSERT_EQ(Update(path_old, path_new, RequestResult::FAIL),
445 ci::AppInstaller::Result::ERROR);
446 ValidatePackage(pkgid, appid);
448 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
451 TEST_F(SmokeTest, DeinstallationMode_Rollback) {
452 bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeinstallationMode_Rollback.wgt"; // NOLINT
453 std::string pkgid = "smokeapp08";
454 std::string appid = "smokeapp08.DeinstallationModeRollback";
455 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
456 ASSERT_EQ(Uninstall(pkgid, RequestResult::FAIL),
457 ci::AppInstaller::Result::ERROR);
458 ValidatePackage(pkgid, appid);
461 } // namespace common_installer
463 int main(int argc, char** argv) {
464 testing::InitGoogleTest(&argc, argv);
465 const char* directory = getenv("HOME");
467 LOG(ERROR) << "Cannot get $HOME value";
470 testing::AddGlobalTestEnvironment(
471 new common_installer::SmokeEnvironment(directory));
472 return RUN_ALL_TESTS();