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 for (auto& dir_entry : boost::make_iterator_range(
67 bf::directory_iterator(root_path), bf::directory_iterator())) {
68 if (bf::is_regular_file(dir_entry)) {
69 if (dir_entry.path().string().find("/recovery") != std::string::npos) {
71 bf::remove(dir_entry.path(), error);
77 bf::path FindRecoveryFile() {
78 bf::path root_path = ci::GetRootAppPath();
79 for (auto& dir_entry : boost::make_iterator_range(
80 bf::directory_iterator(root_path), bf::directory_iterator())) {
81 if (bf::is_regular_file(dir_entry)) {
82 if (dir_entry.path().string().find("/recovery") != std::string::npos) {
83 return dir_entry.path();
90 bool ValidateFileContentInPackage(const std::string& pkgid,
91 const std::string& relative,
92 const std::string& expected) {
93 bf::path root_path = ci::GetRootAppPath();
94 bf::path file_path = root_path / pkgid / relative;
95 if (!bf::exists(file_path)) {
96 LOG(ERROR) << file_path << " doesn't exist";
99 FILE* handle = fopen(file_path.c_str(), "r");
101 LOG(ERROR) << file_path << " cannot be open";
105 std::array<char, 200> buffer;
106 while (fgets(buffer.data(), buffer.size(), handle)) {
107 content += buffer.data();
110 return content == expected;
113 void ValidatePackageFS(const std::string& pkgid, const std::string& appid) {
114 bf::path root_path = ci::GetRootAppPath();
115 bf::path package_path = root_path / pkgid;
116 bf::path binary_path = package_path / "bin" / appid;
117 bf::path data_path = package_path / "data";
118 bf::path shared_path = package_path / "shared";
119 bf::path cache_path = package_path / "cache";
120 ASSERT_TRUE(bf::exists(root_path));
121 ASSERT_TRUE(bf::exists(package_path));
122 ASSERT_TRUE(bf::exists(binary_path));
123 ASSERT_TRUE(bf::exists(data_path));
124 ASSERT_TRUE(bf::exists(shared_path));
125 ASSERT_TRUE(bf::exists(cache_path));
127 bf::path manifest_path =
128 bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
129 bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
130 ASSERT_TRUE(bf::exists(manifest_path));
131 ASSERT_TRUE(bf::exists(icon_path));
133 bf::path widget_root_path = package_path / "res" / "wgt";
134 bf::path config_path = widget_root_path / "config.xml";
135 ASSERT_TRUE(bf::exists(widget_root_path));
136 ASSERT_TRUE(bf::exists(config_path));
138 bf::path private_tmp_path = package_path / "tmp";
139 ASSERT_TRUE(bf::exists(private_tmp_path));
141 // backups should not exist
142 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
143 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
144 bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
145 ASSERT_FALSE(bf::exists(package_backup));
146 ASSERT_FALSE(bf::exists(manifest_backup));
147 ASSERT_FALSE(bf::exists(icon_backup));
150 void PackageCheckCleanup(const std::string& pkgid, const std::string& appid) {
151 bf::path root_path = ci::GetRootAppPath();
152 bf::path package_path = root_path / pkgid;
153 ASSERT_FALSE(bf::exists(package_path));
155 bf::path manifest_path =
156 bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
157 bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
158 ASSERT_FALSE(bf::exists(manifest_path));
159 ASSERT_FALSE(bf::exists(icon_path));
161 // backups should not exist
162 bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
163 bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
164 bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
165 ASSERT_FALSE(bf::exists(package_backup));
166 ASSERT_FALSE(bf::exists(manifest_backup));
167 ASSERT_FALSE(bf::exists(icon_backup));
170 void ValidatePackage(const std::string& pkgid, const std::string& appid) {
171 ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
172 ValidatePackageFS(pkgid, appid);
175 void CheckPackageNonExistance(const std::string& pkgid,
176 const std::string& appid) {
177 ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
178 PackageCheckCleanup(pkgid, appid);
181 std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
182 std::unique_ptr<ci::AppQueryInterface> query_interface(
183 new wgt::WgtAppQueryInterface());
184 return query_interface;
187 std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr) {
188 std::unique_ptr<ci::AppInstaller> installer(new wgt::WgtInstaller(pkgmgr));
192 ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
193 RequestResult mode) {
194 std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
196 case RequestResult::FAIL:
197 installer->AddStep<ci::configuration::StepFail>();
199 case RequestResult::CRASH:
200 installer->AddStep<StepCrash>();
204 return installer->Run();
207 ci::AppInstaller::Result Install(const bf::path& path,
208 RequestResult mode = RequestResult::NORMAL) {
209 const char* argv[] = {"", "-i", path.c_str()};
210 std::unique_ptr<ci::AppQueryInterface> query_interface =
211 CreateQueryInterface();
213 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
214 query_interface.get());
216 LOG(ERROR) << "Failed to initialize pkgmgr interface";
217 return ci::AppInstaller::Result::UNKNOWN;
219 return RunInstallerWithPkgrmgr(pkgmgr, mode);
222 ci::AppInstaller::Result Update(const bf::path& path_old,
223 const bf::path& path_new,
224 RequestResult mode = RequestResult::NORMAL) {
225 if (Install(path_old) != ci::AppInstaller::Result::OK) {
226 LOG(ERROR) << "Failed to install application. Cannot update";
227 return ci::AppInstaller::Result::UNKNOWN;
229 return Install(path_new, mode);
232 ci::AppInstaller::Result Uninstall(const std::string& pkgid,
233 RequestResult mode = RequestResult::NORMAL) {
234 const char* argv[] = {"", "-d", pkgid.c_str()};
235 std::unique_ptr<ci::AppQueryInterface> query_interface =
236 CreateQueryInterface();
238 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
239 query_interface.get());
241 LOG(ERROR) << "Failed to initialize pkgmgr interface";
242 return ci::AppInstaller::Result::UNKNOWN;
244 return RunInstallerWithPkgrmgr(pkgmgr, mode);
247 ci::AppInstaller::Result Reinstall(const bf::path& path,
248 const bf::path& delta_dir,
249 RequestResult mode = RequestResult::NORMAL) {
250 if (Install(path) != ci::AppInstaller::Result::OK) {
251 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
252 return ci::AppInstaller::Result::UNKNOWN;
254 const char* argv[] = {"", "-r", delta_dir.c_str()};
255 std::unique_ptr<ci::AppQueryInterface> query_interface =
256 CreateQueryInterface();
258 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
259 query_interface.get());
261 LOG(ERROR) << "Failed to initialize pkgmgr interface";
262 return ci::AppInstaller::Result::UNKNOWN;
264 return RunInstallerWithPkgrmgr(pkgmgr, mode);
267 ci::AppInstaller::Result DeltaInstall(const bf::path& path,
268 const bf::path& delta_package) {
269 if (Install(path) != ci::AppInstaller::Result::OK) {
270 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
271 return ci::AppInstaller::Result::UNKNOWN;
273 return Install(delta_package);
276 ci::AppInstaller::Result Recover(const bf::path& recovery_file,
277 RequestResult mode = RequestResult::NORMAL) {
278 const char* argv[] = {"", "-e", recovery_file.c_str()};
279 std::unique_ptr<ci::AppQueryInterface> query_interface =
280 CreateQueryInterface();
282 ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
283 query_interface.get());
285 LOG(ERROR) << "Failed to initialize pkgmgr interface";
286 return ci::AppInstaller::Result::UNKNOWN;
288 return RunInstallerWithPkgrmgr(pkgmgr, mode);
293 namespace common_installer {
295 class SmokeEnvironment : public testing::Environment {
297 explicit SmokeEnvironment(const bf::path& home) : home_(home) {
299 void SetUp() override {
300 bs::error_code error;
301 bf::remove_all(home_ / kApplicationDirBackup, error);
302 bf::remove_all(home_ / KUserAppsDirBackup, error);
303 if (bf::exists(home_ / KUserAppsDir)) {
304 bf::rename(home_ / KUserAppsDir, home_ / KUserAppsDirBackup, error);
307 if (bf::exists(home_ / kApplicationDir)) {
308 bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
312 void TearDown() override {
313 bs::error_code error;
314 bf::remove_all(home_ / kApplicationDir, error);
315 bf::remove_all(home_ / KUserAppsDir, error);
316 if (bf::exists(home_ / KUserAppsDirBackup))
317 bf::rename(home_ / KUserAppsDirBackup, home_ / KUserAppsDir, error);
318 if (bf::exists(home_ / kApplicationDirBackup))
319 bf::rename(home_ / kApplicationDirBackup, home_ / kApplicationDir, error);
326 class SmokeTest : public testing::Test {
329 TEST_F(SmokeTest, InstallationMode) {
330 bf::path path = kSmokePackagesDirectory / "InstallationMode.wgt";
331 std::string pkgid = "smokeapp03";
332 std::string appid = "smokeapp03.InstallationMode";
333 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
334 ValidatePackage(pkgid, appid);
337 TEST_F(SmokeTest, UpdateMode) {
338 bf::path path_old = kSmokePackagesDirectory / "UpdateMode.wgt";
339 bf::path path_new = kSmokePackagesDirectory / "UpdateMode_2.wgt";
340 std::string pkgid = "smokeapp04";
341 std::string appid = "smokeapp04.UpdateMode";
342 ASSERT_EQ(Update(path_old, path_new), ci::AppInstaller::Result::OK);
343 ValidatePackage(pkgid, appid);
345 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "2\n"));
348 TEST_F(SmokeTest, DeinstallationMode) {
349 bf::path path = kSmokePackagesDirectory / "DeinstallationMode.wgt";
350 std::string pkgid = "smokeapp05";
351 std::string appid = "smokeapp05.DeinstallationMode";
352 ASSERT_EQ(Install(path),
353 ci::AppInstaller::Result::OK);
354 ASSERT_EQ(Uninstall(pkgid), ci::AppInstaller::Result::OK);
355 CheckPackageNonExistance(pkgid, appid);
358 TEST_F(SmokeTest, RDSMode) {
359 bf::path path = kSmokePackagesDirectory / "RDSMode.wgt";
360 bf::path delta_directory = kSmokePackagesDirectory / "delta_dir/";
361 std::string pkgid = "smokeapp11";
362 std::string appid = "smokeapp11.RDSMode";
363 ASSERT_EQ(Reinstall(path, delta_directory),
364 ci::AppInstaller::Result::OK);
365 ValidatePackage(pkgid, appid);
367 // Check delta modifications
368 bf::path root_path = ci::GetRootAppPath();
369 ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
370 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
371 ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "2\n");
374 TEST_F(SmokeTest, DeltaMode) {
375 bf::path path = kSmokePackagesDirectory / "DeltaMode.wgt";
376 bf::path delta_package = kSmokePackagesDirectory / "DeltaMode.delta";
377 std::string pkgid = "smokeapp17";
378 std::string appid = "smokeapp17.DeltaMode";
379 ASSERT_EQ(DeltaInstall(path, delta_package),
380 ci::AppInstaller::Result::OK);
381 ValidatePackage(pkgid, appid);
383 // Check delta modifications
384 bf::path root_path = ci::GetRootAppPath();
385 ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
386 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
387 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "css" / "style.css")); // NOLINT
388 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "images" / "tizen_32.png")); // NOLINT
389 ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "js" / "main.js"));
390 ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "version 2\n");
393 TEST_F(SmokeTest, RecoveryMode_ForInstallation) {
394 bf::path path = kSmokePackagesDirectory / "RecoveryMode_ForInstallation.wgt";
395 ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
397 std::string pkgid = "smokeapp09";
398 std::string appid = "smokeapp09.RecoveryModeForInstallation";
399 bf::path recovery_file = FindRecoveryFile();
400 ASSERT_FALSE(recovery_file.empty());
401 ASSERT_EQ(Recover(recovery_file),
402 ci::AppInstaller::Result::OK);
403 CheckPackageNonExistance(pkgid, appid);
406 TEST_F(SmokeTest, RecoveryMode_ForUpdate) {
407 bf::path path_old = kSmokePackagesDirectory / "RecoveryMode_ForUpdate.wgt";
408 bf::path path_new = kSmokePackagesDirectory / "RecoveryMode_ForUpdate_2.wgt";
409 RemoveAllRecoveryFiles();
410 ASSERT_DEATH(Update(path_old, path_new, RequestResult::CRASH), ".*");
412 std::string pkgid = "smokeapp10";
413 std::string appid = "smokeapp10.RecoveryModeForUpdate";
414 bf::path recovery_file = FindRecoveryFile();
415 ASSERT_FALSE(recovery_file.empty());
416 ASSERT_EQ(Recover(recovery_file),
417 ci::AppInstaller::Result::OK);
418 ValidatePackage(pkgid, appid);
420 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
423 TEST_F(SmokeTest, InstallationMode_GoodSignature) {
424 bf::path path = kSmokePackagesDirectory / "InstallationMode_GoodSignature.wgt"; // NOLINT
425 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
428 TEST_F(SmokeTest, InstallationMode_WrongSignature) {
429 bf::path path = kSmokePackagesDirectory / "InstallationMode_WrongSignature.wgt"; // NOLINT
430 ASSERT_EQ(Install(path), ci::AppInstaller::Result::ERROR);
433 TEST_F(SmokeTest, InstallationMode_Rollback) {
434 bf::path path = kSmokePackagesDirectory / "InstallationMode_Rollback.wgt";
435 std::string pkgid = "smokeapp06";
436 std::string appid = "smokeapp06.InstallationModeRollback";
437 ASSERT_EQ(Install(path, RequestResult::FAIL),
438 ci::AppInstaller::Result::ERROR);
439 CheckPackageNonExistance(pkgid, appid);
442 TEST_F(SmokeTest, UpdateMode_Rollback) {
443 bf::path path_old = kSmokePackagesDirectory / "UpdateMode_Rollback.wgt";
444 bf::path path_new = kSmokePackagesDirectory / "UpdateMode_Rollback_2.wgt";
445 std::string pkgid = "smokeapp07";
446 std::string appid = "smokeapp07.UpdateModeRollback";
447 ASSERT_EQ(Update(path_old, path_new, RequestResult::FAIL),
448 ci::AppInstaller::Result::ERROR);
449 ValidatePackage(pkgid, appid);
451 ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
454 TEST_F(SmokeTest, DeinstallationMode_Rollback) {
455 bf::path path = kSmokePackagesDirectory / "DeinstallationMode_Rollback.wgt";
456 std::string pkgid = "smokeapp08";
457 std::string appid = "smokeapp08.DeinstallationModeRollback";
458 ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
459 ASSERT_EQ(Uninstall(pkgid, RequestResult::FAIL),
460 ci::AppInstaller::Result::ERROR);
461 ValidatePackage(pkgid, appid);
464 } // namespace common_installer
466 int main(int argc, char** argv) {
467 testing::InitGoogleTest(&argc, argv);
468 const char* directory = getenv("HOME");
470 LOG(ERROR) << "Cannot get $HOME value";
473 testing::AddGlobalTestEnvironment(
474 new common_installer::SmokeEnvironment(directory));
475 return RUN_ALL_TESTS();