From c6e1bd9a28d18c88b335c07e4da1e4246f704bd8 Mon Sep 17 00:00:00 2001
From: Pawel Sikorski
Date: Fri, 18 Dec 2015 10:50:50 +0100
Subject: [PATCH 2/9] Adding initial files to repository
Adding:
* LICENSE, AUTHORS
* check-coding-style tool
* packaging spec file (now empty)
Change-Id: I15e52b9c6af8741fc06513290ca93210f703a8c6
---
AUTHORS | 1 +
LICENSE | 203 +++++++++++++++++++++++++++++++++++++++++++++
packaging/wgt-backend.spec | 17 ++++
tools/check-coding-style | 28 +++++++
4 files changed, 249 insertions(+)
create mode 100644 AUTHORS
create mode 100644 LICENSE
create mode 100644 packaging/wgt-backend.spec
create mode 100755 tools/check-coding-style
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..d115209
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+p.sikorski@samsung.com
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..53779e4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+// 2015, Copyright (c) Samsung Electronics Co., Ltd All Rights Reserved
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec
new file mode 100644
index 0000000..3c17083
--- /dev/null
+++ b/packaging/wgt-backend.spec
@@ -0,0 +1,17 @@
+#Available values for profile: mobile, wearable, tv, ivi, common
+%{!?profile:%define profile tv}
+
+Name: wgt-backend
+Summary: Application installer backend for WGT
+Version: 0.1
+Release: 1
+Group: Application Framework/Package Management
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+
+
+%changelog
+* Thu Dec 18 2015 Pawel Sikorski 0.1-1
+- initial files creation
+
+
diff --git a/tools/check-coding-style b/tools/check-coding-style
new file mode 100755
index 0000000..fd60481
--- /dev/null
+++ b/tools/check-coding-style
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if [ ! `which cpplint.py` ]; then
+ echo -e "\nPlease make sure cpplint.py is in your PATH. It is part of depot_tools inside Chromium repository."
+ exit 1
+fi
+
+OLDPWD=$PWD
+BASE=`dirname $0`
+cd $BASE/..
+
+# filters
+FILTERS="-readability/streams,-build/c++11"
+
+cpplint.py --root=src --filter="$FILTERS" $(find . \( -name '*.h' -o -name '*.cc' \) )
+RET=$?
+
+JS_RET_VAL=$?
+cd $OLDPWD
+
+if [ "x$RET" == "x0" ]; then
+ exit 0
+else
+ exit 1
+fi
--
2.7.4
From 19dd0a66cfd6569cf120233e7d8e3672e7f97670 Mon Sep 17 00:00:00 2001
From: Tomasz Iwanek
Date: Mon, 14 Dec 2015 13:58:10 +0100
Subject: [PATCH 3/9] Move wgt-backend implementation from app-installers
Requires to be submitted with:
- https://review.tizen.org/gerrit/#/c/54291/
Aligned with app-installer's commit: 532a4707928d6d137c2cb93ae3523f25f0ac06ee
Change-Id: I30347bd6ca66026d3e363bb16000a44e2d791f39
---
CMakeLists.txt | 48 ++
cmake/Modules/ApplyPkgConfig.cmake | 35 ++
packaging/wgt-backend-tests.manifest | 8 +
packaging/wgt-backend.manifest | 8 +
packaging/wgt-backend.spec | 54 +-
src/CMakeLists.txt | 2 +
src/unit_tests/CMakeLists.txt | 22 +
src/unit_tests/smoke_test.cc | 473 +++++++++++++++++
.../test_samples/smoke/DeinstallationMode.wgt | Bin 0 -> 33312 bytes
.../smoke/DeinstallationMode_Rollback.wgt | Bin 0 -> 33320 bytes
src/unit_tests/test_samples/smoke/DeltaMode.delta | Bin 0 -> 1070 bytes
src/unit_tests/test_samples/smoke/DeltaMode.wgt | Bin 0 -> 34283 bytes
.../test_samples/smoke/InstallationMode.wgt | Bin 0 -> 33311 bytes
.../smoke/InstallationMode_GoodSignature.wgt | Bin 0 -> 38029 bytes
.../smoke/InstallationMode_Rollback.wgt | Bin 0 -> 33320 bytes
.../smoke/InstallationMode_WrongSignature.wgt | Bin 0 -> 37906 bytes
src/unit_tests/test_samples/smoke/RDSMode.wgt | Bin 0 -> 34275 bytes
.../smoke/RecoveryMode_ForInstallation.wgt | Bin 0 -> 33322 bytes
.../test_samples/smoke/RecoveryMode_ForUpdate.wgt | Bin 0 -> 34140 bytes
.../smoke/RecoveryMode_ForUpdate_2.wgt | Bin 0 -> 34140 bytes
src/unit_tests/test_samples/smoke/UpdateMode.wgt | Bin 0 -> 34134 bytes
src/unit_tests/test_samples/smoke/UpdateMode_2.wgt | Bin 0 -> 34134 bytes
.../test_samples/smoke/UpdateMode_Rollback.wgt | Bin 0 -> 34141 bytes
.../test_samples/smoke/UpdateMode_Rollback_2.wgt | Bin 0 -> 34141 bytes
.../test_samples/smoke/delta_dir/.rds_delta | 6 +
src/unit_tests/test_samples/smoke/delta_dir/ADDED | 0
.../test_samples/smoke/delta_dir/MODIFIED | 1 +
.../test_samples/smoke/delta_dir/config.xml | 9 +
src/wgt/CMakeLists.txt | 51 ++
src/wgt/rds_parser.cc | 61 +++
src/wgt/rds_parser.h | 63 +++
src/wgt/step/step_add_default_privileges.cc | 38 ++
src/wgt/step/step_add_default_privileges.h | 59 +++
src/wgt/step/step_check_settings_level.cc | 47 ++
src/wgt/step/step_check_settings_level.h | 59 +++
src/wgt/step/step_check_wgt_background_category.cc | 30 ++
src/wgt/step/step_check_wgt_background_category.h | 31 ++
src/wgt/step/step_create_symbolic_link.cc | 71 +++
src/wgt/step/step_create_symbolic_link.h | 61 +++
src/wgt/step/step_encrypt_resources.cc | 215 ++++++++
src/wgt/step/step_encrypt_resources.h | 66 +++
src/wgt/step/step_generate_xml.cc | 494 ++++++++++++++++++
src/wgt/step/step_generate_xml.h | 45 ++
src/wgt/step/step_parse.cc | 574 +++++++++++++++++++++
src/wgt/step/step_parse.h | 100 ++++
src/wgt/step/step_parse_recovery.cc | 56 ++
src/wgt/step/step_parse_recovery.h | 63 +++
src/wgt/step/step_rds_modify.cc | 226 ++++++++
src/wgt/step/step_rds_modify.h | 87 ++++
src/wgt/step/step_rds_parse.cc | 50 ++
src/wgt/step/step_rds_parse.h | 61 +++
src/wgt/step/step_remove_encryption_data.cc | 54 ++
src/wgt/step/step_remove_encryption_data.h | 57 ++
src/wgt/step/step_wgt_copy_storage_directories.cc | 172 ++++++
src/wgt/step/step_wgt_copy_storage_directories.h | 58 +++
src/wgt/step/step_wgt_create_icons.cc | 22 +
src/wgt/step/step_wgt_create_icons.h | 36 ++
.../step/step_wgt_create_storage_directories.cc | 102 ++++
src/wgt/step/step_wgt_create_storage_directories.h | 77 +++
src/wgt/step/step_wgt_resource_directory.cc | 44 ++
src/wgt/step/step_wgt_resource_directory.h | 62 +++
src/wgt/wgt_app_query_interface.cc | 101 ++++
src/wgt/wgt_app_query_interface.h | 33 ++
src/wgt/wgt_backend.cc | 23 +
src/wgt/wgt_backend_data.h | 47 ++
src/wgt/wgt_installer.cc | 179 +++++++
src/wgt/wgt_installer.h | 31 ++
67 files changed, 4370 insertions(+), 2 deletions(-)
create mode 100644 CMakeLists.txt
create mode 100644 cmake/Modules/ApplyPkgConfig.cmake
create mode 100644 packaging/wgt-backend-tests.manifest
create mode 100644 packaging/wgt-backend.manifest
create mode 100644 src/CMakeLists.txt
create mode 100644 src/unit_tests/CMakeLists.txt
create mode 100644 src/unit_tests/smoke_test.cc
create mode 100644 src/unit_tests/test_samples/smoke/DeinstallationMode.wgt
create mode 100644 src/unit_tests/test_samples/smoke/DeinstallationMode_Rollback.wgt
create mode 100644 src/unit_tests/test_samples/smoke/DeltaMode.delta
create mode 100644 src/unit_tests/test_samples/smoke/DeltaMode.wgt
create mode 100644 src/unit_tests/test_samples/smoke/InstallationMode.wgt
create mode 100644 src/unit_tests/test_samples/smoke/InstallationMode_GoodSignature.wgt
create mode 100644 src/unit_tests/test_samples/smoke/InstallationMode_Rollback.wgt
create mode 100644 src/unit_tests/test_samples/smoke/InstallationMode_WrongSignature.wgt
create mode 100644 src/unit_tests/test_samples/smoke/RDSMode.wgt
create mode 100644 src/unit_tests/test_samples/smoke/RecoveryMode_ForInstallation.wgt
create mode 100644 src/unit_tests/test_samples/smoke/RecoveryMode_ForUpdate.wgt
create mode 100644 src/unit_tests/test_samples/smoke/RecoveryMode_ForUpdate_2.wgt
create mode 100644 src/unit_tests/test_samples/smoke/UpdateMode.wgt
create mode 100644 src/unit_tests/test_samples/smoke/UpdateMode_2.wgt
create mode 100644 src/unit_tests/test_samples/smoke/UpdateMode_Rollback.wgt
create mode 100644 src/unit_tests/test_samples/smoke/UpdateMode_Rollback_2.wgt
create mode 100644 src/unit_tests/test_samples/smoke/delta_dir/.rds_delta
create mode 100644 src/unit_tests/test_samples/smoke/delta_dir/ADDED
create mode 100644 src/unit_tests/test_samples/smoke/delta_dir/MODIFIED
create mode 100644 src/unit_tests/test_samples/smoke/delta_dir/config.xml
create mode 100644 src/wgt/CMakeLists.txt
create mode 100644 src/wgt/rds_parser.cc
create mode 100644 src/wgt/rds_parser.h
create mode 100644 src/wgt/step/step_add_default_privileges.cc
create mode 100644 src/wgt/step/step_add_default_privileges.h
create mode 100644 src/wgt/step/step_check_settings_level.cc
create mode 100644 src/wgt/step/step_check_settings_level.h
create mode 100644 src/wgt/step/step_check_wgt_background_category.cc
create mode 100644 src/wgt/step/step_check_wgt_background_category.h
create mode 100644 src/wgt/step/step_create_symbolic_link.cc
create mode 100644 src/wgt/step/step_create_symbolic_link.h
create mode 100644 src/wgt/step/step_encrypt_resources.cc
create mode 100644 src/wgt/step/step_encrypt_resources.h
create mode 100644 src/wgt/step/step_generate_xml.cc
create mode 100644 src/wgt/step/step_generate_xml.h
create mode 100644 src/wgt/step/step_parse.cc
create mode 100644 src/wgt/step/step_parse.h
create mode 100644 src/wgt/step/step_parse_recovery.cc
create mode 100644 src/wgt/step/step_parse_recovery.h
create mode 100644 src/wgt/step/step_rds_modify.cc
create mode 100644 src/wgt/step/step_rds_modify.h
create mode 100644 src/wgt/step/step_rds_parse.cc
create mode 100644 src/wgt/step/step_rds_parse.h
create mode 100644 src/wgt/step/step_remove_encryption_data.cc
create mode 100644 src/wgt/step/step_remove_encryption_data.h
create mode 100644 src/wgt/step/step_wgt_copy_storage_directories.cc
create mode 100644 src/wgt/step/step_wgt_copy_storage_directories.h
create mode 100644 src/wgt/step/step_wgt_create_icons.cc
create mode 100644 src/wgt/step/step_wgt_create_icons.h
create mode 100644 src/wgt/step/step_wgt_create_storage_directories.cc
create mode 100644 src/wgt/step/step_wgt_create_storage_directories.h
create mode 100644 src/wgt/step/step_wgt_resource_directory.cc
create mode 100644 src/wgt/step/step_wgt_resource_directory.h
create mode 100644 src/wgt/wgt_app_query_interface.cc
create mode 100644 src/wgt/wgt_app_query_interface.h
create mode 100644 src/wgt/wgt_backend.cc
create mode 100644 src/wgt/wgt_backend_data.h
create mode 100644 src/wgt/wgt_installer.cc
create mode 100644 src/wgt/wgt_installer.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..565d531
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,48 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
+PROJECT(WgtBackend)
+SET(PREFIX "${CMAKE_INSTALL_PREFIX}")
+SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
+SET(LIBDIR "${CMAKE_INSTALL_LIBDIR}")
+SET(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share")
+SET(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
+SET(VERSION_MAJOR 0)
+SET(VERSION "${VERSION_MAJOR}.1.0")
+
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE "Release")
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+# Compiler flags
+SET(CMAKE_C_FLAGS_PROFILING "-O2")
+SET(CMAKE_CXX_FLAGS_PROFILING "-O2 -std=c++11")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -std=c++11 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -std=c++11 -g")
+SET(CMAKE_CXX_FLAGS_CCOV "-O0 -std=c++11 -g --coverage")
+
+# Targets
+SET(TARGET_LIBNAME_WGT "wgt-installer")
+SET(TARGET_WGT_BACKEND "wgt-backend")
+SET(TARGET_SMOKE_TEST "smoke_test")
+
+ADD_DEFINITIONS("-Wall")
+ADD_DEFINITIONS("-Wextra")
+ADD_DEFINITIONS("-fPIE")
+ADD_DEFINITIONS("-fPIC")
+
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
+INCLUDE(FindPkgConfig)
+INCLUDE(ApplyPkgConfig)
+
+# Find all needed packages once
+PKG_CHECK_MODULES(APP_INSTALLERS_DEPS REQUIRED app-installers)
+PKG_CHECK_MODULES(MANIFEST_HANDLERS_DEPS REQUIRED manifest-handlers)
+PKG_CHECK_MODULES(MANIFEST_PARSER_DEPS REQUIRED manifest-parser)
+PKG_CHECK_MODULES(PKGMGR_INSTALLER_DEPS REQUIRED pkgmgr-installer)
+PKG_CHECK_MODULES(ENCRYPTION_DEPS REQUIRED libwebappenc)
+
+FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options)
+FIND_PACKAGE(GTest REQUIRED)
+
+ADD_SUBDIRECTORY(src)
diff --git a/cmake/Modules/ApplyPkgConfig.cmake b/cmake/Modules/ApplyPkgConfig.cmake
new file mode 100644
index 0000000..97679d7
--- /dev/null
+++ b/cmake/Modules/ApplyPkgConfig.cmake
@@ -0,0 +1,35 @@
+# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#
+# This function applies external (out of source tree) dependencies
+# to given target. Arguments are:
+# TARGET - valid cmake target
+# PRIVACY - dependency can be inherited by dependent targets or not:
+# PUBLIC - this should be used by default, cause compile/link flags passing
+# PRIVATE - do not passes any settings to dependent targets,
+# may be usefull for static libraries from the inside of the project
+# Argument ARGV2 and following are supposed to be names of checked pkg config
+# packages. This function will use variables created by check_pkg_modules().
+# - ${DEP_NAME}_LIBRARIES
+# - ${DEP_NAME}_INCLUDE_DIRS
+# - ${DEP_NAME}_CFLAGS
+#
+FUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY)
+ MATH(EXPR DEST_INDEX "${ARGC}-1")
+ FOREACH(I RANGE 2 ${DEST_INDEX})
+ IF(NOT ${ARGV${I}}_FOUND)
+ MESSAGE(FATAL_ERROR "Not found dependency - ${ARGV${I}}_FOUND")
+ ENDIF(NOT ${ARGV${I}}_FOUND)
+ TARGET_LINK_LIBRARIES(${TARGET} ${PRIVACY} "${${ARGV${I}}_LIBRARIES}")
+ TARGET_INCLUDE_DIRECTORIES(${TARGET} ${PRIVACY} SYSTEM "${${ARGV${I}}_INCLUDE_DIRS}")
+ STRING(REPLACE ";" " " CFLAGS_STR "${${ARGV${I}}_CFLAGS}")
+ SET(CFLAGS_LIST ${CFLAGS_STR})
+ SEPARATE_ARGUMENTS(CFLAGS_LIST)
+ FOREACH(OPTION ${CFLAGS_LIST})
+ TARGET_COMPILE_OPTIONS(${TARGET} ${PRIVACY} ${OPTION})
+ ENDFOREACH(OPTION)
+ SET_TARGET_PROPERTIES(${TARGET} PROPERTIES SKIP_BUILD_RPATH true)
+ ENDFOREACH(I RANGE 2 ${DEST_INDEX})
+ENDFUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY)
diff --git a/packaging/wgt-backend-tests.manifest b/packaging/wgt-backend-tests.manifest
new file mode 100644
index 0000000..6c0eb4f
--- /dev/null
+++ b/packaging/wgt-backend-tests.manifest
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/packaging/wgt-backend.manifest b/packaging/wgt-backend.manifest
new file mode 100644
index 0000000..55125da
--- /dev/null
+++ b/packaging/wgt-backend.manifest
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec
index 3c17083..9c001e1 100644
--- a/packaging/wgt-backend.spec
+++ b/packaging/wgt-backend.spec
@@ -9,9 +9,59 @@ Group: Application Framework/Package Management
License: Apache-2.0
Source0: %{name}-%{version}.tar.gz
+Source1000: wgt-backend.manifest
+Source1001: wgt-backend-tests.manifest
+
+BuildRequires: boost-devel
+BuildRequires: cmake
+BuildRequires: gtest-devel
+BuildRequires: pkgconfig(app-installers)
+BuildRequires: pkgconfig(manifest-parser)
+BuildRequires: pkgconfig(manifest-handlers)
+BuildRequires: pkgconfig(pkgmgr-installer)
+BuildRequires: pkgconfig(libwebappenc)
+
+%description
+This is a package that installs the WGT backend of pkgmgr.
+
+%package tests
+Summary: Unit tests for wgt-backend
+Requires: %{name} = %{version}
+
+%description tests
+Unit tests for wgt-backend
+
+%prep
+%setup -q
+
+cp %{SOURCE1000} .
+cp %{SOURCE1001} .
+
+%build
+#Variable for setting symlink to runtime
+runtime_path=%{_bindir}/xwalk-launcher
+%if "%{profile}" == "mobile" || "%{profile}" == "wearable" || "%{profile}" == "tv"
+runtime_path=%{_bindir}/wrt
+%endif
+%cmake . -DCMAKE_BUILD_TYPE=%{?build_type:%build_type} -DWRT_LAUNCHER=${runtime_path}
+make %{?_smp_mflags}
+
+%install
+%make_install
+mkdir -p %{buildroot}/etc/package-manager/backend
+ln -s %{_bindir}/wgt-backend %{buildroot}%{_sysconfdir}/package-manager/backend/wgt
+
+%files
+%manifest wgt-backend.manifest
+%license LICENSE
+%{_sysconfdir}/package-manager/backend/wgt
+%{_bindir}/wgt-backend
+
+%files tests
+%manifest wgt-backend-tests.manifest
+%{_bindir}/wgt-backend-ut/*
+%{_datadir}/wgt-backend-ut/*
%changelog
* Thu Dec 18 2015 Pawel Sikorski 0.1-1
- initial files creation
-
-
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..f0e3653
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,2 @@
+ADD_SUBDIRECTORY(wgt)
+ADD_SUBDIRECTORY(unit_tests)
diff --git a/src/unit_tests/CMakeLists.txt b/src/unit_tests/CMakeLists.txt
new file mode 100644
index 0000000..9c92d11
--- /dev/null
+++ b/src/unit_tests/CMakeLists.txt
@@ -0,0 +1,22 @@
+SET(DESTINATION_DIR wgt-backend-ut)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+# Executables
+ADD_EXECUTABLE(${TARGET_SMOKE_TEST}
+ smoke_test.cc
+)
+
+INSTALL(DIRECTORY test_samples/ DESTINATION ${SHAREDIR}/${DESTINATION_DIR}/test_samples)
+
+APPLY_PKG_CONFIG(smoke_test PUBLIC
+ Boost
+ GTEST
+)
+
+# FindGTest module do not sets all needed libraries in GTEST_LIBRARIES and
+# GTest main libraries is still missing, so additional linking of
+# GTEST_MAIN_LIBRARIES is needed.
+target_link_libraries(smoke_test PRIVATE ${TARGET_LIBNAME_WGT} ${GTEST_MAIN_LIBRARIES})
+
+INSTALL(TARGETS smoke_test DESTINATION ${BINDIR}/${DESTINATION_DIR})
diff --git a/src/unit_tests/smoke_test.cc b/src/unit_tests/smoke_test.cc
new file mode 100644
index 0000000..38f8e33
--- /dev/null
+++ b/src/unit_tests/smoke_test.cc
@@ -0,0 +1,473 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "wgt/wgt_app_query_interface.h"
+#include "wgt/wgt_installer.h"
+
+#define SIZEOFARRAY(ARR) \
+ sizeof(ARR) / sizeof(ARR[0]) \
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
+namespace {
+
+const char kApplicationDir[] = ".applications";
+const char kApplicationDirBackup[] = ".applications.bck";
+const char KUserAppsDir[] = "apps_rw";
+const char KUserAppsDirBackup[] = "apps_rw.bck";
+
+enum class RequestResult {
+ NORMAL,
+ FAIL,
+ CRASH
+};
+
+class StepCrash : public ci::Step {
+ public:
+ using Step::Step;
+
+ ci::Step::Status process() override {
+ raise(SIGSEGV);
+ return Status::OK;
+ }
+ ci::Step::Status clean() override { return ci::Step::Status::OK; }
+ ci::Step::Status undo() override { return ci::Step::Status::OK; }
+ ci::Step::Status precheck() override { return ci::Step::Status::OK; }
+};
+
+void RemoveAllRecoveryFiles() {
+ bf::path root_path = ci::GetRootAppPath();
+ for (auto& dir_entry : boost::make_iterator_range(
+ bf::directory_iterator(root_path), bf::directory_iterator())) {
+ if (bf::is_regular_file(dir_entry)) {
+ if (dir_entry.path().string().find("/recovery") != std::string::npos) {
+ bs::error_code error;
+ bf::remove(dir_entry.path(), error);
+ }
+ }
+ }
+}
+
+bf::path FindRecoveryFile() {
+ bf::path root_path = ci::GetRootAppPath();
+ for (auto& dir_entry : boost::make_iterator_range(
+ bf::directory_iterator(root_path), bf::directory_iterator())) {
+ if (bf::is_regular_file(dir_entry)) {
+ if (dir_entry.path().string().find("/recovery") != std::string::npos) {
+ return dir_entry.path();
+ }
+ }
+ }
+ return {};
+}
+
+bool ValidateFileContentInPackage(const std::string& pkgid,
+ const std::string& relative,
+ const std::string& expected) {
+ bf::path root_path = ci::GetRootAppPath();
+ bf::path file_path = root_path / pkgid / relative;
+ if (!bf::exists(file_path)) {
+ LOG(ERROR) << file_path << " doesn't exist";
+ return false;
+ }
+ FILE* handle = fopen(file_path.c_str(), "r");
+ if (!handle) {
+ LOG(ERROR) << file_path << " cannot be open";
+ return false;
+ }
+ std::string content;
+ std::array buffer;
+ while (fgets(buffer.data(), buffer.size(), handle)) {
+ content += buffer.data();
+ }
+ fclose(handle);
+ return content == expected;
+}
+
+void ValidatePackageFS(const std::string& pkgid, const std::string& appid) {
+ bf::path root_path = ci::GetRootAppPath();
+ bf::path package_path = root_path / pkgid;
+ bf::path binary_path = package_path / "bin" / appid;
+ bf::path data_path = package_path / "data";
+ bf::path shared_path = package_path / "shared";
+ bf::path cache_path = package_path / "cache";
+ ASSERT_TRUE(bf::exists(root_path));
+ ASSERT_TRUE(bf::exists(package_path));
+ ASSERT_TRUE(bf::exists(binary_path));
+ ASSERT_TRUE(bf::exists(data_path));
+ ASSERT_TRUE(bf::exists(shared_path));
+ ASSERT_TRUE(bf::exists(cache_path));
+
+ bf::path manifest_path =
+ bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
+ bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
+ ASSERT_TRUE(bf::exists(manifest_path));
+ ASSERT_TRUE(bf::exists(icon_path));
+
+ bf::path widget_root_path = package_path / "res" / "wgt";
+ bf::path config_path = widget_root_path / "config.xml";
+ ASSERT_TRUE(bf::exists(widget_root_path));
+ ASSERT_TRUE(bf::exists(config_path));
+
+ bf::path private_tmp_path = package_path / "tmp";
+ ASSERT_TRUE(bf::exists(private_tmp_path));
+
+ // backups should not exist
+ bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
+ bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
+ bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
+ ASSERT_FALSE(bf::exists(package_backup));
+ ASSERT_FALSE(bf::exists(manifest_backup));
+ ASSERT_FALSE(bf::exists(icon_backup));
+}
+
+void PackageCheckCleanup(const std::string& pkgid, const std::string& appid) {
+ bf::path root_path = ci::GetRootAppPath();
+ bf::path package_path = root_path / pkgid;
+ ASSERT_FALSE(bf::exists(package_path));
+
+ bf::path manifest_path =
+ bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
+ bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
+ ASSERT_FALSE(bf::exists(manifest_path));
+ ASSERT_FALSE(bf::exists(icon_path));
+
+ // backups should not exist
+ bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
+ bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
+ bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
+ ASSERT_FALSE(bf::exists(package_backup));
+ ASSERT_FALSE(bf::exists(manifest_backup));
+ ASSERT_FALSE(bf::exists(icon_backup));
+}
+
+void ValidatePackage(const std::string& pkgid, const std::string& appid) {
+ ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
+ ValidatePackageFS(pkgid, appid);
+}
+
+void CheckPackageNonExistance(const std::string& pkgid,
+ const std::string& appid) {
+ ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
+ PackageCheckCleanup(pkgid, appid);
+}
+
+std::unique_ptr CreateQueryInterface() {
+ std::unique_ptr query_interface(
+ new wgt::WgtAppQueryInterface());
+ return query_interface;
+}
+
+std::unique_ptr CreateInstaller(ci::PkgMgrPtr pkgmgr) {
+ std::unique_ptr installer(new wgt::WgtInstaller(pkgmgr));
+ return installer;
+}
+
+ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
+ RequestResult mode) {
+ std::unique_ptr installer = CreateInstaller(pkgmgr);
+ switch (mode) {
+ case RequestResult::FAIL:
+ installer->AddStep();
+ break;
+ case RequestResult::CRASH:
+ installer->AddStep();
+ default:
+ break;
+ }
+ return installer->Run();
+}
+
+ci::AppInstaller::Result Install(const bf::path& path,
+ RequestResult mode = RequestResult::NORMAL) {
+ const char* argv[] = {"", "-i", path.c_str()};
+ std::unique_ptr query_interface =
+ CreateQueryInterface();
+ auto pkgmgr =
+ ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast(argv),
+ query_interface.get());
+ if (!pkgmgr) {
+ LOG(ERROR) << "Failed to initialize pkgmgr interface";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+ci::AppInstaller::Result Update(const bf::path& path_old,
+ const bf::path& path_new,
+ RequestResult mode = RequestResult::NORMAL) {
+ if (Install(path_old) != ci::AppInstaller::Result::OK) {
+ LOG(ERROR) << "Failed to install application. Cannot update";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ return Install(path_new, mode);
+}
+
+ci::AppInstaller::Result Uninstall(const std::string& pkgid,
+ RequestResult mode = RequestResult::NORMAL) {
+ const char* argv[] = {"", "-d", pkgid.c_str()};
+ std::unique_ptr query_interface =
+ CreateQueryInterface();
+ auto pkgmgr =
+ ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast(argv),
+ query_interface.get());
+ if (!pkgmgr) {
+ LOG(ERROR) << "Failed to initialize pkgmgr interface";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+ci::AppInstaller::Result Reinstall(const bf::path& path,
+ const bf::path& delta_dir,
+ RequestResult mode = RequestResult::NORMAL) {
+ if (Install(path) != ci::AppInstaller::Result::OK) {
+ LOG(ERROR) << "Failed to install application. Cannot perform RDS";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ const char* argv[] = {"", "-r", delta_dir.c_str()};
+ std::unique_ptr query_interface =
+ CreateQueryInterface();
+ auto pkgmgr =
+ ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast(argv),
+ query_interface.get());
+ if (!pkgmgr) {
+ LOG(ERROR) << "Failed to initialize pkgmgr interface";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+ci::AppInstaller::Result DeltaInstall(const bf::path& path,
+ const bf::path& delta_package) {
+ if (Install(path) != ci::AppInstaller::Result::OK) {
+ LOG(ERROR) << "Failed to install application. Cannot perform RDS";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ return Install(delta_package);
+}
+
+ci::AppInstaller::Result Recover(const bf::path& recovery_file,
+ RequestResult mode = RequestResult::NORMAL) {
+ const char* argv[] = {"", "-e", recovery_file.c_str()};
+ std::unique_ptr query_interface =
+ CreateQueryInterface();
+ auto pkgmgr =
+ ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast(argv),
+ query_interface.get());
+ if (!pkgmgr) {
+ LOG(ERROR) << "Failed to initialize pkgmgr interface";
+ return ci::AppInstaller::Result::UNKNOWN;
+ }
+ return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+} // namespace
+
+namespace common_installer {
+
+class SmokeEnvironment : public testing::Environment {
+ public:
+ explicit SmokeEnvironment(const bf::path& home) : home_(home) {
+ }
+ void SetUp() override {
+ bs::error_code error;
+ bf::remove_all(home_ / kApplicationDirBackup, error);
+ bf::remove_all(home_ / KUserAppsDirBackup, error);
+ if (bf::exists(home_ / KUserAppsDir)) {
+ bf::rename(home_ / KUserAppsDir, home_ / KUserAppsDirBackup, error);
+ assert(!error);
+ }
+ if (bf::exists(home_ / kApplicationDir)) {
+ bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
+ assert(!error);
+ }
+ }
+ void TearDown() override {
+ bs::error_code error;
+ bf::remove_all(home_ / kApplicationDir, error);
+ bf::remove_all(home_ / KUserAppsDir, error);
+ if (bf::exists(home_ / KUserAppsDirBackup))
+ bf::rename(home_ / KUserAppsDirBackup, home_ / KUserAppsDir, error);
+ if (bf::exists(home_ / kApplicationDirBackup))
+ bf::rename(home_ / kApplicationDirBackup, home_ / kApplicationDir, error);
+ }
+
+ private:
+ bf::path home_;
+};
+
+class SmokeTest : public testing::Test {
+};
+
+TEST_F(SmokeTest, InstallationMode) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode.wgt"; // NOLINT
+ std::string pkgid = "smokeapp03";
+ std::string appid = "smokeapp03.InstallationMode";
+ ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, appid);
+}
+
+TEST_F(SmokeTest, UpdateMode) {
+ bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode.wgt"; // NOLINT
+ bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_2.wgt"; // NOLINT
+ std::string pkgid = "smokeapp04";
+ std::string appid = "smokeapp04.UpdateMode";
+ ASSERT_EQ(Update(path_old, path_new), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, appid);
+
+ ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "2\n"));
+}
+
+TEST_F(SmokeTest, DeinstallationMode) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeinstallationMode.wgt"; // NOLINT
+ std::string pkgid = "smokeapp05";
+ std::string appid = "smokeapp05.DeinstallationMode";
+ ASSERT_EQ(Install(path),
+ ci::AppInstaller::Result::OK);
+ ASSERT_EQ(Uninstall(pkgid), ci::AppInstaller::Result::OK);
+ CheckPackageNonExistance(pkgid, appid);
+}
+
+TEST_F(SmokeTest, RDSMode) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/RDSMode.wgt"; // NOLINT
+ std::string delta_directory = "/usr/share/app-installers-ut/test_samples/smoke/delta_dir/"; // NOLINT
+ std::string pkgid = "smokeapp11";
+ std::string appid = "smokeapp11.RDSMode";
+ ASSERT_EQ(Reinstall(path, delta_directory),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, appid);
+
+ // Check delta modifications
+ bf::path root_path = ci::GetRootAppPath();
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
+ ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
+ ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "2\n");
+}
+
+TEST_F(SmokeTest, DeltaMode) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeltaMode.wgt"; // NOLINT
+ std::string delta_package = "/usr/share/app-installers-ut/test_samples/smoke/DeltaMode.delta"; // NOLINT
+ std::string pkgid = "smokeapp17";
+ std::string appid = "smokeapp17.DeltaMode";
+ ASSERT_EQ(DeltaInstall(path, delta_package),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, appid);
+
+ // Check delta modifications
+ bf::path root_path = ci::GetRootAppPath();
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "DELETED"));
+ ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "ADDED"));
+ ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "css" / "style.css")); // NOLINT
+ ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "images" / "tizen_32.png")); // NOLINT
+ ASSERT_TRUE(bf::exists(root_path / pkgid / "res" / "wgt" / "js" / "main.js"));
+ ValidateFileContentInPackage(pkgid, "res/wgt/MODIFIED", "version 2\n");
+}
+
+TEST_F(SmokeTest, RecoveryMode_ForInstallation) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_ForInstallation.wgt"; // NOLINT
+ ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
+
+ std::string pkgid = "smokeapp09";
+ std::string appid = "smokeapp09.RecoveryModeForInstallation";
+ bf::path recovery_file = FindRecoveryFile();
+ ASSERT_FALSE(recovery_file.empty());
+ ASSERT_EQ(Recover(recovery_file),
+ ci::AppInstaller::Result::OK);
+ CheckPackageNonExistance(pkgid, appid);
+}
+
+TEST_F(SmokeTest, RecoveryMode_ForUpdate) {
+ bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_ForUpdate.wgt"; // NOLINT
+ bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_ForUpdate_2.wgt"; // NOLINT
+ RemoveAllRecoveryFiles();
+ ASSERT_DEATH(Update(path_old, path_new, RequestResult::CRASH), ".*");
+
+ std::string pkgid = "smokeapp10";
+ std::string appid = "smokeapp10.RecoveryModeForUpdate";
+ bf::path recovery_file = FindRecoveryFile();
+ ASSERT_FALSE(recovery_file.empty());
+ ASSERT_EQ(Recover(recovery_file),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, appid);
+
+ ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
+}
+
+TEST_F(SmokeTest, InstallationMode_GoodSignature) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_GoodSignature.wgt"; // NOLINT
+ ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
+}
+
+TEST_F(SmokeTest, InstallationMode_WrongSignature) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_WrongSignature.wgt"; // NOLINT
+ ASSERT_EQ(Install(path), ci::AppInstaller::Result::ERROR);
+}
+
+TEST_F(SmokeTest, InstallationMode_Rollback) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_Rollback.wgt"; // NOLINT
+ std::string pkgid = "smokeapp06";
+ std::string appid = "smokeapp06.InstallationModeRollback";
+ ASSERT_EQ(Install(path, RequestResult::FAIL),
+ ci::AppInstaller::Result::ERROR);
+ CheckPackageNonExistance(pkgid, appid);
+}
+
+TEST_F(SmokeTest, UpdateMode_Rollback) {
+ bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_Rollback.wgt"; // NOLINT
+ bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_Rollback_2.wgt"; // NOLINT
+ std::string pkgid = "smokeapp07";
+ std::string appid = "smokeapp07.UpdateModeRollback";
+ ASSERT_EQ(Update(path_old, path_new, RequestResult::FAIL),
+ ci::AppInstaller::Result::ERROR);
+ ValidatePackage(pkgid, appid);
+
+ ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n"));
+}
+
+TEST_F(SmokeTest, DeinstallationMode_Rollback) {
+ bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeinstallationMode_Rollback.wgt"; // NOLINT
+ std::string pkgid = "smokeapp08";
+ std::string appid = "smokeapp08.DeinstallationModeRollback";
+ ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
+ ASSERT_EQ(Uninstall(pkgid, RequestResult::FAIL),
+ ci::AppInstaller::Result::ERROR);
+ ValidatePackage(pkgid, appid);
+}
+
+} // namespace common_installer
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ const char* directory = getenv("HOME");
+ if (!directory) {
+ LOG(ERROR) << "Cannot get $HOME value";
+ return 1;
+ }
+ testing::AddGlobalTestEnvironment(
+ new common_installer::SmokeEnvironment(directory));
+ return RUN_ALL_TESTS();
+}
diff --git a/src/unit_tests/test_samples/smoke/DeinstallationMode.wgt b/src/unit_tests/test_samples/smoke/DeinstallationMode.wgt
new file mode 100644
index 0000000000000000000000000000000000000000..bf5b7d09b866ae23921708bc071ffe32536cb8cc
GIT binary patch
literal 33312
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
egx4!dORJ>p=~%BDFL<-^~#hcLj4vi
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