From c7185f7c2c62e74b9940bf0d8e7a6bee3a7fdc1c Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Thu, 16 Oct 2014 19:16:20 +0200 Subject: [PATCH] Move smack_access and access_provider to ckm test. Change-Id: I5098846a2edcb7597252f2ab08444f6428c73cc7 --- tests/ckm/CMakeLists.txt | 5 ++-- tests/ckm/access_provider2.cpp | 53 +++++++++++++++++++++++++++++++++++++++ tests/ckm/access_provider2.h | 47 ++++++++++++++++++++++++++++++++++ tests/ckm/capi-access_control.cpp | 22 ++++++++-------- tests/ckm/capi-testcases.cpp | 20 +++++++-------- tests/ckm/ckm-common.cpp | 6 ++--- tests/ckm/main.cpp | 50 ++++++++++++++++++------------------ 7 files changed, 152 insertions(+), 51 deletions(-) create mode 100644 tests/ckm/access_provider2.cpp create mode 100644 tests/ckm/access_provider2.h diff --git a/tests/ckm/CMakeLists.txt b/tests/ckm/CMakeLists.txt index 29855b4..a813b7b 100644 --- a/tests/ckm/CMakeLists.txt +++ b/tests/ckm/CMakeLists.txt @@ -31,6 +31,7 @@ PKG_CHECK_MODULES(CKM_DEP SET(TARGET_CKM_TESTS "ckm-tests") SET(CKM_SOURCES + ${PROJECT_SOURCE_DIR}/tests/ckm/access_provider2.cpp ${PROJECT_SOURCE_DIR}/tests/ckm/main.cpp ${PROJECT_SOURCE_DIR}/tests/ckm/capi-testcases.cpp ${PROJECT_SOURCE_DIR}/tests/ckm/capi-access_control.cpp @@ -39,8 +40,8 @@ SET(CKM_SOURCES ) INCLUDE_DIRECTORIES(SYSTEM ${CKM_DEP_INCLUDE_DIRS}) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tests/common/ - ${PROJECT_SOURCE_DIR}/tests/ckm/) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tests/common/ ) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tests/ckm/ ) ADD_EXECUTABLE(${TARGET_CKM_TESTS} ${CKM_SOURCES}) diff --git a/tests/ckm/access_provider2.cpp b/tests/ckm/access_provider2.cpp new file mode 100644 index 0000000..20e88da --- /dev/null +++ b/tests/ckm/access_provider2.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ +/* + * @file access_provider.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Common functions and macros used in security-tests package. + */ +#include +#include +#include + +#include + +#include + +AccessProvider::AccessProvider(const std::string &mySubject) + : m_mySubject(mySubject) +{} + +void AccessProvider::allowAPI(const std::string &api, const std::string &rule) { + m_smackAccess.add(m_mySubject, api, rule); +} + +void AccessProvider::apply() { + m_smackAccess.apply(); +} + +void AccessProvider::applyAndSwithToUser(int uid, int gid) { + RUNNER_ASSERT_MSG(0 == smack_revoke_subject(m_mySubject.c_str()), + "Error in smack_revoke_subject(" << m_mySubject << ")"); + apply(); + RUNNER_ASSERT_MSG(0 == smack_set_label_for_self(m_mySubject.c_str()), + "Error in smack_set_label_for_self."); + RUNNER_ASSERT_MSG(0 == setgid(gid), + "Error in setgid."); + RUNNER_ASSERT_MSG(0 == setuid(uid), + "Error in setuid."); +} + diff --git a/tests/ckm/access_provider2.h b/tests/ckm/access_provider2.h new file mode 100644 index 0000000..0b846f0 --- /dev/null +++ b/tests/ckm/access_provider2.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ +/* + * @file access_provider.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Common functions and macros used in security-tests package. + */ +#ifndef _ACCESS_FOR_DUMMIES_H_ +#define _ACCESS_FOR_DUMMIES_H_ + +#include + +#include + +class AccessProvider { +public: + AccessProvider(const std::string &mySubject); + + AccessProvider(const AccessProvider &second) = delete; + AccessProvider& operator=(const AccessProvider &second) = delete; + + void allowAPI(const std::string &api, const std::string &rules); + void apply(); + void applyAndSwithToUser(int uid, int gid); + + virtual ~AccessProvider(){} +private: + std::string m_mySubject; + SmackAccess m_smackAccess; +}; + +#endif // _ACCESS_FOR_DUMMIES_H_ + diff --git a/tests/ckm/capi-access_control.cpp b/tests/ckm/capi-access_control.cpp index 9c37a66..c0a6149 100644 --- a/tests/ckm/capi-access_control.cpp +++ b/tests/ckm/capi-access_control.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -32,7 +33,6 @@ const char* TEST_LABEL2 = "test-label2"; const char* TEST_DATA = "dsflsdkghkslhglrtghierhgilrehgidsafasdffsgfdgdgfdgfdgfdgfdggf"; - void save_data(const char* alias) { ckmc_raw_buffer_s buffer; @@ -190,17 +190,17 @@ RUNNER_TEST(T3000_init) // invalid arguments check RUNNER_TEST(T3001_manager_allow_access_invalid) { - RUNNER_ASSERT_BT( + RUNNER_ASSERT( CKMC_ERROR_INVALID_PARAMETER == ckmc_allow_access(NULL, "accessor", CKMC_AR_READ)); - RUNNER_ASSERT_BT( + RUNNER_ASSERT( CKMC_ERROR_INVALID_PARAMETER == ckmc_allow_access("alias", NULL, CKMC_AR_READ)); } // invalid arguments check RUNNER_TEST(T3002_manager_deny_access_invalid) { - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access(NULL, "accessor")); - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access("alias", NULL)); + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access(NULL, "accessor")); + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access("alias", NULL)); } // tries to allow access for non existing alias @@ -397,21 +397,21 @@ RUNNER_TEST(T3101_control_allow_access_invalid) { int ret; ret = ckmc_allow_access_by_adm(USER_ROOT, NULL, "alias", "accessor", CKMC_AR_READ); - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == ret); + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ret); ret = ckmc_allow_access_by_adm(USER_ROOT, "owner", NULL, "accessor", CKMC_AR_READ); - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == ret); + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ret); ret = ckmc_allow_access_by_adm(USER_ROOT, "owner", "alias", NULL, CKMC_AR_READ); - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == ret); + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ret); } // invalid argument check RUNNER_TEST(T3102_control_deny_access_invalid) { - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access_by_adm(USER_ROOT, NULL, "alias", "accessor")); - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access_by_adm(USER_ROOT, "owner", NULL, "accessor")); - RUNNER_ASSERT_BT(CKMC_ERROR_INVALID_PARAMETER == + RUNNER_ASSERT(CKMC_ERROR_INVALID_PARAMETER == ckmc_deny_access_by_adm(USER_ROOT, "owner", "alias", NULL)); } diff --git a/tests/ckm/capi-testcases.cpp b/tests/ckm/capi-testcases.cpp index ab523a0..5f6bd49 100644 --- a/tests/ckm/capi-testcases.cpp +++ b/tests/ckm/capi-testcases.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -368,7 +368,7 @@ RUNNER_TEST(T3025_certificate_list_C_API) RUNNER_CHILD_TEST(T3026_user_app_save_key_C_API) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -417,7 +417,7 @@ RUNNER_CHILD_TEST(T3026_user_app_save_key_C_API) RUNNER_CHILD_TEST(T3027_app_user_save_keys_exportable_flag) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -718,7 +718,7 @@ RUNNER_TEST(T3042_save_get_bin_data_C_API) RUNNER_CHILD_TEST(T3043_app_user_save_bin_data_C_API) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -837,7 +837,7 @@ RUNNER_CHILD_TEST(T3052_CAPI_create_rsa_key) { int temp; - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2278,7 +2278,7 @@ RUNNER_TEST_GROUP_INIT(T3000_CAPI_LOCKTYPE_TESTS); RUNNER_CHILD_TEST(T3101_CAPI_init_lock_key) { int tmp; - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2293,7 +2293,7 @@ RUNNER_CHILD_TEST(T3101_CAPI_init_lock_key) RUNNER_CHILD_TEST(T3102_CAPI_unlock_default_passwd) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2343,7 +2343,7 @@ RUNNER_CHILD_TEST(T3102_CAPI_unlock_default_passwd) RUNNER_CHILD_TEST(T3103_CAPI_init_change_user_password) { int tmp; - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2358,7 +2358,7 @@ RUNNER_CHILD_TEST(T3103_CAPI_init_change_user_password) RUNNER_CHILD_TEST(T3104_CAPI_unlock_default_passwd_negative) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2404,7 +2404,7 @@ RUNNER_CHILD_TEST(T3104_CAPI_unlock_default_passwd_negative) RUNNER_CHILD_TEST(T3109_CAPI_deinit) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); } diff --git a/tests/ckm/ckm-common.cpp b/tests/ckm/ckm-common.cpp index daa7f58..c3753d3 100644 --- a/tests/ckm/ckm-common.cpp +++ b/tests/ckm/ckm-common.cpp @@ -22,19 +22,19 @@ #include #include #include -#include +#include #include void switch_to_storage_user(const char* label) { - SecurityServer::AccessProvider ap(label); + AccessProvider ap(label); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(APP_UID, APP_GID); } void switch_to_storage_ocsp_user(const char* label) { - SecurityServer::AccessProvider ap(label); + AccessProvider ap(label); ap.allowAPI("key-manager::api-storage", "rw"); ap.allowAPI("key-manager::api-ocsp", "rw"); ap.applyAndSwithToUser(APP_UID, APP_GID); diff --git a/tests/ckm/main.cpp b/tests/ckm/main.cpp index 98df3c7..61bfbda 100644 --- a/tests/ckm/main.cpp +++ b/tests/ckm/main.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -191,7 +191,7 @@ RUNNER_TEST(T1012_certificate) RUNNER_CHILD_TEST(T1013_user_app_save_key) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -294,7 +294,7 @@ RUNNER_TEST(T1021_save_keys_get_alias) RUNNER_CHILD_TEST(T1022_app_user_save_keys_get_alias) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -334,7 +334,7 @@ RUNNER_CHILD_TEST(T1022_app_user_save_keys_get_alias) RUNNER_CHILD_TEST(T1023_app_user_save_keys_exportable_flag) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -445,7 +445,7 @@ RUNNER_TEST(T1031_save_get_bin_data) RUNNER_CHILD_TEST(T1032_app_user_save_bin_data) { - SecurityServer::AccessProvider ap("mylabel"); + AccessProvider ap("mylabel"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -547,7 +547,7 @@ RUNNER_CHILD_TEST(T1041_create_rsa_key) auto manager = CKM::Manager::create(); CKM::AliasVector av; - SecurityServer::AccessProvider ap("mylabel-rsa"); + AccessProvider ap("mylabel-rsa"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -568,7 +568,7 @@ RUNNER_CHILD_TEST(T1042_create_dsa_key) auto manager = CKM::Manager::create(); CKM::AliasVector av; - SecurityServer::AccessProvider ap("mylabel-dsa"); + AccessProvider ap("mylabel-dsa"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2272,7 +2272,7 @@ RUNNER_TEST_GROUP_INIT(T151_CKM_STORAGE_PERNAMENT_TESTS); RUNNER_CHILD_TEST(T1510_init_unlock_key) { int tmp; - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_TEST, GROUP_APP); @@ -2284,7 +2284,7 @@ RUNNER_CHILD_TEST(T1510_init_unlock_key) RUNNER_CHILD_TEST(T1511_init_insert_data) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST, GROUP_APP); @@ -2378,7 +2378,7 @@ RUNNER_CHILD_TEST(T1511_init_insert_data) RUNNER_CHILD_TEST(T1519_deinit) { int tmp; - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2394,7 +2394,7 @@ RUNNER_TEST_GROUP_INIT(T161_CKM_LOCKTYPE_TESTS); RUNNER_CHILD_TEST(T1610_init_lock_key) { int tmp; - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2409,7 +2409,7 @@ RUNNER_CHILD_TEST(T1610_init_lock_key) RUNNER_CHILD_TEST(T1611_unlock_default_passwd) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2448,7 +2448,7 @@ RUNNER_CHILD_TEST(T1611_unlock_default_passwd) RUNNER_CHILD_TEST(T1612_init_change_user_password) { int tmp; - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2463,7 +2463,7 @@ RUNNER_CHILD_TEST(T1612_init_change_user_password) RUNNER_CHILD_TEST(T1613_unlock_default_passwd_negative) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); @@ -2498,7 +2498,7 @@ RUNNER_CHILD_TEST(T1613_unlock_default_passwd_negative) RUNNER_CHILD_TEST(T1619_deinit) { - SecurityServer::AccessProvider ap("my-label"); + AccessProvider ap("my-label"); ap.allowAPI("key-manager::api-control", "rw"); ap.applyAndSwithToUser(USER_APP, GROUP_APP); } @@ -2517,7 +2517,7 @@ RUNNER_TEST(T1701_init_unlock_key) RUNNER_CHILD_TEST(T1702_init_insert_data) { int temp; - SecurityServer::AccessProvider ap("t170-special-label"); + AccessProvider ap("t170-special-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+1, GROUP_APP); @@ -2587,7 +2587,7 @@ RUNNER_TEST(T1703_removeApplicationData) RUNNER_CHILD_TEST(T1704_data_test) { int temp; - SecurityServer::AccessProvider ap("t170-special-label"); + AccessProvider ap("t170-special-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+1, GROUP_APP); @@ -2644,7 +2644,7 @@ RUNNER_TEST(T17101_init) RUNNER_CHILD_TEST(T17102_prep_data_01) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label"); + AccessProvider ap("t1706-special-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+2, GROUP_APP); @@ -2664,7 +2664,7 @@ RUNNER_CHILD_TEST(T17102_prep_data_01) RUNNER_CHILD_TEST(T17103_prep_data_02) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label2"); + AccessProvider ap("t1706-special-label2"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+2, GROUP_APP); @@ -2684,7 +2684,7 @@ RUNNER_CHILD_TEST(T17103_prep_data_02) RUNNER_CHILD_TEST(T17104_prep_data_03) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label"); + AccessProvider ap("t1706-special-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+3, GROUP_APP); @@ -2704,7 +2704,7 @@ RUNNER_CHILD_TEST(T17104_prep_data_03) RUNNER_CHILD_TEST(T17105_prep_data_04) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label2"); + AccessProvider ap("t1706-special-label2"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+3, GROUP_APP); @@ -2737,7 +2737,7 @@ RUNNER_TEST(T17106_remove_application) RUNNER_CHILD_TEST(T17107_check_data_01) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label"); + AccessProvider ap("t1706-special-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+2, GROUP_APP); @@ -2755,7 +2755,7 @@ RUNNER_CHILD_TEST(T17107_check_data_01) RUNNER_CHILD_TEST(T17108_check_data_02) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label2"); + AccessProvider ap("t1706-special-label2"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+2, GROUP_APP); @@ -2783,7 +2783,7 @@ RUNNER_TEST(T17109_unlock_user2) RUNNER_CHILD_TEST(T17110_check_data_03) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label"); + AccessProvider ap("t1706-special-label"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+3, GROUP_APP); @@ -2801,7 +2801,7 @@ RUNNER_CHILD_TEST(T17110_check_data_03) RUNNER_CHILD_TEST(T17111_check_data_04) { int temp; - SecurityServer::AccessProvider ap("t1706-special-label2"); + AccessProvider ap("t1706-special-label2"); ap.allowAPI("key-manager::api-storage", "rw"); ap.applyAndSwithToUser(USER_TEST+3, GROUP_APP); -- 2.7.4