Fix paths in smoke tests
[platform/core/appfw/wgt-backend.git] / src / unit_tests / smoke_test.cc
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.
4
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>
17 #include <signal.h>
18 #include <unistd.h>
19 #include <tzplatform_config.h>
20
21 #include <array>
22 #include <cstdio>
23 #include <cstdlib>
24
25 #include "wgt/wgt_app_query_interface.h"
26 #include "wgt/wgt_installer.h"
27
28 #define SIZEOFARRAY(ARR)                                                       \
29   sizeof(ARR) / sizeof(ARR[0])                                                 \
30
31 namespace bf = boost::filesystem;
32 namespace bs = boost::system;
33 namespace ci = common_installer;
34
35 namespace {
36
37 const bf::path kSmokePackagesDirectory =
38     "/usr/share/wgt-backend-ut/test_samples/smoke/";
39
40 const char kApplicationDir[] = ".applications";
41 const char kApplicationDirBackup[] = ".applications.bck";
42 const char KUserAppsDir[] = "apps_rw";
43 const char KUserAppsDirBackup[] = "apps_rw.bck";
44
45 enum class RequestResult {
46   NORMAL,
47   FAIL,
48   CRASH
49 };
50
51 class StepCrash : public ci::Step {
52  public:
53   using Step::Step;
54
55   ci::Step::Status process() override {
56     raise(SIGSEGV);
57     return Status::OK;
58   }
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; }
62 };
63
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) {
70         bs::error_code error;
71         bf::remove(dir_entry.path(), error);
72       }
73     }
74   }
75 }
76
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();
84       }
85     }
86   }
87   return {};
88 }
89
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";
97     return false;
98   }
99   FILE* handle = fopen(file_path.c_str(), "r");
100   if (!handle) {
101     LOG(ERROR) << file_path << " cannot  be open";
102     return false;
103   }
104   std::string content;
105   std::array<char, 200> buffer;
106   while (fgets(buffer.data(), buffer.size(), handle)) {
107     content += buffer.data();
108   }
109   fclose(handle);
110   return content == expected;
111 }
112
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));
126
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));
132
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));
137
138   bf::path private_tmp_path = package_path / "tmp";
139   ASSERT_TRUE(bf::exists(private_tmp_path));
140
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));
148 }
149
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));
154
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));
160
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));
168 }
169
170 void ValidatePackage(const std::string& pkgid, const std::string& appid) {
171   ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
172   ValidatePackageFS(pkgid, appid);
173 }
174
175 void CheckPackageNonExistance(const std::string& pkgid,
176                               const std::string& appid) {
177   ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
178   PackageCheckCleanup(pkgid, appid);
179 }
180
181 std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
182   std::unique_ptr<ci::AppQueryInterface> query_interface(
183       new wgt::WgtAppQueryInterface());
184   return query_interface;
185 }
186
187 std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr) {
188   std::unique_ptr<ci::AppInstaller> installer(new wgt::WgtInstaller(pkgmgr));
189   return installer;
190 }
191
192 ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
193                                                  RequestResult mode) {
194   std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
195   switch (mode) {
196   case RequestResult::FAIL:
197     installer->AddStep<ci::configuration::StepFail>();
198     break;
199   case RequestResult::CRASH:
200     installer->AddStep<StepCrash>();
201   default:
202     break;
203   }
204   return installer->Run();
205 }
206
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();
212   auto pkgmgr =
213       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
214                                   query_interface.get());
215   if (!pkgmgr) {
216     LOG(ERROR) << "Failed to initialize pkgmgr interface";
217     return ci::AppInstaller::Result::UNKNOWN;
218   }
219   return RunInstallerWithPkgrmgr(pkgmgr, mode);
220 }
221
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;
228   }
229   return Install(path_new, mode);
230 }
231
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();
237   auto pkgmgr =
238       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
239                                   query_interface.get());
240   if (!pkgmgr) {
241     LOG(ERROR) << "Failed to initialize pkgmgr interface";
242     return ci::AppInstaller::Result::UNKNOWN;
243   }
244   return RunInstallerWithPkgrmgr(pkgmgr, mode);
245 }
246
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;
253   }
254   const char* argv[] = {"", "-r", delta_dir.c_str()};
255   std::unique_ptr<ci::AppQueryInterface> query_interface =
256       CreateQueryInterface();
257   auto pkgmgr =
258       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
259                                   query_interface.get());
260   if (!pkgmgr) {
261     LOG(ERROR) << "Failed to initialize pkgmgr interface";
262     return ci::AppInstaller::Result::UNKNOWN;
263   }
264   return RunInstallerWithPkgrmgr(pkgmgr, mode);
265 }
266
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;
272   }
273   return Install(delta_package);
274 }
275
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();
281   auto pkgmgr =
282       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
283                                   query_interface.get());
284   if (!pkgmgr) {
285     LOG(ERROR) << "Failed to initialize pkgmgr interface";
286     return ci::AppInstaller::Result::UNKNOWN;
287   }
288   return RunInstallerWithPkgrmgr(pkgmgr, mode);
289 }
290
291 }  // namespace
292
293 namespace common_installer {
294
295 class SmokeEnvironment : public testing::Environment {
296  public:
297   explicit SmokeEnvironment(const bf::path& home) : home_(home) {
298   }
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);
305       assert(!error);
306     }
307     if (bf::exists(home_ / kApplicationDir)) {
308       bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
309       assert(!error);
310     }
311   }
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);
320   }
321
322  private:
323   bf::path home_;
324 };
325
326 class SmokeTest : public testing::Test {
327 };
328
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);
335 }
336
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);
344
345   ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "2\n"));
346 }
347
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);
356 }
357
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);
366
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");
372 }
373
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);
382
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");
391 }
392
393 TEST_F(SmokeTest, RecoveryMode_ForInstallation) {
394   bf::path path = kSmokePackagesDirectory / "RecoveryMode_ForInstallation.wgt";
395   ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
396
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);
404 }
405
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), ".*");
411
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);
419
420   ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
421 }
422
423 TEST_F(SmokeTest, InstallationMode_GoodSignature) {
424   bf::path path = kSmokePackagesDirectory / "InstallationMode_GoodSignature.wgt";  // NOLINT
425   ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
426 }
427
428 TEST_F(SmokeTest, InstallationMode_WrongSignature) {
429   bf::path path = kSmokePackagesDirectory / "InstallationMode_WrongSignature.wgt";  // NOLINT
430   ASSERT_EQ(Install(path), ci::AppInstaller::Result::ERROR);
431 }
432
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);
440 }
441
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);
450
451   ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
452 }
453
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);
462 }
463
464 }  // namespace common_installer
465
466 int main(int argc,  char** argv) {
467   testing::InitGoogleTest(&argc, argv);
468   const char* directory = getenv("HOME");
469   if (!directory) {
470     LOG(ERROR) << "Cannot get $HOME value";
471     return 1;
472   }
473   testing::AddGlobalTestEnvironment(
474       new common_installer::SmokeEnvironment(directory));
475   return RUN_ALL_TESTS();
476 }