modify codes related to getting app_path.
[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(false);
66   if (!bf::exists(root_path))
67     return;
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) {
72         bs::error_code error;
73         bf::remove(dir_entry.path(), error);
74       }
75     }
76   }
77 }
78
79 bf::path FindRecoveryFile() {
80   bf::path root_path = ci::GetRootAppPath(false);
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();
86       }
87     }
88   }
89   return {};
90 }
91
92 bool ValidateFileContentInPackage(const std::string& pkgid,
93                                   const std::string& relative,
94                                   const std::string& expected) {
95   bf::path root_path = ci::GetRootAppPath(false);
96   bf::path file_path = root_path / pkgid / relative;
97   if (!bf::exists(file_path)) {
98     LOG(ERROR) << file_path << " doesn't exist";
99     return false;
100   }
101   FILE* handle = fopen(file_path.c_str(), "r");
102   if (!handle) {
103     LOG(ERROR) << file_path << " cannot  be open";
104     return false;
105   }
106   std::string content;
107   std::array<char, 200> buffer;
108   while (fgets(buffer.data(), buffer.size(), handle)) {
109     content += buffer.data();
110   }
111   fclose(handle);
112   return content == expected;
113 }
114
115 void ValidatePackageFS(const std::string& pkgid, const std::string& appid) {
116   bf::path root_path = ci::GetRootAppPath(false);
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));
128
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));
134
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));
139
140   bf::path private_tmp_path = package_path / "tmp";
141   ASSERT_TRUE(bf::exists(private_tmp_path));
142
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));
150 }
151
152 void PackageCheckCleanup(const std::string& pkgid, const std::string& appid) {
153   bf::path root_path = ci::GetRootAppPath(false);
154   bf::path package_path = root_path / pkgid;
155   ASSERT_FALSE(bf::exists(package_path));
156
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));
162
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));
170 }
171
172 void ValidatePackage(const std::string& pkgid, const std::string& appid) {
173   ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
174   ValidatePackageFS(pkgid, appid);
175 }
176
177 void CheckPackageNonExistance(const std::string& pkgid,
178                               const std::string& appid) {
179   ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
180   PackageCheckCleanup(pkgid, appid);
181 }
182
183 std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
184   std::unique_ptr<ci::AppQueryInterface> query_interface(
185       new wgt::WgtAppQueryInterface());
186   return query_interface;
187 }
188
189 std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr) {
190   std::unique_ptr<ci::AppInstaller> installer(new wgt::WgtInstaller(pkgmgr));
191   return installer;
192 }
193
194 ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
195                                                  RequestResult mode) {
196   std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
197   switch (mode) {
198   case RequestResult::FAIL:
199     installer->AddStep<ci::configuration::StepFail>();
200     break;
201   case RequestResult::CRASH:
202     installer->AddStep<StepCrash>();
203   default:
204     break;
205   }
206   return installer->Run();
207 }
208
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();
214   auto pkgmgr =
215       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
216                                   query_interface.get());
217   if (!pkgmgr) {
218     LOG(ERROR) << "Failed to initialize pkgmgr interface";
219     return ci::AppInstaller::Result::UNKNOWN;
220   }
221   return RunInstallerWithPkgrmgr(pkgmgr, mode);
222 }
223
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;
230   }
231   return Install(path_new, mode);
232 }
233
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();
239   auto pkgmgr =
240       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
241                                   query_interface.get());
242   if (!pkgmgr) {
243     LOG(ERROR) << "Failed to initialize pkgmgr interface";
244     return ci::AppInstaller::Result::UNKNOWN;
245   }
246   return RunInstallerWithPkgrmgr(pkgmgr, mode);
247 }
248
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;
255   }
256   const char* argv[] = {"", "-r", delta_dir.c_str()};
257   std::unique_ptr<ci::AppQueryInterface> query_interface =
258       CreateQueryInterface();
259   auto pkgmgr =
260       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
261                                   query_interface.get());
262   if (!pkgmgr) {
263     LOG(ERROR) << "Failed to initialize pkgmgr interface";
264     return ci::AppInstaller::Result::UNKNOWN;
265   }
266   return RunInstallerWithPkgrmgr(pkgmgr, mode);
267 }
268
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;
274   }
275   return Install(delta_package);
276 }
277
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();
283   auto pkgmgr =
284       ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
285                                   query_interface.get());
286   if (!pkgmgr) {
287     LOG(ERROR) << "Failed to initialize pkgmgr interface";
288     return ci::AppInstaller::Result::UNKNOWN;
289   }
290   return RunInstallerWithPkgrmgr(pkgmgr, mode);
291 }
292
293 }  // namespace
294
295 namespace common_installer {
296
297 class SmokeEnvironment : public testing::Environment {
298  public:
299   explicit SmokeEnvironment(const bf::path& home) : home_(home) {
300   }
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);
307       assert(!error);
308     }
309     if (bf::exists(home_ / kApplicationDir)) {
310       bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
311       assert(!error);
312     }
313   }
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);
322   }
323
324  private:
325   bf::path home_;
326 };
327
328 class SmokeTest : public testing::Test {
329 };
330
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);
337 }
338
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);
346
347   ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "2\n"));
348 }
349
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);
358 }
359
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);
368
369   // Check delta modifications
370   bf::path root_path = ci::GetRootAppPath(false);
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");
374 }
375
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);
384
385   // Check delta modifications
386   bf::path root_path = ci::GetRootAppPath(false);
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");
393 }
394
395 TEST_F(SmokeTest, RecoveryMode_ForInstallation) {
396   bf::path path = kSmokePackagesDirectory / "RecoveryMode_ForInstallation.wgt";
397   ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
398
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);
406 }
407
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), ".*");
413
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);
421
422   ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
423 }
424
425 TEST_F(SmokeTest, InstallationMode_GoodSignature) {
426   bf::path path = kSmokePackagesDirectory / "InstallationMode_GoodSignature.wgt";  // NOLINT
427   ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
428 }
429
430 TEST_F(SmokeTest, InstallationMode_WrongSignature) {
431   bf::path path = kSmokePackagesDirectory / "InstallationMode_WrongSignature.wgt";  // NOLINT
432   ASSERT_EQ(Install(path), ci::AppInstaller::Result::ERROR);
433 }
434
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);
442 }
443
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);
452
453   ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
454 }
455
456 }  // namespace common_installer
457
458 int main(int argc,  char** argv) {
459   testing::InitGoogleTest(&argc, argv);
460   const char* directory = getenv("HOME");
461   if (!directory) {
462     LOG(ERROR) << "Cannot get $HOME value";
463     return 1;
464   }
465   testing::AddGlobalTestEnvironment(
466       new common_installer::SmokeEnvironment(directory));
467   return RUN_ALL_TESTS();
468 }