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 bf::path kSmokePackagesDirectory =
38 "/usr/share/wgt-backend-ut/test_samples/smoke/";
40 const char kApplicationDir[] = ".applications";
41 const char kApplicationDirBackup[] = ".applications.bck";
42 const char KUserAppsDir[] = "apps_rw";
43 const char KUserAppsDirBackup[] = "apps_rw.bck";
45 enum class RequestResult {
51 class StepCrash : public ci::Step {
55 ci::Step::Status process() override {
59 ci::Step::Status clean() override { return ci::Step::Status::OK; }
60 ci::Step::Status undo() override { return ci::Step::Status::OK; }
61 ci::Step::Status precheck() override { return ci::Step::Status::OK; }
64 void RemoveAllRecoveryFiles() {
65 bf::path root_path = ci::GetRootAppPath();
66 if (!bf::exists(root_path))
68 for (auto& dir_entry : boost::make_iterator_range(
69 bf::directory_iterator(root_path), bf::directory_iterator())) {
70 if (bf::is_regular_file(dir_entry)) {
71 if (dir_entry.path().string().find("/recovery") != std::string::npos) {
73 bf::remove(dir_entry.path(), error);
79 bf::path FindRecoveryFile() {
80 bf::path root_path = ci::GetRootAppPath();
81 for (auto& dir_entry : boost::make_iterator_range(
82 bf::directory_iterator(root_path), bf::directory_iterator())) {
83 if (bf::is_regular_file(dir_entry)) {
84 if (dir_entry.path().string().find("/recovery") != std::string::npos) {
85 return dir_entry.path();
92 bool ValidateFileContentInPackage(const std::string& pkgid,
93 const std::string& relative,
94 const std::string& expected) {
95 bf::path root_path = ci::GetRootAppPath();
96 bf::path file_path = root_path / pkgid / relative;
97 if (!bf::exists(file_path)) {
98 LOG(ERROR) << file_path << " doesn't exist";
101 FILE* handle = fopen(file_path.c_str(), "r");
103 LOG(ERROR) << file_path << " cannot be open";
107 std::array<char, 200> buffer;
108 while (fgets(buffer.data(), buffer.size(), handle)) {
109 content += buffer.data();
112 return content == expected;
115 void ValidatePackageFS(const std::string& pkgid, const std::string& appid) {
116 bf::path root_path = ci::GetRootAppPath();
117 bf::path package_path = root_path / pkgid;
118 bf::path binary_path = package_path / "bin" / appid;
119 bf::path data_path = package_path / "data";
120 bf::path shared_path = package_path / "shared";
121 bf::path cache_path = package_path / "cache";
122 ASSERT_TRUE(bf::exists(root_path));
123 ASSERT_TRUE(bf::exists(package_path));
124 ASSERT_TRUE(bf::exists(binary_path));
125 ASSERT_TRUE(bf::exists(data_path));
126 ASSERT_TRUE(bf::exists(shared_path));
127 ASSERT_TRUE(bf::exists(cache_path));
129 bf::path manifest_path =
130 bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
131 bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
132 ASSERT_TRUE(bf::exists(manifest_path));
133 ASSERT_TRUE(bf::exists(icon_path));
135 bf::path widget_root_path = package_path / "res" / "wgt";
136 bf::path config_path = widget_root_path / "config.xml";
137 ASSERT_TRUE(bf::exists(widget_root_path));
138 ASSERT_TRUE(bf::exists(config_path));
140 bf::path private_tmp_path = package_path / "tmp";
141 ASSERT_TRUE(bf::exists(private_tmp_path));
143 // backups should not exist
144 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
145 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
146 bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
147 ASSERT_FALSE(bf::exists(package_backup));
148 ASSERT_FALSE(bf::exists(manifest_backup));
149 ASSERT_FALSE(bf::exists(icon_backup));
152 void PackageCheckCleanup(const std::string& pkgid, const std::string& appid) {
153 bf::path root_path = ci::GetRootAppPath();
154 bf::path package_path = root_path / pkgid;
155 ASSERT_FALSE(bf::exists(package_path));
157 bf::path manifest_path =
158 bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
159 bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
160 ASSERT_FALSE(bf::exists(manifest_path));
161 ASSERT_FALSE(bf::exists(icon_path));
163 // backups should not exist
164 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
165 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
166 bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
167 ASSERT_FALSE(bf::exists(package_backup));
168 ASSERT_FALSE(bf::exists(manifest_backup));
169 ASSERT_FALSE(bf::exists(icon_backup));
172 void ValidatePackage(const std::string& pkgid, const std::string& appid) {
173 ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
174 ValidatePackageFS(pkgid, appid);
177 void CheckPackageNonExistance(const std::string& pkgid,
178 const std::string& appid) {
179 ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
180 PackageCheckCleanup(pkgid, appid);
183 std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
184 std::unique_ptr<ci::AppQueryInterface> query_interface(
185 new wgt::WgtAppQueryInterface());
186 return query_interface;
189 std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr) {
190 std::unique_ptr<ci::AppInstaller> installer(new wgt::WgtInstaller(pkgmgr));
194 ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
195 RequestResult mode) {
196 std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
198 case RequestResult::FAIL:
199 installer->AddStep<ci::configuration::StepFail>();
201 case RequestResult::CRASH:
202 installer->AddStep<StepCrash>();
206 return installer->Run();
209 ci::AppInstaller::Result Install(const bf::path& path,
210 RequestResult mode = RequestResult::NORMAL) {
211 const char* argv[] = {"", "-i", path.c_str()};
212 std::unique_ptr<ci::AppQueryInterface> query_interface =
213 CreateQueryInterface();
215 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
216 query_interface.get());
218 LOG(ERROR) << "Failed to initialize pkgmgr interface";
219 return ci::AppInstaller::Result::UNKNOWN;
221 return RunInstallerWithPkgrmgr(pkgmgr, mode);
224 ci::AppInstaller::Result Update(const bf::path& path_old,
225 const bf::path& path_new,
226 RequestResult mode = RequestResult::NORMAL) {
227 if (Install(path_old) != ci::AppInstaller::Result::OK) {
228 LOG(ERROR) << "Failed to install application. Cannot update";
229 return ci::AppInstaller::Result::UNKNOWN;
231 return Install(path_new, mode);
234 ci::AppInstaller::Result Uninstall(const std::string& pkgid,
235 RequestResult mode = RequestResult::NORMAL) {
236 const char* argv[] = {"", "-d", pkgid.c_str()};
237 std::unique_ptr<ci::AppQueryInterface> query_interface =
238 CreateQueryInterface();
240 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
241 query_interface.get());
243 LOG(ERROR) << "Failed to initialize pkgmgr interface";
244 return ci::AppInstaller::Result::UNKNOWN;
246 return RunInstallerWithPkgrmgr(pkgmgr, mode);
249 ci::AppInstaller::Result Reinstall(const bf::path& path,
250 const bf::path& delta_dir,
251 RequestResult mode = RequestResult::NORMAL) {
252 if (Install(path) != ci::AppInstaller::Result::OK) {
253 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
254 return ci::AppInstaller::Result::UNKNOWN;
256 const char* argv[] = {"", "-r", delta_dir.c_str()};
257 std::unique_ptr<ci::AppQueryInterface> query_interface =
258 CreateQueryInterface();
260 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
261 query_interface.get());
263 LOG(ERROR) << "Failed to initialize pkgmgr interface";
264 return ci::AppInstaller::Result::UNKNOWN;
266 return RunInstallerWithPkgrmgr(pkgmgr, mode);
269 ci::AppInstaller::Result DeltaInstall(const bf::path& path,
270 const bf::path& delta_package) {
271 if (Install(path) != ci::AppInstaller::Result::OK) {
272 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
273 return ci::AppInstaller::Result::UNKNOWN;
275 return Install(delta_package);
278 ci::AppInstaller::Result Recover(const bf::path& recovery_file,
279 RequestResult mode = RequestResult::NORMAL) {
280 const char* argv[] = {"", "-b", recovery_file.c_str()};
281 std::unique_ptr<ci::AppQueryInterface> query_interface =
282 CreateQueryInterface();
284 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
285 query_interface.get());
287 LOG(ERROR) << "Failed to initialize pkgmgr interface";
288 return ci::AppInstaller::Result::UNKNOWN;
290 return RunInstallerWithPkgrmgr(pkgmgr, mode);
295 namespace common_installer {
297 class SmokeEnvironment : public testing::Environment {
299 explicit SmokeEnvironment(const bf::path& home) : home_(home) {
301 void SetUp() override {
302 bs::error_code error;
303 bf::remove_all(home_ / kApplicationDirBackup, error);
304 bf::remove_all(home_ / KUserAppsDirBackup, error);
305 if (bf::exists(home_ / KUserAppsDir)) {
306 bf::rename(home_ / KUserAppsDir, home_ / KUserAppsDirBackup, error);
309 if (bf::exists(home_ / kApplicationDir)) {
310 bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
314 void TearDown() override {
315 bs::error_code error;
316 bf::remove_all(home_ / kApplicationDir, error);
317 bf::remove_all(home_ / KUserAppsDir, error);
318 if (bf::exists(home_ / KUserAppsDirBackup))
319 bf::rename(home_ / KUserAppsDirBackup, home_ / KUserAppsDir, error);
320 if (bf::exists(home_ / kApplicationDirBackup))
321 bf::rename(home_ / kApplicationDirBackup, home_ / kApplicationDir, error);
328 class SmokeTest : public testing::Test {
331 TEST_F(SmokeTest, InstallationMode) {
332 bf::path path = kSmokePackagesDirectory / "InstallationMode.wgt";
333 std::string pkgid = "smokeapp03";
334 std::string appid = "smokeapp03.InstallationMode";
335 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
336 ValidatePackage(pkgid, appid);
339 TEST_F(SmokeTest, UpdateMode) {
340 bf::path path_old = kSmokePackagesDirectory / "UpdateMode.wgt";
341 bf::path path_new = kSmokePackagesDirectory / "UpdateMode_2.wgt";
342 std::string pkgid = "smokeapp04";
343 std::string appid = "smokeapp04.UpdateMode";
344 ASSERT_EQ(Update(path_old, path_new), ci::AppInstaller::Result::OK);
345 ValidatePackage(pkgid, appid);
347 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "2\n"));
350 TEST_F(SmokeTest, DeinstallationMode) {
351 bf::path path = kSmokePackagesDirectory / "DeinstallationMode.wgt";
352 std::string pkgid = "smokeapp05";
353 std::string appid = "smokeapp05.DeinstallationMode";
354 ASSERT_EQ(Install(path),
355 ci::AppInstaller::Result::OK);
356 ASSERT_EQ(Uninstall(pkgid), ci::AppInstaller::Result::OK);
357 CheckPackageNonExistance(pkgid, appid);
360 TEST_F(SmokeTest, RDSMode) {
361 bf::path path = kSmokePackagesDirectory / "RDSMode.wgt";
362 bf::path delta_directory = kSmokePackagesDirectory / "delta_dir/";
363 std::string pkgid = "smokeapp11";
364 std::string appid = "smokeapp11.RDSMode";
365 ASSERT_EQ(Reinstall(path, delta_directory),
366 ci::AppInstaller::Result::OK);
367 ValidatePackage(pkgid, appid);
369 // Check delta modifications
370 bf::path root_path = ci::GetRootAppPath();
371 ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
372 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
373 ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "2\n");
376 TEST_F(SmokeTest, DeltaMode) {
377 bf::path path = kSmokePackagesDirectory / "DeltaMode.wgt";
378 bf::path delta_package = kSmokePackagesDirectory / "DeltaMode.delta";
379 std::string pkgid = "smokeapp17";
380 std::string appid = "smokeapp17.DeltaMode";
381 ASSERT_EQ(DeltaInstall(path, delta_package),
382 ci::AppInstaller::Result::OK);
383 ValidatePackage(pkgid, appid);
385 // Check delta modifications
386 bf::path root_path = ci::GetRootAppPath();
387 ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
388 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
389 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "css" / "style.css")); // NOLINT
390 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "images" / "tizen_32.png")); // NOLINT
391 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "js" / "main.js"));
392 ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "version 2\n");
395 TEST_F(SmokeTest, RecoveryMode_ForInstallation) {
396 bf::path path = kSmokePackagesDirectory / "RecoveryMode_ForInstallation.wgt";
397 ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
399 std::string pkgid = "smokeapp09";
400 std::string appid = "smokeapp09.RecoveryModeForInstallation";
401 bf::path recovery_file = FindRecoveryFile();
402 ASSERT_FALSE(recovery_file.empty());
403 ASSERT_EQ(Recover(recovery_file),
404 ci::AppInstaller::Result::OK);
405 CheckPackageNonExistance(pkgid, appid);
408 TEST_F(SmokeTest, RecoveryMode_ForUpdate) {
409 bf::path path_old = kSmokePackagesDirectory / "RecoveryMode_ForUpdate.wgt";
410 bf::path path_new = kSmokePackagesDirectory / "RecoveryMode_ForUpdate_2.wgt";
411 RemoveAllRecoveryFiles();
412 ASSERT_DEATH(Update(path_old, path_new, RequestResult::CRASH), ".*");
414 std::string pkgid = "smokeapp10";
415 std::string appid = "smokeapp10.RecoveryModeForUpdate";
416 bf::path recovery_file = FindRecoveryFile();
417 ASSERT_FALSE(recovery_file.empty());
418 ASSERT_EQ(Recover(recovery_file),
419 ci::AppInstaller::Result::OK);
420 ValidatePackage(pkgid, appid);
422 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
425 TEST_F(SmokeTest, InstallationMode_GoodSignature) {
426 bf::path path = kSmokePackagesDirectory / "InstallationMode_GoodSignature.wgt"; // NOLINT
427 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
430 TEST_F(SmokeTest, InstallationMode_WrongSignature) {
431 bf::path path = kSmokePackagesDirectory / "InstallationMode_WrongSignature.wgt"; // NOLINT
432 ASSERT_EQ(Install(path), ci::AppInstaller::Result::ERROR);
435 TEST_F(SmokeTest, InstallationMode_Rollback) {
436 bf::path path = kSmokePackagesDirectory / "InstallationMode_Rollback.wgt";
437 std::string pkgid = "smokeapp06";
438 std::string appid = "smokeapp06.InstallationModeRollback";
439 ASSERT_EQ(Install(path, RequestResult::FAIL),
440 ci::AppInstaller::Result::ERROR);
441 CheckPackageNonExistance(pkgid, appid);
444 TEST_F(SmokeTest, UpdateMode_Rollback) {
445 bf::path path_old = kSmokePackagesDirectory / "UpdateMode_Rollback.wgt";
446 bf::path path_new = kSmokePackagesDirectory / "UpdateMode_Rollback_2.wgt";
447 std::string pkgid = "smokeapp07";
448 std::string appid = "smokeapp07.UpdateModeRollback";
449 ASSERT_EQ(Update(path_old, path_new, RequestResult::FAIL),
450 ci::AppInstaller::Result::ERROR);
451 ValidatePackage(pkgid, appid);
453 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
456 TEST_F(SmokeTest, DeinstallationMode_Rollback) {
457 bf::path path = kSmokePackagesDirectory / "DeinstallationMode_Rollback.wgt";
458 std::string pkgid = "smokeapp08";
459 std::string appid = "smokeapp08.DeinstallationModeRollback";
460 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
461 ASSERT_EQ(Uninstall(pkgid, RequestResult::FAIL),
462 ci::AppInstaller::Result::ERROR);
463 ValidatePackage(pkgid, appid);
466 } // namespace common_installer
468 int main(int argc, char** argv) {
469 testing::InitGoogleTest(&argc, argv);
470 const char* directory = getenv("HOME");
472 LOG(ERROR) << "Cannot get $HOME value";
475 testing::AddGlobalTestEnvironment(
476 new common_installer::SmokeEnvironment(directory));
477 return RUN_ALL_TESTS();