From: Krzysztof Jackiewicz Date: Thu, 16 Apr 2015 10:17:53 +0000 (+0200) Subject: Merging tizen into ckm. Stage 3. X-Git-Tag: security-manager_5.5_testing~9^2~95 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F21%2F38321%2F1;hp=2cae7d239635c99bb67421a5b1b3f0e326c034fd;p=platform%2Fcore%2Ftest%2Fsecurity-tests.git Merging tizen into ckm. Stage 3. Merged remote-tracking branch 'tizen.org/tizen' into ckm Change-Id: Iffa2e26113f653cf4c6f685bc7e4dc7d25472ae5 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 99f65e4..8b76681 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,3 +86,4 @@ SET(COMMON_TARGET_TEST "tests-common") ############################# subdirectories ################################## ADD_SUBDIRECTORY(src) +ADD_SUBDIRECTORY(tests) diff --git a/README b/README index 87a2bed..c946fe7 100644 --- a/README +++ b/README @@ -26,6 +26,10 @@ security-manager cynara cynara-test +There are also inner-tests for testing complex security-tests framework +mechanisms with binary: + security-tests-inner-test + ==HOW TO RUN=================================================================== Each test suite may be run with options: @@ -152,6 +156,25 @@ dpl-test-framework RUNNER_ERROR_MSG Print error message using red color. +--Defer macros----------------------------------------------------------------- +Used to defer throwing TestException exceptions (TestFailed, TestIgnored) +by catching them and rethrowing later. This mechanism can help in breaking +test and passing test result from places where throwing exceptions +is not allowed + +dpl-test-framework + test_runner.h + RUNNER_DEFER_TRYCATCH + Catches thrown TestException exceptions and stores them in TestRunner + structures for later use. This macro works only inside deffered scope + defined by RUNNER_DEFER_SCOPE, otherwise it won't catch exceptions + RUNNER_DEFER_SCOPE + Defines deferred scope. All RUNNER_DEFER_TRYCATCH macros used inside + the scope catch and save TestException exceptions. After scope is left + all saved exceptions take part in setting result of test. If there + is no any uncaught exception then additionally first of saved + exceptions is thrown. + --Collectors------------------------------------------------------------------- Collectors are classes which collect test results. Each class does it differently. Collectors can be registered by --output parameter (see HOW TO RUN section) but diff --git a/packaging/security-tests.spec b/packaging/security-tests.spec index 8b561ac..fac0fe8 100644 --- a/packaging/security-tests.spec +++ b/packaging/security-tests.spec @@ -59,13 +59,13 @@ make %{?jobs:-j%jobs} ln -sf /etc/smack/test_smack_rules %{buildroot}/etc/smack/test_smack_rules_lnk %post -%{_bindir}/gum-utils --add-user --username=security-tests-app --usertype=4 --offline +%{_bindir}/gum-utils --add-user --username=security-tests-app --usertype=normal --offline find /etc/smack/test_privilege_control_DIR/ -type f -name exec -exec chmod 0755 {} + find /usr/apps/test_DIR/ -type f -name exec -exec chmod 0755 {} + # Load permissions templates -api_feature_loader --verbose --clear-permissions +api_feature_loader --verbose # Set vconf key for cc-mode testing if vconf key isn't there. %if "%{sec_product_feature_security_mdfpp_enable}" != "1" @@ -118,3 +118,4 @@ echo "security-tests postinst done ..." /usr/lib/security-tests/cynara-tests/plugins/single-policy/* /usr/lib/security-tests/cynara-tests/plugins/multiple-policy/* /usr/lib/security-tests/cynara-tests/plugins/test-agent/* +/usr/bin/security-tests-inner-test diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 11a444f..fcfc13f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -20,6 +20,10 @@ SET(COMMON_TARGET_TEST_SOURCES ${PROJECT_SOURCE_DIR}/src/common/memory.cpp ${PROJECT_SOURCE_DIR}/src/common/db_sqlite.cpp ${PROJECT_SOURCE_DIR}/src/common/fs_label_manager.cpp + ${PROJECT_SOURCE_DIR}/src/common/passwd_access.cpp + ${PROJECT_SOURCE_DIR}/src/common/uds.cpp + ${PROJECT_SOURCE_DIR}/src/common/synchronization_pipe.cpp + ${PROJECT_SOURCE_DIR}/src/common/timeout.cpp ) #system and local includes diff --git a/src/common/db_sqlite.h b/src/common/db_sqlite.h index 9a17083..42092cf 100644 --- a/src/common/db_sqlite.h +++ b/src/common/db_sqlite.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2012-2015 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. @@ -115,14 +115,14 @@ public: * * If database is already opened do nothing. * - * @throw DPL::Test::TestRunner::TestFailed when opening database fails + * @throw DPL::Test::TestFailed when opening database fails */ void open(void); /** * @brief Close database. * - * @throw DPL::Test::TestRunner::TestFailed when closing database fails + * @throw DPL::Test::TestFailed when closing database fails */ void close(void); @@ -140,7 +140,7 @@ public: * @param sql_query SQL query * @param result returned result * - * @throw DPL::Test::TestRunner::TestFailed when execution of query fails + * @throw DPL::Test::TestFailed when execution of query fails */ void execute(const std::string& sql_query, Sqlite3DBaseSelectResult& result); diff --git a/src/common/passwd_access.cpp b/src/common/passwd_access.cpp new file mode 100644 index 0000000..6f55549 --- /dev/null +++ b/src/common/passwd_access.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 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 passwd_access.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Provides access to UID and GID + */ + +#include +#include +#include + +#include + +#include "passwd_access.h" + +namespace PasswdAccess { + uid_t uid(const std::string &username) { + struct passwd *passwd = nullptr; + do { + errno = 0; + passwd = getpwnam(username.c_str()); + } while (passwd == nullptr && errno == EINTR); + RUNNER_ASSERT_ERRNO_MSG(passwd != nullptr, "Error in getpwnam(). Username: " << username); + return passwd->pw_uid; + } + + gid_t gid(const std::string &groupname) { + struct group *group = nullptr; + do { + errno = 0; + group = getgrnam(groupname.c_str()); + } while (group == nullptr && errno == EINTR); + RUNNER_ASSERT_ERRNO_MSG(group != nullptr, "Error in getgrnam(). Groupname: " << groupname); + return group->gr_gid; + } +} // namespace PasswdAccess diff --git a/src/common/passwd_access.h b/src/common/passwd_access.h new file mode 100644 index 0000000..3638828 --- /dev/null +++ b/src/common/passwd_access.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 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 passwd_access.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Provides access to UID and GID + */ + +#ifndef TESTS_COMMON_PASSWD_ACCESS_H_ +#define TESTS_COMMON_PASSWD_ACCESS_H_ + +#include +#include + +namespace PasswdAccess { + uid_t uid(const std::string &username); + gid_t gid(const std::string &groupname); +} // namespace PasswdAccess + +#endif // TESTS_COMMON_PASSWD_ACCESS_H_ diff --git a/src/common/service_manager.cpp b/src/common/service_manager.cpp index 7321f77..5349171 100644 --- a/src/common/service_manager.cpp +++ b/src/common/service_manager.cpp @@ -54,7 +54,7 @@ ServiceManager::ServiceManager(const std::string &serviceName) addBusMatch(MATCH_RELOADING); m_connection.flush(); m_connection.addFilter(messageHandler, - reinterpret_cast(this)); + static_cast(this)); subscribeSignals(); m_connection.requestName(DBUS_CLIENT_NAME); getUnitPath(); @@ -190,7 +190,7 @@ void ServiceManager::sendResetFailedToService() DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t) { (void) conn; - ServiceManager* self = reinterpret_cast(t); + ServiceManager* self = static_cast(t); DBus::MessageIn messageIn(msg, true); if (messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_REMOVED)) diff --git a/src/common/synchronization_pipe.cpp b/src/common/synchronization_pipe.cpp new file mode 100644 index 0000000..dcf9d30 --- /dev/null +++ b/src/common/synchronization_pipe.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 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 synchronization_pipe.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief A crippled abstraction of widely praised, but often misused communication mechanism + */ + +#include +#include + +#include + +#include "synchronization_pipe.h" + +static void closeFd(int *fd) { + if (*fd > -1) { + close(*fd); + *fd = -1; + } +} + +SynchronizationPipe::SynchronizationPipe() { + auto ret = pipe(m_pipeCP); + RUNNER_ASSERT_ERRNO_MSG(ret == 0, "pipe failed"); + + ret = pipe(m_pipePC); + RUNNER_ASSERT_ERRNO_MSG(ret == 0, "pipe failed"); +} + +SynchronizationPipe::~SynchronizationPipe() { + closeFd(m_pipeCP + 0); + closeFd(m_pipeCP + 1); + closeFd(m_pipePC + 0); + closeFd(m_pipePC + 1); +} + +void SynchronizationPipe::claimParentEp() { + if (m_epClaimed) + return; + + m_readEp = m_pipeCP[0]; + closeFd(m_pipeCP + 1); + + m_writeEp = m_pipePC[1]; + closeFd(m_pipePC + 0); + + m_epClaimed = true; +} + +void SynchronizationPipe::claimChildEp() { + if (m_epClaimed) + return; + + m_readEp = m_pipePC[0]; + closeFd(m_pipePC + 1); + + m_writeEp = m_pipeCP[1]; + closeFd(m_pipeCP + 0); + + m_epClaimed = true; +} + +void SynchronizationPipe::post() { + RUNNER_ASSERT_MSG(m_epClaimed == true, "Endpoint not claimed"); + auto ret = TEMP_FAILURE_RETRY(write(m_writeEp, "#", 1)); + RUNNER_ASSERT_ERRNO_MSG(ret > 0, "Write failed ret = " << ret); +} + +void SynchronizationPipe::wait() { + RUNNER_ASSERT_MSG(m_epClaimed == true, "Endpoint not claimed"); + + char buf; + auto ret = TEMP_FAILURE_RETRY(read(m_readEp, &buf, 1)); + RUNNER_ASSERT_ERRNO_MSG(ret > 0, "Read failed ret = " << ret); +} diff --git a/src/common/synchronization_pipe.h b/src/common/synchronization_pipe.h new file mode 100644 index 0000000..e072ca2 --- /dev/null +++ b/src/common/synchronization_pipe.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 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 synchronization_pipe.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief A crippled abstraction of widely praised, but often misused communication mechanism + */ + +#ifndef TESTS_COMMON_SYNCHRONIZATION_PIPE_H_ +#define TESTS_COMMON_SYNCHRONIZATION_PIPE_H_ + +class SynchronizationPipe { +public: + SynchronizationPipe(); + ~SynchronizationPipe(); + + void claimParentEp(); + void claimChildEp(); + + void post(); + void wait(); + +private: + int m_pipeCP[2]; // Child -> Parent + int m_pipePC[2]; // Parent -> Child + int m_readEp = -1; + int m_writeEp = -1; + bool m_epClaimed = false; +}; + +#endif // TESTS_COMMON_SYNCHRONIZATION_PIPE_H_ diff --git a/src/common/timeout.cpp b/src/common/timeout.cpp new file mode 100644 index 0000000..c9e1347 --- /dev/null +++ b/src/common/timeout.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 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 timeout.cpp + * @author Lukasz Wojciechowski + * @brief Definition of future_status serialization operator + */ + +#include + +namespace Timeout { + +std::ostream& operator<<(std::ostream& os, const std::future_status &status) +{ + switch (status) { + case std::future_status::ready: + os << ""; + break; + case std::future_status::timeout: + os << ""; + break; + case std::future_status::deferred: + os << ""; + break; + } + os << " [" << static_cast(status) << "]"; + return os; +} + +} // namespace Timeout diff --git a/src/common/timeout.h b/src/common/timeout.h index 7e985ab..01ef862 100644 --- a/src/common/timeout.h +++ b/src/common/timeout.h @@ -25,18 +25,16 @@ #include #include #include +#include #include -#include +#include namespace Timeout { template using Timeout = std::chrono::duration; -template -using Function = std::function; - typedef std::function CancelFunction; enum ExpectMode { @@ -45,33 +43,17 @@ enum ExpectMode { IGNORE, }; -std::ostream& operator<<(std::ostream& os, const std::future_status &status) -{ - switch (status) { - case std::future_status::ready: - os << ""; - break; - case std::future_status::timeout: - os << ""; - break; - case std::future_status::deferred: - os << ""; - break; - } - os << " [" << static_cast(status) << "]"; - return os; -} +std::ostream& operator<<(std::ostream& os, const std::future_status &status); -template -Ret callAndWait(const Timeout &timeout, +template + typename std::result_of::type + callAndWait(const Timeout &timeout, ExpectMode expect, CancelFunction cancelFunction, - Function function, - Args... args) { - RUNNER_ASSERT_MSG(function, - "not empty function must be passed to callAndWait"); + F&& function, + Args&&... args) { - std::future fut = std::async(std::launch::async, function, std::forward(args)...); + auto fut = std::async(std::launch::async, function, std::forward(args)...); std::future_status status = fut.wait_for(timeout); if (status == std::future_status::timeout && cancelFunction) diff --git a/src/common/uds.cpp b/src/common/uds.cpp new file mode 100644 index 0000000..7523539 --- /dev/null +++ b/src/common/uds.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 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 uds.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Helpers for Unix Domain Sockets + */ + +#include +#include +#include +#include + +#include +#include + +#include "uds.h" + +namespace UDSHelpers { + +int createServer(const struct sockaddr_un *sockaddr) { + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + RUNNER_ASSERT_ERRNO_MSG(sock >= 0, "socket failed"); + + SockUniquePtr sockPtr(&sock); + + int bindResult = bind(sock, (const struct sockaddr*) sockaddr, sizeof(struct sockaddr_un)); + RUNNER_ASSERT_ERRNO_MSG(bindResult == 0, "bind failed"); + + int listenResult = listen(sock, 1); + RUNNER_ASSERT_ERRNO_MSG(listenResult == 0, "listen failed"); + + sockPtr.release(); + return sock; +} + +int createClient(const struct sockaddr_un *sockaddr) { + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + RUNNER_ASSERT_ERRNO_MSG(sock >= 0, "socket failed"); + + SockUniquePtr sockPtr(&sock); + + int connectResult = TEMP_FAILURE_RETRY( + connect(sock, (const struct sockaddr*) sockaddr, sizeof(struct sockaddr_un))); + RUNNER_ASSERT_ERRNO_MSG(connectResult == 0, "connect failed"); + + sockPtr.release(); + return sock; +} + +int acceptClient(int sock) { + int clientSock = TEMP_FAILURE_RETRY(accept(sock, NULL, NULL)); + RUNNER_ASSERT_ERRNO_MSG(clientSock >= 0, "accept failed"); + return clientSock; +} + +void waitForDisconnect(int sock) { + const nfds_t fdCount = 1; + const int timeout = -1; // no timeout + + struct pollfd pfd { sock, POLLRDHUP, 0 }; + int ret = TEMP_FAILURE_RETRY(poll(&pfd, fdCount, timeout)); + RUNNER_ASSERT_ERRNO_MSG(ret >= 0, "poll failed"); +} + +struct sockaddr_un makeAbstractAddress(const std::string &path) { + struct sockaddr_un sockaddr; + RUNNER_ASSERT_MSG(path.size() <= sizeof(sockaddr.sun_path) - 1, "Socket path too long"); + memset(&sockaddr, 0, sizeof(struct sockaddr_un)); + sockaddr.sun_family = AF_UNIX; + // Leave '\0' as a first character of path + memcpy(sockaddr.sun_path + 1, path.c_str(), path.size()); + return sockaddr; +} + +} // namespace UDSHelpers diff --git a/src/common/uds.h b/src/common/uds.h new file mode 100644 index 0000000..7af0631 --- /dev/null +++ b/src/common/uds.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 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 uds.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Helpers for Unix Domain Sockets + */ + +#ifndef TESTS_COMMON_UDS_H_ +#define TESTS_COMMON_UDS_H_ + +#include +#include + +namespace UDSHelpers { + int createServer(const struct sockaddr_un *sockaddr); + int createClient(const struct sockaddr_un *sockaddr); + int acceptClient(int sock); + void waitForDisconnect(int sock); + struct sockaddr_un makeAbstractAddress(const std::string &path); +}; + +#endif // TESTS_COMMON_UDS_H_ diff --git a/src/cynara-tests/CMakeLists.txt b/src/cynara-tests/CMakeLists.txt index cde27fe..1b275fd 100644 --- a/src/cynara-tests/CMakeLists.txt +++ b/src/cynara-tests/CMakeLists.txt @@ -46,6 +46,7 @@ SET(CYNARA_TARGET_TEST_SOURCES ${PROJECT_SOURCE_DIR}/src/cynara-tests/plugins/plugins.cpp ${PROJECT_SOURCE_DIR}/src/cynara-tests/cynara-test.cpp ${PROJECT_SOURCE_DIR}/src/cynara-tests/test_cases.cpp + ${PROJECT_SOURCE_DIR}/src/cynara-tests/test_cases_agent.cpp ${PROJECT_SOURCE_DIR}/src/cynara-tests/test_cases_async.cpp ${PROJECT_SOURCE_DIR}/src/cynara-tests/test_cases_db.cpp ) diff --git a/src/cynara-tests/common/cynara_test_agent.cpp b/src/cynara-tests/common/cynara_test_agent.cpp index 840d393..e2f408d 100644 --- a/src/cynara-tests/common/cynara_test_agent.cpp +++ b/src/cynara-tests/common/cynara_test_agent.cpp @@ -61,11 +61,13 @@ void Agent::getRequest(AgentRequest &request, int expectedResult) void Agent::putResponse(const AgentResponse &response, int expectedResult) { + auto size = response.data().size(); int ret = cynara_agent_put_response(m_agent, response.type(), response.id(), - reinterpret_cast(response.data().data()), - response.data().size()); + size ? static_cast(response.data().data()) + : nullptr, + size); RUNNER_ASSERT_MSG(ret == expectedResult, "cynara_agent_put_response returned wrong value: " diff --git a/src/cynara-tests/common/cynara_test_agent_request.cpp b/src/cynara-tests/common/cynara_test_agent_request.cpp index 52cb46a..821624e 100644 --- a/src/cynara-tests/common/cynara_test_agent_request.cpp +++ b/src/cynara-tests/common/cynara_test_agent_request.cpp @@ -39,7 +39,7 @@ void AgentRequest::set(cynara_agent_msg_type type, cynara_agent_req_id id, { m_type = type; m_id = id; - m_data = Cynara::PluginData(reinterpret_cast(data), dataSize); + m_data = Cynara::PluginData(static_cast(data), dataSize); m_client.clear(); m_user.clear(); m_privilege.clear(); diff --git a/src/cynara-tests/common/cynara_test_client_async_client.cpp b/src/cynara-tests/common/cynara_test_client_async_client.cpp index 3201f97..6c70813 100644 --- a/src/cynara-tests/common/cynara_test_client_async_client.cpp +++ b/src/cynara-tests/common/cynara_test_client_async_client.cpp @@ -52,8 +52,10 @@ CheckKey CheckData::toAdminPolicy() Client::Client(const StatusFunction &userFunction) : m_cynara(nullptr), m_statusMonitor(userFunction) { - int ret = cynara_async_initialize(&m_cynara, nullptr, StatusMonitor::updateStatus, - reinterpret_cast(&m_statusMonitor)); + int ret; + RUNNER_DEFER_SCOPE(ret = cynara_async_initialize(&m_cynara, nullptr, + StatusMonitor::updateStatus, + static_cast(&m_statusMonitor));); RUNNER_ASSERT_MSG(ret == CYNARA_API_SUCCESS, "cynara_async_initialize() failed. ret = " << ret << "."); RUNNER_ASSERT_MSG(m_cynara != nullptr, "cynara_async struct was not initialized."); @@ -65,7 +67,7 @@ Client::~Client() noexcept(false) { bool oops = std::uncaught_exception(); try { - cynara_async_finish(m_cynara); + RUNNER_DEFER_SCOPE(cynara_async_finish(m_cynara);); assertStatus(DISCONNECTED); } catch (...) { if (!oops) @@ -85,9 +87,11 @@ void Client::assertStatus(enum SocketStatus expectedStatus) void Client::checkCache(const CheckData &checkData, int expectedResult) { - int ret = cynara_async_check_cache(m_cynara, checkData.m_client.c_str(), - checkData.m_session.c_str(), checkData.m_user.c_str(), - checkData.m_privilege.c_str()); + int ret; + RUNNER_DEFER_SCOPE(ret = cynara_async_check_cache(m_cynara, checkData.m_client.c_str(), + checkData.m_session.c_str(), + checkData.m_user.c_str(), + checkData.m_privilege.c_str());); RUNNER_ASSERT_MSG(ret == expectedResult, "Cache check returned unexpected value: " << " returned value = " << ret << "," @@ -101,11 +105,14 @@ void Client::checkCache(const CheckData &checkData, int expectedResult) void Client::createRequest(const CheckData &checkData, cynara_check_id &id, const RequestEntity &callbackData, int expectedResult) { - int ret = cynara_async_create_request(m_cynara, checkData.m_client.c_str(), - checkData.m_session.c_str(), checkData.m_user.c_str(), - checkData.m_privilege.c_str(), &id, - RequestMonitor::updateResponse, - reinterpret_cast(&m_requestMonitor)); + int ret; + RUNNER_DEFER_SCOPE(ret = cynara_async_create_request(m_cynara, checkData.m_client.c_str(), + checkData.m_session.c_str(), + checkData.m_user.c_str(), + checkData.m_privilege.c_str(), &id, + RequestMonitor::updateResponse, + static_cast( + &m_requestMonitor));); if (ret == CYNARA_API_SUCCESS) m_requestMonitor.registerRequest(id, callbackData); @@ -140,19 +147,19 @@ void Client::process(int expectedResult, ret = TEMP_FAILURE_RETRY(select(fd + 1, &fds, &fds, NULL, &tv)); if (ret == 0) { - RUNNER_ASSERT_ERRNO_MSG(timeoutExpectation != EXPECT_NO_TIMEOUT, - "Unexpected select timeout." - << " ret = " << ret); + RUNNER_ASSERT_MSG(timeoutExpectation != EXPECT_NO_TIMEOUT, + "Unexpected select timeout." + << " ret = " << ret); return; } RUNNER_ASSERT_ERRNO_MSG(ret > 0, "Select returned error:" << " ret = " << ret); - RUNNER_ASSERT_ERRNO_MSG(timeoutExpectation != EXPECT_TIMEOUT, - "Select returned positive value, when timeout was expected." - << " ret = " << ret); + RUNNER_ASSERT_MSG(timeoutExpectation != EXPECT_TIMEOUT, + "Select returned positive value, when timeout was expected." + << " ret = " << ret); - ret = cynara_async_process(m_cynara); + RUNNER_DEFER_SCOPE(ret = cynara_async_process(m_cynara);); RUNNER_ASSERT_MSG(ret == expectedResult, "cynara_async_process returned unexpected value: " << " returned value = " << ret << "," @@ -161,7 +168,8 @@ void Client::process(int expectedResult, void Client::cancel(cynara_check_id id, int expectedResult) { - int ret = cynara_async_cancel_request(m_cynara, id); + int ret; + RUNNER_DEFER_SCOPE(ret = cynara_async_cancel_request(m_cynara, id);); RUNNER_ASSERT_MSG(ret == expectedResult, "Cancel request returned unexpected value: " << " returned value = " << ret << "," diff --git a/src/cynara-tests/common/cynara_test_client_async_request_monitor.cpp b/src/cynara-tests/common/cynara_test_client_async_request_monitor.cpp index ee08c7e..33244d0 100644 --- a/src/cynara-tests/common/cynara_test_client_async_request_monitor.cpp +++ b/src/cynara-tests/common/cynara_test_client_async_request_monitor.cpp @@ -53,48 +53,50 @@ void RequestMonitor::registerRequest(cynara_check_id id, const RequestEntity &re void RequestMonitor::updateResponse(cynara_check_id checkId, cynara_async_call_cause cause, int response, void *data) { - RequestMonitor *monitor = reinterpret_cast(data); - if (!monitor) { - RUNNER_FAIL_MSG("Bad user data (nullptr) in response callback."); - return; - } - - auto it = monitor->m_requests.find(checkId); - if (it == monitor->m_requests.end()) { - RUNNER_FAIL_MSG("Received unexpected callback for request:" - << "id = " << checkId << "," - << "response = " << response << "," - << "cause = " << cause << "."); - return; - } + RUNNER_DEFER_TRYCATCH( + RequestMonitor *monitor = static_cast(data); + if (!monitor) { + RUNNER_FAIL_MSG("Bad user data (nullptr) in response callback."); + return; + } - //save request data and remove request from monitored requests - auto expectedResponse = it->second.m_expectedResponse; - auto expectedCause = it->second.m_expectedCause; - auto userFunction = it->second.m_userFunction; - monitor->m_requests.erase(it); + auto it = monitor->m_requests.find(checkId); + if (it == monitor->m_requests.end()) { + RUNNER_FAIL_MSG("Received unexpected callback for request:" + << "id = " << checkId << "," + << "response = " << response << "," + << "cause = " << cause << "."); + return; + } - RUNNER_ASSERT_MSG(cause == expectedCause, - "Unexpected cause in response callback:" - << "id = " << checkId << "," - << "received response = " << response << "," - << "expected response = " << expectedResponse << "," - << "received cause = " << cause << "," - << "expected cause = " << expectedCause << "."); + //save request data and remove request from monitored requests + auto expectedResponse = it->second.m_expectedResponse; + auto expectedCause = it->second.m_expectedCause; + auto userFunction = it->second.m_userFunction; + monitor->m_requests.erase(it); - if (cause == CYNARA_CALL_CAUSE_ANSWER) - { - RUNNER_ASSERT_MSG(response == expectedResponse, - "Unexpected response in response callback:" + RUNNER_ASSERT_MSG(cause == expectedCause, + "Unexpected cause in response callback:" << "id = " << checkId << "," << "received response = " << response << "," << "expected response = " << expectedResponse << "," << "received cause = " << cause << "," << "expected cause = " << expectedCause << "."); - } - if (userFunction) - userFunction(); + if (cause == CYNARA_CALL_CAUSE_ANSWER) + { + RUNNER_ASSERT_MSG(response == expectedResponse, + "Unexpected response in response callback:" + << "id = " << checkId << "," + << "received response = " << response << "," + << "expected response = " << expectedResponse << "," + << "received cause = " << cause << "," + << "expected cause = " << expectedCause << "."); + } + + if (userFunction) + userFunction(); + ); } }// namespace CynaraTestClientAsync diff --git a/src/cynara-tests/common/cynara_test_client_async_status_monitor.cpp b/src/cynara-tests/common/cynara_test_client_async_status_monitor.cpp index 2a2e0ae..5246178 100644 --- a/src/cynara-tests/common/cynara_test_client_async_status_monitor.cpp +++ b/src/cynara-tests/common/cynara_test_client_async_status_monitor.cpp @@ -27,21 +27,23 @@ StatusMonitor::StatusMonitor(const StatusFunction &userFunction) void StatusMonitor::updateStatus(int oldFd, int newFd, cynara_async_status status, void *data) { - StatusMonitor *monitor = reinterpret_cast(data); - if (!monitor) { - RUNNER_FAIL_MSG("Bad user data (nullptr) in status callback."); - return; - } + RUNNER_DEFER_TRYCATCH( + StatusMonitor *monitor = static_cast(data); + if (!monitor) { + RUNNER_FAIL_MSG("Bad user data (nullptr) in status callback."); + return; + } - RUNNER_ASSERT_MSG(monitor->m_fd == oldFd, - "fd value mismatch: " - << " last saved fd = " << monitor->m_fd << "," - << " callback oldFd = " << oldFd << "."); + RUNNER_ASSERT_MSG(monitor->m_fd == oldFd, + "fd value mismatch: " + << " last saved fd = " << monitor->m_fd << "," + << " callback oldFd = " << oldFd << "."); - monitor->m_fd = newFd; - monitor->m_status = status; - if (monitor->m_userFunction) - monitor->m_userFunction(oldFd, newFd, status); + monitor->m_fd = newFd; + monitor->m_status = status; + if (monitor->m_userFunction) + monitor->m_userFunction(oldFd, newFd, status); + ); } int StatusMonitor::getFd(void) const diff --git a/src/cynara-tests/common/cynara_test_commons.cpp b/src/cynara-tests/common/cynara_test_commons.cpp index afeec79..8c2f5a1 100644 --- a/src/cynara-tests/common/cynara_test_commons.cpp +++ b/src/cynara-tests/common/cynara_test_commons.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include @@ -39,21 +39,19 @@ void environmentWrap(const char *testName, const std::function &func { CynaraTestEnv env(testName); env.save(); + env.loadDefaultDatabase(); try { func(); - } catch (const DPL::Test::TestRunner::TestFailed &e) { + } catch (const DPL::Test::TestException &e) { env.restore(); - throw e; - } catch (const DPL::Test::TestRunner::Ignored &e) { - env.restore(); - throw e; + throw; } catch (const DPL::Exception &e) { env.restore(); - throw e; + throw; } catch (const std::exception &e) { env.restore(); - throw e; + throw; } catch (...) { env.restore(); throw std::runtime_error("Unknown exception"); diff --git a/src/cynara-tests/common/cynara_test_env.cpp b/src/cynara-tests/common/cynara_test_env.cpp index 3185007..ba3350a 100644 --- a/src/cynara-tests/common/cynara_test_env.cpp +++ b/src/cynara-tests/common/cynara_test_env.cpp @@ -29,6 +29,7 @@ CynaraTestEnv::CynaraTestEnv(const char *dirName) m_saveDir = TMP_DIR + "/" + dirName; m_dbSaveDir = m_saveDir + "/db"; m_pluginsSaveDir = m_saveDir + "/plugins"; + m_defaultDir = "/etc/security-tests/db_patterns/default"; } CynaraTestEnv::~CynaraTestEnv() @@ -74,3 +75,13 @@ void CynaraTestEnv::restore() removeDirIfExists(m_pluginsSaveDir); removeDirIfExists(m_saveDir); } + +void CynaraTestEnv::loadDefaultDatabase() +{ + CynaraMask mask; + + if (m_dbPresent) { + removeDirFiles(CynaraTestConsts::DB_DIR); + copyCynaraFiles(m_defaultDir, CynaraTestConsts::DB_DIR); + } +} diff --git a/src/cynara-tests/common/cynara_test_env.h b/src/cynara-tests/common/cynara_test_env.h index 707e852..6c528f7 100644 --- a/src/cynara-tests/common/cynara_test_env.h +++ b/src/cynara-tests/common/cynara_test_env.h @@ -27,11 +27,13 @@ public: void save(); void restore(); + void loadDefaultDatabase(); private: std::string m_saveDir; std::string m_dbSaveDir; std::string m_pluginsSaveDir; + std::string m_defaultDir; bool m_dbPresent; }; diff --git a/src/cynara-tests/common/cynara_test_file_operations.cpp b/src/cynara-tests/common/cynara_test_file_operations.cpp index 0c27a26..1f7a5da 100644 --- a/src/cynara-tests/common/cynara_test_file_operations.cpp +++ b/src/cynara-tests/common/cynara_test_file_operations.cpp @@ -95,6 +95,9 @@ void copyCynaraFile(const std::string &src, const std::string &dst) ret = sendfile(outFd, inFd, 0, statSrc.st_size); RUNNER_ASSERT_ERRNO_MSG(ret != -1, "sendfile failed"); + + ret = fsync(outFd); + RUNNER_ASSERT_ERRNO_MSG(ret != -1, "fsync failed"); } void copyCynaraFiles(const std::string &source, const std::string &destination) @@ -114,12 +117,30 @@ void copyCynaraFiles(const std::string &source, const std::string &destination) std::string tempSrc = source + "/" + direntPtr->d_name; copyCynaraFile(tempSrc, tempDest); } + + syncDir(destination); +} + +void syncElem(const std::string &filename, int flags, mode_t mode) +{ + int fileFd = TEMP_FAILURE_RETRY(open(filename.c_str(), flags, mode)); + RUNNER_ASSERT_ERRNO_MSG(fileFd != -1, "open failed name=" << filename); + FdUniquePtr fdPtr(&fileFd); + + int ret = fsync(fileFd); + RUNNER_ASSERT_ERRNO_MSG(ret != -1, "fsync failed name=" << filename); +} + +void syncDir(const std::string &dirname, mode_t mode) { + syncElem(dirname, O_DIRECTORY, mode); } void makeDir(const std::string &directory) { RUNNER_ASSERT_ERRNO_MSG(!mkdir(directory.c_str(), S_IRWXU | S_IRWXG | S_IRWXO), "Unable to make " << directory << " test directory"); + + syncDir(directory); } void removeDirFiles(const std::string &dir) @@ -127,6 +148,8 @@ void removeDirFiles(const std::string &dir) int ret = nftw(dir.c_str(), removeFile, 2, FTW_DEPTH | FTW_PHYS); if (ret == -1) RUNNER_ASSERT_ERRNO_MSG(errno == ENOENT, "nftw failed"); + else + syncDir(dir); } void removeDirIfExists(const std::string &dir) diff --git a/src/cynara-tests/common/cynara_test_file_operations.h b/src/cynara-tests/common/cynara_test_file_operations.h index fae2e09..d3acdb8 100644 --- a/src/cynara-tests/common/cynara_test_file_operations.h +++ b/src/cynara-tests/common/cynara_test_file_operations.h @@ -17,6 +17,7 @@ #ifndef CYNARA_TEST_FILE_OPERATIONS_H #define CYNARA_TEST_FILE_OPERATIONS_H +#include #include namespace FileOperations @@ -25,6 +26,8 @@ namespace FileOperations bool dirExists(const std::string &directory); void copyCynaraFile(const std::string &src, const std::string &dst); void copyCynaraFiles(const std::string &source, const std::string &destination); +void syncElem(const std::string &filename, int flags = O_RDONLY, mode_t mode = S_IRUSR | S_IWUSR); +void syncDir(const std::string &dirname, mode_t mode = S_IRUSR | S_IWUSR); void makeDir(const std::string &directory); void removeDirFiles(const std::string &dir); void removeDirIfExists(const std::string &dir); diff --git a/src/cynara-tests/db_patterns/default/checksum b/src/cynara-tests/db_patterns/default/checksum new file mode 100644 index 0000000..9998a60 --- /dev/null +++ b/src/cynara-tests/db_patterns/default/checksum @@ -0,0 +1,2 @@ +buckets;$1$$6ZlVs5lw2nZgVmiw0BdY21 +_;$1$$qRPK7m23GJusamGpoGLby/ diff --git a/src/cynara-tests/db_patterns/defaultAllowed/checksum b/src/cynara-tests/db_patterns/defaultAllowed/checksum new file mode 100644 index 0000000..90c581c --- /dev/null +++ b/src/cynara-tests/db_patterns/defaultAllowed/checksum @@ -0,0 +1,2 @@ +buckets;$1$$UYHKvrIkGoSTO5hIgvCLg0 +_;$1$$qRPK7m23GJusamGpoGLby/ diff --git a/src/cynara-tests/db_patterns/nonEmptyDatabase/checksum b/src/cynara-tests/db_patterns/nonEmptyDatabase/checksum new file mode 100644 index 0000000..ebaaf4c --- /dev/null +++ b/src/cynara-tests/db_patterns/nonEmptyDatabase/checksum @@ -0,0 +1,2 @@ +buckets;$1$$6ZlVs5lw2nZgVmiw0BdY21 +_;$1$$nssatAXP6yl4N8gjldhxf0 diff --git a/src/cynara-tests/test_cases_agent.cpp b/src/cynara-tests/test_cases_agent.cpp new file mode 100644 index 0000000..51fab54 --- /dev/null +++ b/src/cynara-tests/test_cases_agent.cpp @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2015 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 test_cases_agent.cpp + * @author Lukasz Wojciechowski + * @author Radoslaw Bartosiak + * @version 1.0 + * @brief Tests for libcynara-agent + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace CynaraTestAdmin; +using namespace CynaraTestAgent; +using namespace CynaraTestClientAsync; +using namespace CynaraTestPlugins; + +void loadAgentPlugin() +{ + DirectoryPaths paths; + paths.push_back(TEST_PLUGIN_PATH + TEST_AGENT); + loadServicePlugins(paths); +} + +void setAgentPolicy(int expectedResult = CYNARA_API_SUCCESS) +{ + const char *bucket = CYNARA_ADMIN_DEFAULT_BUCKET; + const char *wildcard = CYNARA_ADMIN_WILDCARD; + const char *extra = nullptr; +// collection of policy descriptions defined by plugin that causes use of TestAgent + auto testAgentPolicies = POLICY_DESCRIPTIONS.at(TEST_AGENT); +// any policy type from above collection + auto policyType = testAgentPolicies[0].type; + + CynaraPoliciesContainer cp; + cp.add(bucket, wildcard, wildcard, wildcard, policyType, extra); + + Admin admin; + admin.setPolicies(cp, expectedResult); +} + +void restartCynara() +{ + ServiceManager serviceManager(CynaraTestConsts::SERVICE); + serviceManager.restartService(); +} + +void getAgentRequest(Agent &agent, AgentRequest &request, Client &client, + int expectedResult = CYNARA_API_SUCCESS, + Timeout::ExpectMode expectTimeoutMode = Timeout::ExpectMode::TIMEOUT) +{ + auto timeLimit = std::chrono::seconds(2); + auto hangOnGetRequest = [&agent, &request, &expectedResult]() { + agent.getRequest(request, expectedResult); + }; + Timeout::CancelFunction sendClientRequest = [&client]() { + client.process(); + client.assertStatus(READ); + }; + + Timeout::callAndWait(timeLimit, expectTimeoutMode, + sendClientRequest, hangOnGetRequest); +} + +void tcag01_set_agent_type_policy_without_plugin_func() +{ + loadServicePlugins(DirectoryPaths()); + setAgentPolicy(CYNARA_API_INVALID_PARAM); +} + +void tcag02_set_agent_type_policy_with_plugin_loaded_func() +{ + loadAgentPlugin(); + setAgentPolicy(); +} + +void tcag03_check_with_no_agent_func() +{ + std::string testNo("03"); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_DENIED, + CYNARA_CALL_CAUSE_ANSWER}; + + loadAgentPlugin(); + setAgentPolicy(); + + Client client; + client.createRequest({testNo}, id, callbackData); + client.assertStatus(READWRITE); + + //send requests + client.process(); + client.process(CYNARA_API_SUCCESS, Client::IGNORE_TIMEOUT); +} + +void tcag04_agent_initialize_func() +{ + Agent(); +} + +void tcag05_agent_request_timeout_func() +{ + Agent agent; + AgentRequest request; + + auto testTimeLimit = std::chrono::seconds(2); + auto hangOnGetRequest = [&agent, &request]() { + agent.getRequest(request, CYNARA_API_SERVICE_NOT_AVAILABLE); + }; + + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::TIMEOUT, + restartCynara, hangOnGetRequest); +} + +void tcag06_check_with_unregistered_agent_func() +{ + std::string testNo("06"); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_DENIED, + CYNARA_CALL_CAUSE_ANSWER}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + + Client client; + client.createRequest({testNo}, id, callbackData); + client.assertStatus(READWRITE); + + //send requests + client.process(); + client.process(CYNARA_API_SUCCESS, Client::IGNORE_TIMEOUT); +} + +void tcag07_get_request_func() +{ + std::string testNo("07"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_ALLOWED, + CYNARA_CALL_CAUSE_ANSWER}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequest; + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + + agentRequest.assertAction(data.m_client, data.m_user, data.m_privilege); + agent.putResponse(AgentResponse::createAllow(agentRequest.id())); + client.process(); +} + +void tcag08_get_request_and_respond_with_wrong_id_func() +{ + std::string testNo("08"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_SUCCESS, + CYNARA_CALL_CAUSE_FINISH}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequest; + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequest.assertAction(data.m_client, data.m_user, data.m_privilege); + agent.putResponse(AgentResponse::createAllow(agentRequest.id() + 1)); + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_TIMEOUT, 2); +} + +void tcag09_get_request_and_correct_responded_id_func() +{ + std::string testNo("09"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_ALLOWED, + CYNARA_CALL_CAUSE_ANSWER}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequest; + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequest.assertAction(data.m_client, data.m_user, data.m_privilege); + agent.putResponse(AgentResponse::createAllow(agentRequest.id() + 1)); + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_TIMEOUT, 2); + agent.putResponse(AgentResponse::createAllow(agentRequest.id())); + client.process(); +} + +void tcag10_cancel_request_func() +{ + std::string testNo("10"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_ALLOWED, + CYNARA_CALL_CAUSE_CANCEL}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequest; + + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequest.assertAction(data.m_client, data.m_user, data.m_privilege); + client.cancel(id); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequest.assertCancel(); + agent.putResponse(AgentResponse::createCancel(id)); + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_NO_TIMEOUT, 2); +} + +void tcag11_cancel_processed_request_func() +{ + std::string testNo("11"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_ALLOWED, + CYNARA_CALL_CAUSE_CANCEL}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequest; + + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequest.assertAction(data.m_client, data.m_user, data.m_privilege); + agent.putResponse(AgentResponse::createCancel(id)); + client.cancel(id); + // we do not expect getting the cancel request in the agent + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::TIMEOUT, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SERVICE_NOT_AVAILABLE, Timeout::ExpectMode::TIMEOUT); + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_NO_TIMEOUT, 2); +} + +void tcag12_create_two_requests_func() +{ + std::string testNo("12"); + CheckData data1(testNo, 1), data2(testNo, 2); + cynara_check_id id1, id2; + RequestEntity callbackData1 = {RequestFunction(), + CYNARA_API_ACCESS_DENIED, + CYNARA_CALL_CAUSE_ANSWER}; + RequestEntity callbackData2 = {RequestFunction(), + CYNARA_API_ACCESS_ALLOWED, + CYNARA_CALL_CAUSE_CANCEL}; + + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequest1, agentRequest2, agentRequest3; + Client client; + client.createRequest(data1, id1, callbackData1); + client.assertStatus(READWRITE); + client.createRequest(data2, id2, callbackData2); + client.assertStatus(READWRITE); + + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest1), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest2), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::IGNORE); + client.cancel(id2); + client.assertStatus(READWRITE); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), std::ref(agentRequest3), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequest1.assertAction(data1.m_client, data1.m_user, data1.m_privilege); + agentRequest2.assertAction(data2.m_client, data2.m_user, data2.m_privilege); + agentRequest3.assertCancel(); + + agent.putResponse(AgentResponse::createDeny(id1)); + agent.putResponse(AgentResponse::createCancel(id2)); + + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_NO_TIMEOUT, 3); + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::IGNORE_TIMEOUT, 1); +} + +void tcag13_create_many_requests_func() +{ + const int numberOfRequests = 4; + std::string testNo("13"); + cynara_check_id ids[numberOfRequests]; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_DENIED, + CYNARA_CALL_CAUSE_ANSWER}; + loadAgentPlugin(); + setAgentPolicy(); + + Agent agent; + AgentRequest agentRequests[numberOfRequests]; + Client client; + for (int i = 0; i < numberOfRequests; i++) { + CheckData data(testNo, i); + client.createRequest(data, ids[i], callbackData); + client.assertStatus(READWRITE); + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, restartCynara, + getAgentRequest, std::ref(agent), std::ref(agentRequests[i]), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + agentRequests[i].assertAction(data.m_client, data.m_user, data.m_privilege); + }; + for (int i = numberOfRequests - 1; i >= 0; i--) { + agent.putResponse(AgentResponse::createDeny(ids[i])); + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_NO_TIMEOUT, 2); + } +} + +void tcag14_client_disconnects_func() +{ + std::string testNo("14"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_ALLOWED, + CYNARA_CALL_CAUSE_FINISH}; + + loadAgentPlugin(); + setAgentPolicy(); + Agent agent; + AgentRequest agentRequest; + auto testTimeLimit = std::chrono::seconds(5); + { + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequest, std::ref(agent), + std::ref(agentRequest), std::ref(client), + CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + }; + auto getAgentRequestWrap = [&agent, &agentRequest]() { + agent.getRequest(agentRequest, CYNARA_API_SUCCESS); + }; + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, + restartCynara, getAgentRequestWrap); + agentRequest.assertCancel(); +} + +void tcag15_agent_disconnects_func() +{ + std::string testNo("15"); + CheckData data(testNo); + cynara_check_id id; + RequestEntity callbackData = {RequestFunction(), + CYNARA_API_ACCESS_DENIED, + CYNARA_CALL_CAUSE_ANSWER}; + + loadAgentPlugin(); + setAgentPolicy(); + Client client; + client.createRequest(data, id, callbackData); + client.assertStatus(READWRITE); + AgentRequest agentRequest; + { + Agent agent; + auto testTimeLimit = std::chrono::seconds(5); + Timeout::callAndWait(testTimeLimit, Timeout::ExpectMode::FINISHED, restartCynara, + getAgentRequest, std::ref(agent), std::ref(agentRequest), + std::ref(client), CYNARA_API_SUCCESS, Timeout::ExpectMode::TIMEOUT); + }; + client.process(CYNARA_API_SUCCESS, Client::TimeoutExpectation::EXPECT_NO_TIMEOUT, 2); +} + +RUNNER_TEST_GROUP_INIT(cynara_agent_tests) + +RUN_CYNARA_TEST(tcag01_set_agent_type_policy_without_plugin) +RUN_CYNARA_TEST(tcag02_set_agent_type_policy_with_plugin_loaded) +RUN_CYNARA_TEST(tcag03_check_with_no_agent) +RUN_CYNARA_TEST(tcag04_agent_initialize) +RUN_CYNARA_TEST(tcag05_agent_request_timeout) +RUN_CYNARA_TEST(tcag06_check_with_unregistered_agent) +RUN_CYNARA_TEST(tcag07_get_request) +RUN_CYNARA_TEST(tcag08_get_request_and_respond_with_wrong_id) +RUN_CYNARA_TEST(tcag09_get_request_and_correct_responded_id) +RUN_CYNARA_TEST(tcag10_cancel_request) +RUN_CYNARA_TEST(tcag11_cancel_processed_request) +RUN_CYNARA_TEST(tcag12_create_two_requests) +RUN_CYNARA_TEST(tcag13_create_many_requests) +RUN_CYNARA_TEST(tcag14_client_disconnects) +RUN_CYNARA_TEST(tcag15_agent_disconnects) diff --git a/src/cynara-tests/test_cases_db.cpp b/src/cynara-tests/test_cases_db.cpp index 6fe3202..16b3d91 100644 --- a/src/cynara-tests/test_cases_db.cpp +++ b/src/cynara-tests/test_cases_db.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -51,6 +51,7 @@ const std::string defDbAllow("defaultAllowed"); const std::string nonEmptyDb("nonEmptyDatabase"); const std::string cynaraTestPatternsPath("/etc/security-tests/db_patterns/"); const std::string directoryWildcard("/*"); +const char directorySeparator('/'); void createDbFile(const std::string &filename) { @@ -108,19 +109,63 @@ size_t db_files_count(const std::string &source) { return dbFilesCount; } +const std::set dump_glob_filenames(const glob_t &globbuf) { + std::set set; + + for (unsigned i = 0; i < globbuf.gl_pathc; ++i) { + std::string filename(globbuf.gl_pathv[i]); + set.insert(filename.substr(filename.find_last_of(directorySeparator)+1)); + } + + return set; +} + +const std::set glob_filenames(const std::string &source, const std::string &wildcard) { + //for finding files matching pattern in directory + glob_t globbuf; + std::string pattern = source + wildcard; + + //for freeing allocated memory + GlobPtr globbufPtr(&globbuf); + + //actually find files matching pattern in directory - including dotfiles + RUNNER_ASSERT_MSG(0 == glob(pattern.c_str(), GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf), + "Failed to search for requested pathnames in " << source << "."); + + return dump_glob_filenames(globbuf); +} + +const std::set db_files_pathnames(const std::string &source) { + return glob_filenames(source, directoryWildcard); +} + +std::ostream& operator<<(std::ostream& os, const std::set &set) +{ + os << "{"; + for (const auto &item : set) { + os << " " << item; + } + os << " }"; + return os; +} + void compareDbs(const std::string &source) { //for accessing files in directory std::string patternDir = cynaraTestPatternsPath + source; + std::string resultDir = CynaraTestConsts::DB_DIR; DIR *patternDirPtr = nullptr; struct dirent *direntPtr; size_t patternFileCount = db_files_count(patternDir); - size_t resultFileCount = db_files_count(CynaraTestConsts::DB_DIR); + size_t resultFileCount = db_files_count(resultDir); //directories do not match if there is different number of files RUNNER_ASSERT_MSG(patternFileCount == resultFileCount, - "No match in database and pattern directory file count"); + "No match in database and pattern directory file count: " + << resultFileCount << " != " << patternFileCount << "." << std::endl + << "Expected: " << db_files_pathnames(patternDir) << std::endl + << "Actual: " << db_files_pathnames(resultDir)); //compare files in database directory with pattern directory RUNNER_ASSERT_ERRNO_MSG(patternDirPtr = opendir(patternDir.c_str()), @@ -131,12 +176,12 @@ void compareDbs(const std::string &source) if (!strcmp(direntPtr->d_name, ".") || !strcmp(direntPtr->d_name, "..")) continue; - std::string patternName = patternDir + "/" + direntPtr->d_name; - std::string resultName = CynaraTestConsts::DB_DIR + "/" + direntPtr->d_name; + std::string patternName = patternDir + directorySeparator + direntPtr->d_name; + std::string resultName = CynaraTestConsts::DB_DIR + directorySeparator + direntPtr->d_name; //comparing file saved db dir with reference file from patterns dir RUNNER_ASSERT_MSG(true == unordered_files_match(patternName, resultName), - "No match in stored file and pattern file"); + "No match in stored file and pattern file: " << resultName); } } @@ -160,7 +205,7 @@ void tcdb01_lockdown_init_failure_func() const char *bucket = CYNARA_ADMIN_DEFAULT_BUCKET; const char *extra = nullptr; - const auto fakeBackupGuard = CynaraTestConsts::DB_DIR + "/guard"; + const auto fakeBackupGuard = CynaraTestConsts::DB_DIR + directorySeparator + "guard"; createDbFile(fakeBackupGuard); admin.setBucket(bucket, CYNARA_ADMIN_ALLOW, extra, CYNARA_API_OPERATION_FAILED); @@ -190,7 +235,7 @@ void tcdb02_write_to_backup_failure_func() const char *bucket = CYNARA_ADMIN_DEFAULT_BUCKET; const char *extra = nullptr; - const auto fakeBucketDumpFile = CynaraTestConsts::DB_DIR + "/_~"; + const auto fakeBucketDumpFile = CynaraTestConsts::DB_DIR + directorySeparator + "_~"; admin.setBucket(bucket, CYNARA_ADMIN_ALLOW, extra); compareDbs(defDbAllow); @@ -221,7 +266,7 @@ void tcdb03_invalid_and_valid_backup_removal_func() const char *bucket = CYNARA_ADMIN_DEFAULT_BUCKET; const char *extra = nullptr; - const auto defaultBucketDumpFile = CynaraTestConsts::DB_DIR + "/_~"; + const auto defaultBucketDumpFile = CynaraTestConsts::DB_DIR + directorySeparator + "_~"; createDbFile(defaultBucketDumpFile); admin.setBucket(bucket, CYNARA_ADMIN_ALLOW, extra, CYNARA_API_OPERATION_FAILED); @@ -280,7 +325,7 @@ void tcdb05_non_indexed_files_removal_func() "some-file-that-doesnt-belong-here" }; for (const auto &filename : filenames) { - auto garbageFilename = CynaraTestConsts::DB_DIR + "/" + filename; + auto garbageFilename = CynaraTestConsts::DB_DIR + directorySeparator + filename; createDbFile(garbageFilename); } diff --git a/src/framework/config.cmake b/src/framework/config.cmake index 411f09e..72b3d2c 100644 --- a/src/framework/config.cmake +++ b/src/framework/config.cmake @@ -32,6 +32,7 @@ SET(DPL_FRAMEWORK_TEST_SOURCES ${PROJECT_SOURCE_DIR}/src/framework/src/dlog_log_provider.cpp ${PROJECT_SOURCE_DIR}/src/framework/src/log.cpp ${PROJECT_SOURCE_DIR}/src/framework/src/old_style_log_provider.cpp + ${PROJECT_SOURCE_DIR}/src/framework/src/test_failed.cpp ${PROJECT_SOURCE_DIR}/src/framework/src/test_results_collector.cpp ${PROJECT_SOURCE_DIR}/src/framework/src/test_results_collector_commons.cpp ${PROJECT_SOURCE_DIR}/src/framework/src/test_results_collector_console.cpp diff --git a/src/framework/include/dpl/test/performance_result.h b/src/framework/include/dpl/test/performance_result.h new file mode 100644 index 0000000..f15c0da --- /dev/null +++ b/src/framework/include/dpl/test/performance_result.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015 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 performance_result.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief Header file with declaration of PerformanceResult class + */ + +#ifndef DPL_TEST_PERFORMANCE_RESULT_H +#define DPL_TEST_PERFORMANCE_RESULT_H + +#include + +#include +#include + +namespace DPL { +namespace Test { + +class PerformanceResult; + +typedef std::shared_ptr PerformanceResultPtr; +typedef std::shared_ptr ConstPerformanceResultPtr; + +class PerformanceResult +{ +public: + PerformanceResult(const std::chrono::system_clock::duration& maxDuration) + : m_startTime(std::chrono::system_clock::now()) + , m_duration(std::chrono::microseconds::zero()) + , m_maxDuration(maxDuration < std::chrono::microseconds::zero() + ? std::chrono::microseconds::zero() + : maxDuration) {} + + PerformanceResult(BinaryQueue &queue) + : m_startTime(std::chrono::system_clock::now()) + , m_duration(std::chrono::microseconds::zero()) + , m_maxDuration(std::chrono::microseconds::zero()) { + queue.FlattenConsume(const_cast(&m_startTime), + sizeof(std::chrono::system_clock::time_point)); + queue.FlattenConsume(const_cast(&m_duration), + sizeof(std::chrono::system_clock::duration)); + queue.FlattenConsume(const_cast(&m_maxDuration), + sizeof(std::chrono::system_clock::duration)); + } + + bool IsMaxDuration() const { + return m_maxDuration > std::chrono::microseconds::zero(); + } + + bool IsDurationOk() const { + return m_duration <= m_maxDuration; + } + + const std::chrono::system_clock::duration &GetDuration() const { + return m_duration; + } + + const std::chrono::system_clock::duration &GetMaxDuration() const { + return m_maxDuration; + } + + void Finish() { + if (m_duration == std::chrono::microseconds::zero()) + m_duration = std::chrono::system_clock::now() - m_startTime; + } + + const std::string ToBinaryString() const { + std::string strStartTime(reinterpret_cast(&m_startTime), sizeof(m_startTime)); + std::string strDuration(reinterpret_cast(&m_duration), sizeof(m_duration)); + std::string strMaxDuration(reinterpret_cast(&m_maxDuration), + sizeof(m_maxDuration)); + return strStartTime + strDuration + strMaxDuration; + } + +private: + const std::chrono::system_clock::time_point m_startTime; + std::chrono::system_clock::duration m_duration; + const std::chrono::system_clock::duration m_maxDuration; +}; + +} // namespace Test +} // namespace DPL + +#endif // DPL_TEST_PERFORMANCE_RESULT_H diff --git a/src/framework/include/dpl/test/statistic.h b/src/framework/include/dpl/test/statistic.h index fe550bd..4990ffd 100644 --- a/src/framework/include/dpl/test/statistic.h +++ b/src/framework/include/dpl/test/statistic.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -27,7 +27,7 @@ #include #include -#include +#include namespace DPL { namespace Test { @@ -42,15 +42,15 @@ class Statistic m_count(0) {} - void AddTest(TestResultsCollectorBase::FailStatus status) + void AddTest(TestResult::FailStatus status) { ++m_count; switch (status) { - case TestResultsCollectorBase::FailStatus::FAILED: ++m_failed; + case TestResult::FailStatus::FAILED: ++m_failed; break; - case TestResultsCollectorBase::FailStatus::IGNORED: ++m_ignored; + case TestResult::FailStatus::IGNORED: ++m_ignored; break; - case TestResultsCollectorBase::FailStatus::NONE: ++m_passed; + case TestResult::FailStatus::NONE: ++m_passed; break; default: Assert(false && "Bad FailStatus"); diff --git a/src/framework/include/dpl/test/test_exception.h b/src/framework/include/dpl/test/test_exception.h new file mode 100644 index 0000000..49e4739 --- /dev/null +++ b/src/framework/include/dpl/test/test_exception.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 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 test_exception.h + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief This file is the header file of test_exception base class + */ + +#ifndef DPL_TEST_EXCEPTION_H +#define DPL_TEST_EXCEPTION_H + +#include + +namespace DPL { +namespace Test { + +class TestException +{ + public: + std::string GetMessage() const + { + return m_message; + } + + protected: + std::string m_message; + + TestException() {} + TestException(const std::string &message) : + m_message(message) {} + +}; + +} // namespace Test +} // namespace DPL + +#endif // DPL_TEST_EXCEPTION_H diff --git a/src/framework/include/dpl/test/test_failed.h b/src/framework/include/dpl/test/test_failed.h new file mode 100644 index 0000000..f446094 --- /dev/null +++ b/src/framework/include/dpl/test/test_failed.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 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 test_failed.h + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief This file is the header file of TestFailed class + */ + +#ifndef DPL_TEST_FAILED_H +#define DPL_TEST_FAILED_H + +#include + +#include + +namespace DPL { +namespace Test { + +class TestFailed : public TestException +{ + public: + TestFailed() = default; + + //! \brief Failed test message creator + //! + //! \param[in] aTest string for tested expression + //! \param[in] aFile source file name + //! \param[in] aLine source file line + //! \param[in] aMessage error message + TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage); + + TestFailed(const std::string &message) : + TestException(message) + {} +}; + +} // namespace Test +} // namespace DPL + +#endif // DPL_TEST_FAILED_H diff --git a/src/framework/include/dpl/test/test_ignored.h b/src/framework/include/dpl/test/test_ignored.h new file mode 100644 index 0000000..17a5c0a --- /dev/null +++ b/src/framework/include/dpl/test/test_ignored.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 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 test_ignored.h + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief This file is the header file of TestIgnored class + */ + +#ifndef DPL_TEST_IGNORED_H +#define DPL_TEST_IGNORED_H + +#include + +#include + +namespace DPL { +namespace Test { + +class TestIgnored : public TestException +{ + public: + TestIgnored() = default; + + TestIgnored(const std::string &message) : + TestException(message) + {} +}; + +} // namespace Test +} // namespace DPL + +#endif // DPL_TEST_IGNORED_H diff --git a/src/framework/include/dpl/test/test_result.h b/src/framework/include/dpl/test/test_result.h new file mode 100644 index 0000000..e2810d6 --- /dev/null +++ b/src/framework/include/dpl/test/test_result.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 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 test_result.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Header file with declaration of TestResult class + */ + +#ifndef DPL_TEST_RESULT_H +#define DPL_TEST_RESULT_H + +#include + +#include + +namespace DPL { +namespace Test { + +class TestResult +{ +public: + enum class FailStatus + { + NONE, + FAILED, + IGNORED + }; + + TestResult(FailStatus status, + const std::string& reason = std::string(), + ConstPerformanceResultPtr performanceResult = nullptr) + : m_failStatus(status) + , m_reason(reason) + , m_performanceResult(performanceResult) {} + + FailStatus GetFailStatus() const { + return m_failStatus; + } + + const std::string& GetReason() const { + return m_reason; + } + + ConstPerformanceResultPtr GetPerformanceResult() const { + return m_performanceResult; + } + +private: + const FailStatus m_failStatus; + const std::string m_reason; + ConstPerformanceResultPtr m_performanceResult; +}; + +} // namespace Test +} // namespace DPL + +#endif // DPL_TEST_RESULT_H diff --git a/src/framework/include/dpl/test/test_results_collector.h b/src/framework/include/dpl/test/test_results_collector.h index cfd9227..60a926f 100644 --- a/src/framework/include/dpl/test/test_results_collector.h +++ b/src/framework/include/dpl/test/test_results_collector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -15,6 +15,7 @@ */ /* * @file test_results_collector.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) * @author Lukasz Wrzosek (l.wrzosek@samsung.com) * @version 1.0 * @brief Header file with declaration of TestResultsCollectorBase @@ -24,10 +25,11 @@ #define DPL_TEST_RESULTS_COLLECTOR_H #include +#include + #include #include #include -#include #include #include @@ -43,12 +45,6 @@ class TestResultsCollectorBase : public: typedef TestResultsCollectorBase* (*CollectorConstructorFunc)(); typedef std::list TestCaseIdList; - enum class FailStatus - { - NONE, - FAILED, - IGNORED - }; virtual ~TestResultsCollectorBase() {} @@ -61,13 +57,7 @@ class TestResultsCollectorBase : virtual void CollectCurrentTestGroupName(const std::string& /*groupName*/) {} - virtual void CollectTestsCasesList(const TestCaseIdList& /*list*/) {} - virtual void CollectResult(const std::string& id, - const FailStatus status = FailStatus::NONE, - const std::string& reason = "", - const bool& isPerformanceTest = false, - const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), - const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) = 0; + virtual void CollectResult(const std::string& id, const TestResult &result) = 0; virtual std::string CollectorSpecificHelp() const { return ""; diff --git a/src/framework/include/dpl/test/test_results_collector_commons.h b/src/framework/include/dpl/test/test_results_collector_commons.h index 6961f4e..8fc98c1 100644 --- a/src/framework/include/dpl/test/test_results_collector_commons.h +++ b/src/framework/include/dpl/test/test_results_collector_commons.h @@ -41,10 +41,14 @@ namespace Test { "[%s%s%s] %s[elapsed: %0.3fms, expected < %0.3fms]%s\n", BOLD_GREEN_BEGIN, \ " OK ", BOLD_GREEN_END, BOLD_RED_BEGIN, elapsed, max, BOLD_RED_END +extern const std::string COLLECTOR_NO_VERBOSE_HELP; + // Get duration as a fraction of millisecond (max precision is 1 microsecond) double get_milliseconds (const std::chrono::system_clock::duration& performanceTime); +std::string CollectorFileHelp(const std::string &defaultFilename); bool ParseCollectorFileArg(const std::string &arg, std::string &filename); +bool ParseCollectorNoVerboseArg(const std::string &arg, bool &verbosity); } // namespace Test } // namespace DPL diff --git a/src/framework/include/dpl/test/test_results_collector_console.h b/src/framework/include/dpl/test/test_results_collector_console.h index 332763b..8f43d75 100644 --- a/src/framework/include/dpl/test/test_results_collector_console.h +++ b/src/framework/include/dpl/test/test_results_collector_console.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -40,28 +40,20 @@ public: private: ConsoleCollector(); + virtual bool ParseCollectorSpecificArg(const std::string& arg); + virtual std::string CollectorSpecificHelp() const; virtual void CollectCurrentTestGroupName(const std::string& name); - virtual void CollectResult(const std::string& id, - const FailStatus status = FailStatus::NONE, - const std::string& reason = "", - const bool& isPerformanceTest = true, - const std::chrono::system_clock::duration& performanceTime - = std::chrono::microseconds::zero(), - const std::chrono::system_clock::duration& performanceMaxTime - = std::chrono::microseconds::zero()); + virtual void CollectResult(const std::string& id, const TestResult &result); virtual void Finish(); - void PrintfErrorMessage(const char* type, - const std::string& message, - bool verbosity); - void PrintfIgnoredMessage(const char* type, - const std::string& message, - bool verbosity); + void PrintfErrorMessage(const char* type, const std::string& message); + void PrintfIgnoredMessage(const char* type, const std::string& message); void PrintStats(const std::string& title, const Statistic& stats); Statistic m_stats; std::map m_groupsStats; std::string m_currentGroup; + bool m_verbosity; }; } // namespace Test diff --git a/src/framework/include/dpl/test/test_results_collector_html.h b/src/framework/include/dpl/test/test_results_collector_html.h index 90d635e..122d3f9 100644 --- a/src/framework/include/dpl/test/test_results_collector_html.h +++ b/src/framework/include/dpl/test/test_results_collector_html.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -46,22 +46,11 @@ private: virtual bool Configure(); virtual void Start(); virtual void CollectCurrentTestGroupName(const std::string& name); - virtual void CollectResult(const std::string& id, - const FailStatus status = FailStatus::NONE, - const std::string& reason = "", - const bool& isPerformanceTest = false, - const std::chrono::system_clock::duration& performanceTime - = std::chrono::microseconds::zero(), - const std::chrono::system_clock::duration& performanceMaxTime - = std::chrono::microseconds::zero()); + virtual void CollectResult(const std::string& id, const TestResult &result); virtual void Finish(); - void PrintfErrorMessage(const char* type, - const std::string& message, - bool verbosity); - void PrintfIgnoredMessage(const char* type, - const std::string& message, - bool verbosity); + void PrintfErrorMessage(const char* type, const std::string& message); + void PrintfIgnoredMessage(const char* type, const std::string& message); void PrintStats(const std::string& name, const Statistic& stats); std::string m_filename; @@ -69,6 +58,7 @@ private: Statistic m_stats; std::string m_currentGroup; std::map m_groupsStats; + bool m_verbosity; }; } // namespace Test diff --git a/src/framework/include/dpl/test/test_results_collector_summary.h b/src/framework/include/dpl/test/test_results_collector_summary.h index f0edfcc..8f83a71 100644 --- a/src/framework/include/dpl/test/test_results_collector_summary.h +++ b/src/framework/include/dpl/test/test_results_collector_summary.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -45,14 +45,7 @@ private: virtual std::string CollectorSpecificHelp() const; virtual bool ParseCollectorSpecificArg(const std::string& arg); virtual void Start(); - virtual void CollectResult(const std::string& id, - const FailStatus status = FailStatus::NONE, - const std::string& reason = "", - const bool& isPerformanceTest = false, - const std::chrono::system_clock::duration& performanceTime - = std::chrono::microseconds::zero(), - const std::chrono::system_clock::duration& performanceMaxTime - = std::chrono::microseconds::zero()); + virtual void CollectResult(const std::string& id, const TestResult &result); virtual void Finish(); void writeStats(bool segfault); diff --git a/src/framework/include/dpl/test/test_results_collector_xml.h b/src/framework/include/dpl/test/test_results_collector_xml.h index 01b9802..60e8aca 100644 --- a/src/framework/include/dpl/test/test_results_collector_xml.h +++ b/src/framework/include/dpl/test/test_results_collector_xml.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -44,14 +44,7 @@ private: virtual bool Configure(); virtual void Start(); virtual void CollectCurrentTestGroupName(const std::string& name); - virtual void CollectResult(const std::string& id, - const FailStatus status = FailStatus::NONE, - const std::string& reason = "", - const bool& isPerformanceTest = false, - const std::chrono::system_clock::duration& performanceTime - = std::chrono::microseconds::zero(), - const std::chrono::system_clock::duration& performanceMaxTime - = std::chrono::microseconds::zero()); + virtual void CollectResult(const std::string& id, const TestResult &result); virtual void Finish(); void GroupStart(const std::size_t pos, const std::string& name); @@ -65,12 +58,8 @@ private: const std::string& value); std::string UIntToString(const unsigned int value); void GroupFinish(const std::size_t groupPosition); - void PrintfErrorMessage(const char* type, - const std::string& message, - bool verbosity); - void PrintfIgnoredMessage(const char* type, - const std::string& message, - bool verbosity); + void PrintfErrorMessage(const char* type, const std::string& message); + void PrintfIgnoredMessage(const char* type, const std::string& message); void FlushOutput(); std::string EscapeSpecialCharacters(std::string s); @@ -79,6 +68,7 @@ private: Statistic m_stats; std::string m_outputBuffer; std::string m_resultBuffer; + bool m_verbosity; }; } // namespace Test diff --git a/src/framework/include/dpl/test/test_runner.h b/src/framework/include/dpl/test/test_runner.h index 373b319..ee1d7c3 100644 --- a/src/framework/include/dpl/test/test_runner.h +++ b/src/framework/include/dpl/test/test_runner.h @@ -25,6 +25,7 @@ #define DPL_TEST_RUNNER_H #include +#include #include #include #include @@ -41,6 +42,11 @@ #include #include #include +#include +#include +#include +#include +#include #include namespace DPL { @@ -61,16 +67,14 @@ class TestRunner m_currentTestCase(nullptr) , m_terminate(false) , m_allowChildLogs(false) + , m_deferDeepness(0U) + , m_firstDeferredExceptionType(DeferredExceptionType::DEFERRED_FAILED) {} - void beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds); - void endPerformanceTestTime(); - void getCurrentTestCasePerformanceResult(bool& isPerformanceTest, - std::chrono::system_clock::duration& result, - std::chrono::system_clock::duration& resultMax); - void setCurrentTestCasePerformanceResult(bool isPerformanceTest, - std::chrono::system_clock::duration result, - std::chrono::system_clock::duration resultMax); + void beginPerformance(std::chrono::system_clock::duration maxDurationInMicroseconds); + void endPerformance(); + void setCurrentTestCasePerformanceResult(const PerformanceResultPtr &performance); + ConstPerformanceResultPtr getCurrentTestCasePerformanceResult(); void addFailReason(const std::string &reason); @@ -81,11 +85,7 @@ class TestRunner { std::string name; TestCase proc; - - bool m_isPerformanceTest; - std::chrono::system_clock::time_point m_performanceTestStartTime; - std::chrono::system_clock::duration m_performanceTestDurationTime; - std::chrono::system_clock::duration m_performanceMaxTime; + PerformanceResultPtr performance; bool operator <(const TestCaseStruct &other) const { @@ -99,8 +99,7 @@ class TestRunner TestCaseStruct(const std::string &n, TestCase p) : name(n), - proc(p), - m_isPerformanceTest(false) + proc(p) {} }; @@ -110,14 +109,8 @@ class TestRunner TestCaseStruct * m_currentTestCase; - typedef std::set SelectedTestNameSet; - SelectedTestNameSet m_selectedTestNamesSet; - typedef std::set SelectedTestGroupSet; - SelectedTestGroupSet m_selectedTestGroupSet; std::string m_currentGroup; - DPL::Atomic m_totalAssertions; - // Terminate without any logs. // Some test requires to call fork function. // Child process must not produce any logs and should die quietly. @@ -132,9 +125,7 @@ class TestRunner bool filterByXML(std::map & casesMap); void normalizeXMLTag(std::string& str, const std::string& testcase); - enum Status { FAILED, IGNORED, PASS }; - - Status RunTestCase(const TestCaseStruct& testCase); + void RunTestCase(const TestCaseStruct& testCase); void setCurrentTestCase(TestCaseStruct* testCase); TestCaseStruct *getCurrentTestCase(); @@ -143,74 +134,33 @@ class TestRunner std::string getConcatedFailReason(const std::string &reason); - void CollectResult(const std::string& id, - const TestResultsCollectorBase::FailStatus status - = TestResultsCollectorBase::FailStatus::NONE, - const std::string& reason = std::string(), - const bool& isPerformanceTest = false, - const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), - const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()); + void CollectResult(const std::string& id, const TestResult &result); public: - class TestFailed - { - private: - std::string m_message; - - public: - TestFailed() - {} - - //! \brief Failed test message creator - //! - //! \param[in] aTest string for tested expression - //! \param[in] aFile source file name - //! \param[in] aLine source file line - //! \param[in] aMessage error message - TestFailed(const char* aTest, - const char* aFile, - int aLine, - const std::string &aMessage); - - TestFailed(const std::string &message); - - std::string GetMessage() const - { - return m_message; - } - }; - - class Ignored - { - private: - std::string m_message; - - public: - Ignored() - {} - - Ignored(const std::string &message) : - m_message(message) - {} - - std::string GetMessage() const - { - return m_message; - } - }; - - void MarkAssertion(); - void RegisterTest(const char *testName, TestCase proc); void InitGroup(const char* name); int ExecTestRunner(int argc, char *argv[]); typedef std::vector ArgsList; int ExecTestRunner(ArgsList args); - bool getRunIgnored() const; // The runner will terminate as soon as possible (after current test). void Terminate(); bool GetAllowChildLogs(); + + void deferFailedException(const DPL::Test::TestFailed &ex); + void deferIgnoredException(const DPL::Test::TestIgnored &ex); + void deferBegin(); + void deferEnd(); + +private: + std::vector m_deferredExceptionsMessages; + std::size_t m_deferDeepness; + enum DeferredExceptionType { + DEFERRED_FAILED, + DEFERRED_IGNORED, + } m_firstDeferredExceptionType; + DPL::Test::TestFailed m_firstDeferredFail; + DPL::Test::TestIgnored m_firstDeferredIgnore; }; typedef DPL::Singleton TestRunnerSingleton; @@ -247,16 +197,14 @@ typedef DPL::Singleton TestRunnerSingleton; #define RUNNER_ASSERT_MSG(test, message) \ do \ { \ - DPL::Test::TestRunnerSingleton::Instance().MarkAssertion(); \ - \ if (!(test)) \ { \ std::ostringstream assertMsg; \ assertMsg << message << DPL::gdbbacktrace(); \ - DPL::Test::TestRunner::TestFailed e(#test, \ - __FILE__, \ - __LINE__, \ - assertMsg.str()); \ + DPL::Test::TestFailed e(#test, \ + __FILE__, \ + __LINE__, \ + assertMsg.str()); \ if (!std::uncaught_exception()) \ throw e; \ DPL::Test::TestRunnerSingleton::Instance().addFailReason(e.GetMessage()); \ @@ -266,8 +214,6 @@ typedef DPL::Singleton TestRunnerSingleton; #define RUNNER_ASSERT_ERRNO_MSG(test, message) \ do \ { \ - DPL::Test::TestRunnerSingleton::Instance().MarkAssertion(); \ - \ if (!(test)) \ { \ const char *err = strerror(errno); \ @@ -276,10 +222,10 @@ typedef DPL::Singleton TestRunnerSingleton; if (!assertMsg.str().empty()) \ assertMsg << ". "; \ assertMsg << err << DPL::gdbbacktrace(); \ - DPL::Test::TestRunner::TestFailed e(#test, \ - __FILE__, \ - __LINE__, \ - assertMsg.str()); \ + DPL::Test::TestFailed e(#test, \ + __FILE__, \ + __LINE__, \ + assertMsg.str()); \ if (!std::uncaught_exception()) \ throw e; \ DPL::Test::TestRunnerSingleton::Instance().addFailReason(e.GetMessage()); \ @@ -303,12 +249,12 @@ typedef DPL::Singleton TestRunnerSingleton; * body. */ -#define RUNNER_IGNORED_MSG(message) \ - do \ - { \ - std::ostringstream assertMsg; \ - assertMsg << message; \ - throw DPL::Test::TestRunner::Ignored(assertMsg.str()); \ +#define RUNNER_IGNORED_MSG(message) \ + do \ + { \ + std::ostringstream assertMsg; \ + assertMsg << message; \ + throw DPL::Test::TestIgnored(assertMsg.str()); \ } while (0) /** @@ -331,13 +277,13 @@ typedef DPL::Singleton TestRunnerSingleton; #define RUNNER_PERF_TEST_BEGIN(maxTime) \ do { \ - DPL::Test::TestRunnerSingleton::Instance().beginPerformanceTestTime( \ + DPL::Test::TestRunnerSingleton::Instance().beginPerformance( \ std::chrono::microseconds{static_cast(maxTime*1000000.0)}); \ } while (0) -#define RUNNER_PERF_TEST_END() \ - do { \ - DPL::Test::TestRunnerSingleton::Instance().endPerformanceTestTime(); \ +#define RUNNER_PERF_TEST_END() \ + do { \ + DPL::Test::TestRunnerSingleton::Instance().endPerformance(); \ } while (0) /** @@ -352,4 +298,39 @@ typedef DPL::Singleton TestRunnerSingleton; << DPL::Colors::Text::RED_END << std::endl; \ } while (0) +/** + * DEFER MACROS + * + * Use them to defer fails and ignores in test cases. + * Some code constructions disallow to throw. Such places can be surrounded + * with RUNNER_DEFER_SCOPE macro. RUNNER_DEFER_TRYCATCH macro can be used to catch possibly thrown + * exceptions within such scope. Possibly catched exceptions will be rethrown + * when leaving RUNNER_DEFER_SCOPE scope. + * Macros can be safely nested. + */ + + +#define RUNNER_DEFER_TRYCATCH(scope) \ + do { \ + try \ + { \ + scope \ + } \ + catch (const DPL::Test::TestFailed &ex) \ + { \ + DPL::Test::TestRunnerSingleton::Instance().deferFailedException(ex); \ + } \ + catch (const DPL::Test::TestIgnored &ex) \ + { \ + DPL::Test::TestRunnerSingleton::Instance().deferIgnoredException(ex); \ + } \ + } while (0) \ + +#define RUNNER_DEFER_SCOPE(scope) \ + do { \ + DPL::Test::TestRunnerSingleton::Instance().deferBegin(); \ + scope \ + DPL::Test::TestRunnerSingleton::Instance().deferEnd(); \ + } while (0) \ + #endif // DPL_TEST_RUNNER_H diff --git a/src/framework/include/dpl/test/test_runner_child.h b/src/framework/include/dpl/test/test_runner_child.h index d1e4b1c..8c52600 100644 --- a/src/framework/include/dpl/test/test_runner_child.h +++ b/src/framework/include/dpl/test/test_runner_child.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2013-2015 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. @@ -50,15 +50,11 @@ class PipeWrapper : DPL::Noncopyable virtual ~PipeWrapper(); Status send(int code, std::string &message); - Status sendTime(int code, - std::chrono::system_clock::duration time, - std::chrono::system_clock::duration timeMax); + Status sendPerformance(const ConstPerformanceResultPtr &performance); Status receive(int &code, - int &msgType, std::string &data, - std::chrono::system_clock::duration &time, - std::chrono::system_clock::duration &timeMax, + PerformanceResultPtr &performance, time_t deadline); void closeAll(); @@ -66,7 +62,6 @@ class PipeWrapper : DPL::Noncopyable protected: std::string toBinaryString(int data); - std::string toBinaryString(std::chrono::system_clock::duration data); void closeHelp(int desc); diff --git a/src/framework/src/test_failed.cpp b/src/framework/src/test_failed.cpp new file mode 100644 index 0000000..c8de070 --- /dev/null +++ b/src/framework/src/test_failed.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 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 test_failed.cpp + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief This file is the implementation file of TestFailed class + */ + +#include +#include +#include +#include +#include + +#include + +namespace DPL { +namespace Test { +namespace // anonymous +{ +std::string BaseName(const std::string &aPath) +{ + std::unique_ptr path(strdup(aPath.c_str()), free); + if (!path) + throw std::bad_alloc(); + + return basename(path.get()); +} +} // namespace anonymous + +//! \brief Failed test message creator +//! +//! \param[in] aTest string for tested expression +//! \param[in] aFile source file name +//! \param[in] aLine source file line +//! \param[in] aMessage error message +TestFailed::TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage) +{ + std::ostringstream assertMsg; + assertMsg << "[" << BaseName(aFile) << ":" << aLine + << "] Assertion failed (" + << aTest << ") " << aMessage; + m_message = assertMsg.str(); +} + +} // namespace Test +} // namespace DPL diff --git a/src/framework/src/test_results_collector_commons.cpp b/src/framework/src/test_results_collector_commons.cpp index e821f16..013bde2 100644 --- a/src/framework/src/test_results_collector_commons.cpp +++ b/src/framework/src/test_results_collector_commons.cpp @@ -27,12 +27,28 @@ namespace DPL { namespace Test { +namespace { + +const std::string NO_VERBOSE_ARG = "--no-verbose"; + +} // namespace + +const std::string COLLECTOR_NO_VERBOSE_HELP = + NO_VERBOSE_ARG + " - turns off verbosity\n" + + std::string(NO_VERBOSE_ARG.size(), ' ') + " verbosity turned on by default\n"; + double get_milliseconds (const std::chrono::system_clock::duration& performanceTime) { return (static_cast(std::chrono::duration_cast (performanceTime).count()))/1000.0; } +std::string CollectorFileHelp(const std::string &defaultFilename) +{ + return "--file= - name of file for output\n" + " default - " + defaultFilename + "\n"; +} + bool ParseCollectorFileArg(const std::string &arg, std::string &filename) { const std::string argname = "--file="; @@ -43,6 +59,14 @@ bool ParseCollectorFileArg(const std::string &arg, std::string &filename) return false; } +bool ParseCollectorNoVerboseArg(const std::string &arg, bool &verbosity) +{ + if (arg != NO_VERBOSE_ARG) + return false; + verbosity=false; + return true; +} + } // namespace Test } // namespace DPL diff --git a/src/framework/src/test_results_collector_console.cpp b/src/framework/src/test_results_collector_console.cpp index 09030a8..dab84f8 100644 --- a/src/framework/src/test_results_collector_console.cpp +++ b/src/framework/src/test_results_collector_console.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -34,6 +34,7 @@ namespace DPL { namespace Test { ConsoleCollector::ConsoleCollector() + : m_verbosity(true) { } @@ -42,6 +43,16 @@ TestResultsCollectorBase* ConsoleCollector::Constructor() return new ConsoleCollector(); } +bool ConsoleCollector::ParseCollectorSpecificArg(const std::string& arg) +{ + return ParseCollectorNoVerboseArg(arg, m_verbosity); +} + +std::string ConsoleCollector::CollectorSpecificHelp() const +{ + return COLLECTOR_NO_VERBOSE_HELP; +} + void ConsoleCollector::CollectCurrentTestGroupName(const std::string& name) { printf("Starting group %s\n", name.c_str()); @@ -59,92 +70,79 @@ void ConsoleCollector::Finish() PrintStats("All tests together", m_stats); } -void ConsoleCollector::CollectResult(const std::string& id, - const FailStatus status, - const std::string& reason, - const bool& isPerformanceTest, - const std::chrono::system_clock::duration& performanceTime, - const std::chrono::system_clock::duration& performanceMaxTime) +void ConsoleCollector::CollectResult(const std::string& id, const TestResult &result) { using namespace DPL::Colors::Text; std::string tmp = "'" + id + "' ..."; printf("Running test case %-60s", tmp.c_str()); - switch (status) { - case FailStatus::NONE: - if (isPerformanceTest) { - if (performanceMaxTime <= std::chrono::microseconds::zero()) { - printf(GREEN_RESULT_OK_TIME, - get_milliseconds(performanceTime)); - break; - } - else { - if (performanceTime > performanceMaxTime) - printf(GREEN_RESULT_OK_TIME_TOO_LONG( - get_milliseconds(performanceTime), - get_milliseconds(performanceMaxTime))); - else - printf(GREEN_RESULT_OK_TIME_MAX( - get_milliseconds(performanceTime), - get_milliseconds(performanceMaxTime))); - break; - } + + ConstPerformanceResultPtr performanceResult; + switch (result.GetFailStatus()) { + case TestResult::FailStatus::NONE: + performanceResult = result.GetPerformanceResult(); + if (!performanceResult) { + printf(GREEN_RESULT_OK); + break; + } + if (!performanceResult->IsMaxDuration()) { + printf(GREEN_RESULT_OK_TIME, + get_milliseconds(performanceResult->GetDuration())); + break; + } + if (!performanceResult->IsDurationOk()) { + printf(GREEN_RESULT_OK_TIME_TOO_LONG( + get_milliseconds(performanceResult->GetDuration()), + get_milliseconds(performanceResult->GetMaxDuration()))); + break; } - printf(GREEN_RESULT_OK); + printf(GREEN_RESULT_OK_TIME_MAX( + get_milliseconds(performanceResult->GetDuration()), + get_milliseconds(performanceResult->GetMaxDuration()))); break; - case FailStatus::FAILED: - PrintfErrorMessage(" FAILED ", reason, true); + case TestResult::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", result.GetReason()); break; - case FailStatus::IGNORED: - PrintfIgnoredMessage("Ignored ", reason, true); + case TestResult::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", result.GetReason()); break; default: Assert(false && "Bad status"); } - m_stats.AddTest(status); - m_groupsStats[m_currentGroup].AddTest(status); + m_stats.AddTest(result.GetFailStatus()); + m_groupsStats[m_currentGroup].AddTest(result.GetFailStatus()); } -void ConsoleCollector::PrintfErrorMessage(const char* type, - const std::string& message, - bool verbosity) +void ConsoleCollector::PrintfErrorMessage(const char* type, const std::string& message) { using namespace DPL::Colors::Text; - if (verbosity) { - printf("[%s%s%s] %s%s%s\n", - BOLD_RED_BEGIN, - type, - BOLD_RED_END, + printf("[%s%s%s]", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + if (m_verbosity) { + printf(" %s%s%s", BOLD_YELLOW_BEGIN, message.c_str(), BOLD_YELLOW_END); - } else { - printf("[%s%s%s]\n", - BOLD_RED_BEGIN, - type, - BOLD_RED_END); } + printf("\n"); } -void ConsoleCollector::PrintfIgnoredMessage(const char* type, - const std::string& message, - bool verbosity) +void ConsoleCollector::PrintfIgnoredMessage(const char* type, const std::string& message) { using namespace DPL::Colors::Text; - if (verbosity) { - printf("[%s%s%s] %s%s%s\n", - CYAN_BEGIN, - type, - CYAN_END, + printf("[%s%s%s]", + CYAN_BEGIN, + type, + CYAN_END); + if (m_verbosity) { + printf(" %s%s%s", BOLD_GOLD_BEGIN, message.c_str(), BOLD_GOLD_END); - } else { - printf("[%s%s%s]\n", - CYAN_BEGIN, - type, - CYAN_END); } + printf("\n"); } void ConsoleCollector::PrintStats(const std::string& title, const Statistic& stats) diff --git a/src/framework/src/test_results_collector_html.cpp b/src/framework/src/test_results_collector_html.cpp index 93698cc..86fce37 100644 --- a/src/framework/src/test_results_collector_html.cpp +++ b/src/framework/src/test_results_collector_html.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -39,7 +39,8 @@ const char *DEFAULT_HTML_FILE_NAME = "index.html"; } HtmlCollector::HtmlCollector() - : m_filename(DEFAULT_HTML_FILE_NAME) + : m_filename(DEFAULT_HTML_FILE_NAME), + m_verbosity(true) { } @@ -66,8 +67,7 @@ bool HtmlCollector::Configure() std::string HtmlCollector::CollectorSpecificHelp() const { - return "--file= - name of file for output\n" - " default - index.html\n"; + return CollectorFileHelp(DEFAULT_HTML_FILE_NAME) + COLLECTOR_NO_VERBOSE_HELP; } void HtmlCollector::Start() @@ -102,99 +102,87 @@ void HtmlCollector::Finish() bool HtmlCollector::ParseCollectorSpecificArg(const std::string& arg) { - return ParseCollectorFileArg(arg, m_filename); + return ParseCollectorFileArg(arg, m_filename) || ParseCollectorNoVerboseArg(arg, m_verbosity); } -void HtmlCollector::CollectResult(const std::string& id, - const FailStatus status, - const std::string& reason, - const bool& isPerformanceTest, - const std::chrono::system_clock::duration& performanceTime, - const std::chrono::system_clock::duration& performanceMaxTime) +void HtmlCollector::CollectResult(const std::string& id, const TestResult &result) { using namespace DPL::Colors::Html; std::string tmp = "'" + id + "' ..."; fprintf(m_fp.Get(), "Running test case %-100s", tmp.c_str()); - switch (status) { - case FailStatus::NONE: - if (isPerformanceTest) { - if (performanceMaxTime <= std::chrono::microseconds::zero()) { - fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME, - get_milliseconds(performanceTime)); - break; - } else { - if (performanceTime > performanceMaxTime) - fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_TOO_LONG( - get_milliseconds(performanceTime), - get_milliseconds(performanceMaxTime))); - else - fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_MAX( - get_milliseconds(performanceTime), - get_milliseconds(performanceMaxTime))); - break; - } + + ConstPerformanceResultPtr performanceResult; + switch (result.GetFailStatus()) { + case TestResult::FailStatus::NONE: + performanceResult = result.GetPerformanceResult(); + if (!performanceResult) { + fprintf(m_fp.Get(), GREEN_RESULT_OK); + break; + } + if (!performanceResult->IsMaxDuration()) { + fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME, + get_milliseconds(performanceResult->GetDuration())); + break; } - fprintf(m_fp.Get(), GREEN_RESULT_OK); + if (!performanceResult->IsDurationOk()) { + fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_TOO_LONG( + get_milliseconds(performanceResult->GetDuration()), + get_milliseconds(performanceResult->GetMaxDuration()))); + break; + } + fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_MAX( + get_milliseconds(performanceResult->GetDuration()), + get_milliseconds(performanceResult->GetMaxDuration()))); break; - case FailStatus::FAILED: - PrintfErrorMessage(" FAILED ", reason, true); + case TestResult::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", result.GetReason()); break; - case FailStatus::IGNORED: - PrintfIgnoredMessage("Ignored ", reason, true); + case TestResult::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", result.GetReason()); break; default: Assert(false && "Bad status"); } - m_groupsStats[m_currentGroup].AddTest(status); - m_stats.AddTest(status); + m_groupsStats[m_currentGroup].AddTest(result.GetFailStatus()); + m_stats.AddTest(result.GetFailStatus()); } -void HtmlCollector::PrintfErrorMessage(const char* type, - const std::string& message, - bool verbosity) +void HtmlCollector::PrintfErrorMessage(const char* type, const std::string& message) { using namespace DPL::Colors::Html; - if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s]", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + if (m_verbosity) { fprintf(m_fp.Get(), - "[%s%s%s] %s%s%s\n", - BOLD_RED_BEGIN, - type, - BOLD_RED_END, + " %s%s%s", BOLD_YELLOW_BEGIN, message.c_str(), BOLD_YELLOW_END); - } else { - fprintf(m_fp.Get(), - "[%s%s%s]\n", - BOLD_RED_BEGIN, - type, - BOLD_RED_END); } + fprintf(m_fp.Get(), "\n"); } -void HtmlCollector::PrintfIgnoredMessage(const char* type, - const std::string& message, - bool verbosity) +void HtmlCollector::PrintfIgnoredMessage(const char* type, const std::string& message) { using namespace DPL::Colors::Html; - if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s]", + CYAN_BEGIN, + type, + CYAN_END); + if (m_verbosity) { fprintf(m_fp.Get(), - "[%s%s%s] %s%s%s\n", - CYAN_BEGIN, - type, - CYAN_END, + " %s%s%s", BOLD_GOLD_BEGIN, message.c_str(), BOLD_GOLD_END); - } else { - fprintf(m_fp.Get(), - "[%s%s%s]\n", - CYAN_BEGIN, - type, - CYAN_END); } + fprintf(m_fp.Get(), "\n"); } void HtmlCollector::PrintStats(const std::string& name, const Statistic& stats) diff --git a/src/framework/src/test_results_collector_summary.cpp b/src/framework/src/test_results_collector_summary.cpp index 74cb680..efcaa31 100644 --- a/src/framework/src/test_results_collector_summary.cpp +++ b/src/framework/src/test_results_collector_summary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -48,8 +48,7 @@ TestResultsCollectorBase* SummaryCollector::Constructor() std::string SummaryCollector::CollectorSpecificHelp() const { - return "--file= - name of file for output\n" - " default - " + DEFAULT_SUMMARY_FILE_NAME + "\n"; + return CollectorFileHelp(DEFAULT_SUMMARY_FILE_NAME); } bool SummaryCollector::ParseCollectorSpecificArg(const std::string& arg) @@ -62,20 +61,11 @@ void SummaryCollector::Start() writeStats(true); } -void SummaryCollector::CollectResult(const std::string& id, - const FailStatus status, - const std::string& reason, - const bool& isPerformanceTest, - const std::chrono::system_clock::duration& performanceTime, - const std::chrono::system_clock::duration& performanceMaxTime) +void SummaryCollector::CollectResult(const std::string& id, const TestResult &result) { DPL_UNUSED_PARAM(id); - DPL_UNUSED_PARAM(reason); - DPL_UNUSED_PARAM(isPerformanceTest); - DPL_UNUSED_PARAM(performanceTime); - DPL_UNUSED_PARAM(performanceMaxTime); - m_stats.AddTest(status); + m_stats.AddTest(result.GetFailStatus()); writeStats(true); } diff --git a/src/framework/src/test_results_collector_xml.cpp b/src/framework/src/test_results_collector_xml.cpp index 7eea2b7..6ad2fce 100644 --- a/src/framework/src/test_results_collector_xml.cpp +++ b/src/framework/src/test_results_collector_xml.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -42,7 +42,7 @@ const char *DEFAULT_XML_FILE_NAME = "results.xml"; } XmlCollector::XmlCollector() - : m_filename(DEFAULT_XML_FILE_NAME) + : m_filename(DEFAULT_XML_FILE_NAME), m_verbosity(true) { } @@ -99,8 +99,7 @@ bool XmlCollector::Configure() std::string XmlCollector::CollectorSpecificHelp() const { - return "--file= - name of file for output\n" - " default - results.xml\n"; + return CollectorFileHelp(DEFAULT_XML_FILE_NAME) + COLLECTOR_NO_VERBOSE_HELP; } void XmlCollector::Start() @@ -122,54 +121,49 @@ void XmlCollector::Finish() bool XmlCollector::ParseCollectorSpecificArg(const std::string& arg) { - return ParseCollectorFileArg(arg, m_filename); + return ParseCollectorFileArg(arg, m_filename) || ParseCollectorNoVerboseArg(arg, m_verbosity); } -void XmlCollector::CollectResult(const std::string& id, - const FailStatus status, - const std::string& reason, - const bool& isPerformanceTest, - const std::chrono::system_clock::duration& performanceTime, - const std::chrono::system_clock::duration& performanceMaxTime) +void XmlCollector::CollectResult(const std::string& id, const TestResult &result) { m_resultBuffer.erase(); m_resultBuffer.append("\t\t\n"); - break; - } else { - m_resultBuffer.append(" status=\"OK\" time=\""); - std::ostringstream ostr; - ostr << performanceTime.count(); - m_resultBuffer.append(ostr.str()); - m_resultBuffer.append("\" time_expected=\""); - ostr.str(""); - ostr << performanceMaxTime.count(); - m_resultBuffer.append(ostr.str()); - m_resultBuffer.append("\"/>\n"); - break; - } + + std::ostringstream ostr; + ConstPerformanceResultPtr performanceResult; + switch (result.GetFailStatus()) { + case TestResult::FailStatus::NONE: + performanceResult = result.GetPerformanceResult(); + if (!performanceResult) { + m_resultBuffer.append(" status=\"OK\"/>\n"); + break; } - m_resultBuffer.append(" status=\"OK\"/>\n"); + if (!performanceResult->IsMaxDuration()) { + m_resultBuffer.append(" status=\"OK\" time=\""); + ostr << performanceResult->GetDuration().count(); + m_resultBuffer.append(ostr.str()); + m_resultBuffer.append("\"/>\n"); + break; + } + m_resultBuffer.append(" status=\"OK\" time=\""); + ostr << performanceResult->GetDuration().count(); + m_resultBuffer.append(ostr.str()); + m_resultBuffer.append("\" time_expected=\""); + ostr.str(""); + ostr << performanceResult->GetMaxDuration().count(); + m_resultBuffer.append(ostr.str()); + m_resultBuffer.append("\"/>\n"); break; - case FailStatus::FAILED: + case TestResult::FailStatus::FAILED: m_resultBuffer.append(" status=\"FAILED\">\n"); - PrintfErrorMessage("FAILED", EscapeSpecialCharacters(reason), true); + PrintfErrorMessage("FAILED", EscapeSpecialCharacters(result.GetReason())); m_resultBuffer.append("\t\t\n"); break; - case FailStatus::IGNORED: + case TestResult::FailStatus::IGNORED: m_resultBuffer.append(" status=\"Ignored\">\n"); - PrintfIgnoredMessage("Ignored", EscapeSpecialCharacters( - reason), true); + PrintfIgnoredMessage("Ignored", EscapeSpecialCharacters(result.GetReason())); m_resultBuffer.append("\t\t\n"); break; default: @@ -188,7 +182,7 @@ void XmlCollector::CollectResult(const std::string& id, } m_outputBuffer.insert(last_case_pos - 2, m_resultBuffer); - m_stats.AddTest(status); + m_stats.AddTest(result.GetFailStatus()); UpdateGroupHeader(group_pos, m_stats.GetTotal() + 1, // include SegFault @@ -300,38 +294,26 @@ void XmlCollector::FlushOutput() } } -void XmlCollector::PrintfErrorMessage(const char* type, - const std::string& message, - bool verbosity) +void XmlCollector::PrintfErrorMessage(const char* type, const std::string& message) { - if (verbosity) { - m_resultBuffer.append("\t\t\t\n"); - } else { - m_resultBuffer.append("\t\t\t\n"); } + m_resultBuffer.append("\"/>\n"); } -void XmlCollector::PrintfIgnoredMessage(const char* type, - const std::string& message, - bool verbosity) +void XmlCollector::PrintfIgnoredMessage(const char* type, const std::string& message) { - if (verbosity) { - m_resultBuffer.append("\t\t\t\n"); - } else { - m_resultBuffer.append("\t\t\t\n"); } + m_resultBuffer.append("\"/>\n"); } std::string XmlCollector::EscapeSpecialCharacters(std::string s) diff --git a/src/framework/src/test_runner.cpp b/src/framework/src/test_runner.cpp index ae9bbc5..95e1698 100644 --- a/src/framework/src/test_runner.cpp +++ b/src/framework/src/test_runner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* +/** * @file test_runner.cpp * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) * @author Lukasz Wrzosek (l.wrzosek@samsung.com) @@ -21,6 +21,8 @@ * @brief This file is the implementation file of test runner */ #include +#include +#include #include #include #include @@ -31,9 +33,6 @@ #include #include #include -#include -#include -#include #include #include @@ -59,42 +58,6 @@ std::string getXMLNode(xmlNodePtr node) namespace DPL { namespace Test { -namespace // anonymous -{ -std::string BaseName(std::string aPath) -{ - ScopedFree path(strdup(aPath.c_str())); - if (nullptr == path.Get()) { - throw std::bad_alloc(); - } - char* baseName = basename(path.Get()); - std::string retValue = baseName; - return retValue; -} -} // namespace anonymous - -//! \brief Failed test message creator -//! -//! \param[in] aTest string for tested expression -//! \param[in] aFile source file name -//! \param[in] aLine source file line -//! \param[in] aMessage error message -TestRunner::TestFailed::TestFailed(const char* aTest, - const char* aFile, - int aLine, - const std::string &aMessage) -{ - std::ostringstream assertMsg; - assertMsg << "[" << BaseName(aFile) << ":" << aLine - << "] Assertion failed (" - << aTest << ") " << aMessage; - m_message = assertMsg.str(); -} - -TestRunner::TestFailed::TestFailed(const std::string &message) -{ - m_message = message; -} void TestRunner::RegisterTest(const char *testName, TestCase proc) { @@ -243,57 +206,50 @@ bool TestRunner::filterByXML(std::map & casesMap) return true; } -TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase) +void TestRunner::RunTestCase(const TestCaseStruct& testCase) { setCurrentTestCase(&(const_cast(testCase))); + m_deferDeepness = 0U; try { testCase.proc(); } catch (const TestFailed &e) { // Simple test failure CollectResult(testCase.name, - TestResultsCollectorBase::FailStatus::FAILED, - getConcatedFailReason(e.GetMessage())); + TestResult(TestResult::FailStatus::FAILED, + getConcatedFailReason(e.GetMessage()))); setCurrentTestCase(nullptr); - return FAILED; - } catch (const Ignored &e) { + return; + } catch (const TestIgnored &e) { if (m_runIgnored) { // Simple test have to be implemented CollectResult(testCase.name, - TestResultsCollectorBase::FailStatus::IGNORED, - e.GetMessage()); + TestResult(TestResult::FailStatus::IGNORED, e.GetMessage())); } setCurrentTestCase(nullptr); - return IGNORED; + return; } catch (const std::exception &) { // std exception failure CollectResult(testCase.name, - TestResultsCollectorBase::FailStatus::FAILED, - "std exception"); + TestResult(TestResult::FailStatus::FAILED, "std exception")); setCurrentTestCase(nullptr); - return FAILED; + return; } catch (...) { // Unknown exception failure CollectResult(testCase.name, - TestResultsCollectorBase::FailStatus::FAILED, - "unknown exception"); - + TestResult(TestResult::FailStatus::FAILED, "unknown exception")); setCurrentTestCase(nullptr); - return FAILED; + return; } + // Everything OK CollectResult(testCase.name, - TestResultsCollectorBase::FailStatus::NONE, - "", - testCase.m_isPerformanceTest, - testCase.m_performanceTestDurationTime, - testCase.m_performanceMaxTime); + TestResult(TestResult::FailStatus::NONE, + std::string(), + testCase.performance)); setCurrentTestCase(nullptr); - - // Everything OK - return PASS; } void TestRunner::RunTests() @@ -360,56 +316,41 @@ void TestRunner::setCurrentTestCase(TestCaseStruct* testCase) m_currentTestCase = testCase; } -void TestRunner::beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds) +void TestRunner::beginPerformance(std::chrono::system_clock::duration maxDurationInMicroseconds) { TestCaseStruct* testCase = getCurrentTestCase(); if (!testCase) return; - testCase->m_isPerformanceTest = true; - testCase->m_performanceMaxTime = maxTimeInMicroseconds; - testCase->m_performanceTestStartTime = std::chrono::system_clock::now(); - - // Set result to 0 microseconds. Display 0ms result when end macro is missing. - testCase->m_performanceTestDurationTime = std::chrono::microseconds::zero(); + if (!testCase->performance) + testCase->performance.reset(new PerformanceResult(maxDurationInMicroseconds)); } -void TestRunner::endPerformanceTestTime() +void TestRunner::endPerformance() { TestCaseStruct* testCase = getCurrentTestCase(); if (!testCase) return; - testCase->m_performanceTestDurationTime = std::chrono::system_clock::now() - - testCase->m_performanceTestStartTime; + testCase->performance->Finish(); } -void TestRunner::getCurrentTestCasePerformanceResult(bool& isPerformanceTest, - std::chrono::system_clock::duration& result, - std::chrono::system_clock::duration& resultMax) +ConstPerformanceResultPtr TestRunner::getCurrentTestCasePerformanceResult() { TestCaseStruct* testCase = getCurrentTestCase(); - if (!testCase || !(testCase->m_isPerformanceTest)){ - isPerformanceTest = false; - return; - } + if (!testCase) + return nullptr; - isPerformanceTest = testCase->m_isPerformanceTest; - result = testCase->m_performanceTestDurationTime; - resultMax = testCase->m_performanceMaxTime; + return testCase->performance; } -void TestRunner::setCurrentTestCasePerformanceResult(bool isPerformanceTest, - std::chrono::system_clock::duration result, - std::chrono::system_clock::duration resultMax) +void TestRunner::setCurrentTestCasePerformanceResult(const PerformanceResultPtr &performance) { TestCaseStruct* testCase = getCurrentTestCase(); if (!testCase) return; - testCase->m_isPerformanceTest = isPerformanceTest; - testCase->m_performanceTestDurationTime = result; - testCase->m_performanceMaxTime = resultMax; + testCase->performance = performance; } void TestRunner::addFailReason(const std::string &reason) @@ -428,24 +369,13 @@ std::string TestRunner::getConcatedFailReason(const std::string &reason) return reason + ret; } -void TestRunner::CollectResult( - const std::string& id, - const TestResultsCollectorBase::FailStatus status, - const std::string& reason, - const bool& isPerformanceTest, - const std::chrono::system_clock::duration& performanceTestDurationTime, - const std::chrono::system_clock::duration& performanceMaxTime) +void TestRunner::CollectResult(const std::string& id, const TestResult& result) { std::for_each(m_collectors.begin(), m_collectors.end(), [&](const TestResultsCollectors::value_type & collector) { - collector.second->CollectResult(id, - status, - reason, - isPerformanceTest, - performanceTestDurationTime, - performanceMaxTime); + collector.second->CollectResult(id, result); }); } @@ -532,11 +462,6 @@ int TestRunner::ExecTestRunner(int argc, char *argv[]) return ExecTestRunner(args); } -void TestRunner::MarkAssertion() -{ - ++m_totalAssertions; -} - int TestRunner::ExecTestRunner(ArgsList args) { m_runIgnored = false; @@ -742,11 +667,6 @@ int TestRunner::ExecTestRunner(ArgsList args) return 0; } -bool TestRunner::getRunIgnored() const -{ - return m_runIgnored; -} - void TestRunner::Terminate() { m_terminate = true; @@ -757,5 +677,60 @@ bool TestRunner::GetAllowChildLogs() return m_allowChildLogs; } +void TestRunner::deferFailedException(const DPL::Test::TestFailed &ex) +{ + if (m_deferDeepness <= 0) + throw ex; + + if (m_deferredExceptionsMessages.empty()) { + m_firstDeferredFail = ex; + m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_FAILED; + } + m_deferredExceptionsMessages.push_back(ex.GetMessage()); } + +void TestRunner::deferIgnoredException(const DPL::Test::TestIgnored &ex) +{ + if (m_deferDeepness <= 0) + throw ex; + + if (m_deferredExceptionsMessages.empty()) { + m_firstDeferredIgnore = ex; + m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_IGNORED; + } + m_deferredExceptionsMessages.push_back(ex.GetMessage()); +} + +void TestRunner::deferBegin() +{ + m_deferDeepness++; +} + +void TestRunner::deferEnd() +{ + if (m_deferDeepness > 0) + m_deferDeepness--; + + if (m_deferDeepness > 0) + return; + + bool oops = std::uncaught_exception(); + size_t additionalExceptions = oops ? 0 : 1; + for (size_t i = additionalExceptions; i < m_deferredExceptionsMessages.size(); ++i) + addFailReason(m_deferredExceptionsMessages[i]); + + if (!oops && !m_deferredExceptionsMessages.empty()) + { + m_deferredExceptionsMessages.clear(); + switch (m_firstDeferredExceptionType) { + case DeferredExceptionType::DEFERRED_FAILED: + throw m_firstDeferredFail; + case DeferredExceptionType::DEFERRED_IGNORED: + throw m_firstDeferredIgnore; + } + } + m_deferredExceptionsMessages.clear(); +} + +} // namespace Test } // namespace DPL diff --git a/src/framework/src/test_runner_child.cpp b/src/framework/src/test_runner_child.cpp index 19ed08c..e2efb02 100644 --- a/src/framework/src/test_runner_child.cpp +++ b/src/framework/src/test_runner_child.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2013-2015 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. @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* +/** * @file test_runner_child.cpp * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) * @version 1.0 * @brief This file is the implementation file of test runner */ #include +#include +#include #include #include #include @@ -47,9 +49,6 @@ const int CHILD_TEST_FAIL = 0; const int CHILD_TEST_PASS = 1; const int CHILD_TEST_IGNORED = 2; -const int MSG_TYPE_MESSAGE = 0; // sizeof(Message) + Message -const int MSG_TYPE_PERF_TIME = 1; // perfTime + maxTime - int closeOutput() { int devnull; int retcode = -1; @@ -113,7 +112,6 @@ PipeWrapper::Status PipeWrapper::send(int code, std::string &message) std::ostringstream output; output << toBinaryString(code); - output << toBinaryString(MSG_TYPE_MESSAGE); output << toBinaryString(static_cast(message.size())); output << message; @@ -129,21 +127,16 @@ PipeWrapper::Status PipeWrapper::send(int code, std::string &message) return SUCCESS; } -PipeWrapper::Status PipeWrapper::sendTime(int code, - std::chrono::system_clock::duration time, - std::chrono::system_clock::duration timeMax) +PipeWrapper::Status PipeWrapper::sendPerformance(const ConstPerformanceResultPtr &performance) { + int foo = 0; if (m_pipefd[1] == PIPE_CLOSED) { return ERROR; } + if (!performance) + return writeHelp(&foo, sizeof(int)); - std::ostringstream output; - output << toBinaryString(code); - output << toBinaryString(MSG_TYPE_PERF_TIME); - output << toBinaryString(time); - output << toBinaryString(timeMax); - - std::string binary = output.str(); + std::string binary = performance->ToBinaryString(); int size = binary.size(); if ((writeHelp(&size, @@ -156,10 +149,8 @@ PipeWrapper::Status PipeWrapper::sendTime(int code, } PipeWrapper::Status PipeWrapper::receive(int &code, - int &msgType, std::string &data, - std::chrono::system_clock::duration &time, - std::chrono::system_clock::duration &timeMax, + PerformanceResultPtr &performance, time_t deadline) { if (m_pipefd[0] == PIPE_CLOSED) { @@ -185,24 +176,34 @@ PipeWrapper::Status PipeWrapper::receive(int &code, queue.AppendCopy(&buffer[0], size); queue.FlattenConsume(&code, sizeof(int)); - queue.FlattenConsume(&msgType, sizeof(int)); - - switch (msgType) { - case MSG_TYPE_MESSAGE: - queue.FlattenConsume(&size, sizeof(int)); - - buffer.resize(size); - - queue.FlattenConsume(&buffer[0], size); - data.assign(buffer.begin(), buffer.end()); - break; - case MSG_TYPE_PERF_TIME: - queue.FlattenConsume(&time, sizeof(std::chrono::system_clock::duration)); - queue.FlattenConsume(&timeMax, sizeof(std::chrono::system_clock::duration)); - break; - default: - return ERROR; + queue.FlattenConsume(&size, sizeof(int)); + + buffer.resize(size); + + queue.FlattenConsume(&buffer[0], size); + data.assign(buffer.begin(), buffer.end()); + + if (code != CHILD_TEST_PASS) + return SUCCESS; + + if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) { + return ret; } + + if (size == 0) { + performance = nullptr; + return SUCCESS; + } + + buffer.resize(size); + + if ((ret = readHelp(buffer.data(), size, deadline)) != SUCCESS) { + return ret; + } + + queue.AppendCopy(buffer.data(), size); + + performance.reset(new PerformanceResult(queue)); } catch (DPL::BinaryQueue::Exception::Base &e) { return ERROR; } @@ -222,13 +223,6 @@ std::string PipeWrapper::toBinaryString(int data) return std::string(buffer, buffer + sizeof(int)); } -std::string PipeWrapper::toBinaryString(std::chrono::system_clock::duration data) -{ - char buffer[sizeof(std::chrono::system_clock::duration)]; - memcpy(buffer, &data, sizeof(std::chrono::system_clock::duration)); - return std::string(buffer, buffer + sizeof(std::chrono::system_clock::duration)); -} - void PipeWrapper::closeHelp(int desc) { if (m_pipefd[desc] != PIPE_CLOSED) { @@ -297,13 +291,13 @@ void RunChildProc(TestRunner::TestCase procChild) { PipeWrapper pipe; if (!pipe.isReady()) { - throw TestRunner::TestFailed("Pipe creation failed"); + throw TestFailed("Pipe creation failed"); } pid_t pid = fork(); if (pid == -1) { - throw TestRunner::TestFailed("Child creation failed"); + throw TestFailed("Child creation failed"); } if (pid != 0) { @@ -311,12 +305,10 @@ void RunChildProc(TestRunner::TestCase procChild) pipe.setUsage(PipeWrapper::READONLY); int code; - int msgType; - std::chrono::system_clock::duration time_m; - std::chrono::system_clock::duration timeMax_m; std::string message; + PerformanceResultPtr performance; - int pipeReturn = pipe.receive(code, msgType, message, time_m, timeMax_m, time(0) + 10); + int pipeReturn = pipe.receive(code, message, performance, time(0) + 10); if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error pipe.closeAll(); @@ -327,23 +319,19 @@ void RunChildProc(TestRunner::TestCase procChild) waitpid(pid, &status, 0); if (pipeReturn == PipeWrapper::TIMEOUT) { - throw TestRunner::TestFailed("Timeout"); + throw TestFailed("Timeout"); } if (pipeReturn == PipeWrapper::ERROR) { - throw TestRunner::TestFailed("Reading pipe error"); + throw TestFailed("Reading pipe error"); } - if (code == CHILD_TEST_PASS && msgType == MSG_TYPE_PERF_TIME) { - DPL::Test::TestRunnerSingleton::Instance().setCurrentTestCasePerformanceResult(true, - time_m, - timeMax_m); - } + TestRunnerSingleton::Instance().setCurrentTestCasePerformanceResult(performance); if (code == CHILD_TEST_FAIL) { - throw TestRunner::TestFailed(message); + throw TestFailed(message); } else if (code == CHILD_TEST_IGNORED) { - throw TestRunner::Ignored(message); + throw TestIgnored(message); } } else { // child code @@ -353,9 +341,6 @@ void RunChildProc(TestRunner::TestCase procChild) int code = CHILD_TEST_PASS; std::string msg; - bool isPerformanceTest; - std::chrono::system_clock::duration time_m; - std::chrono::system_clock::duration timeMax_m; bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs(); @@ -368,10 +353,10 @@ void RunChildProc(TestRunner::TestCase procChild) try { procChild(); - } catch (const DPL::Test::TestRunner::TestFailed &e) { + } catch (const DPL::Test::TestFailed &e) { msg = e.GetMessage(); code = CHILD_TEST_FAIL; - } catch (const DPL::Test::TestRunner::Ignored &e) { + } catch (const DPL::Test::TestIgnored &e) { msg = e.GetMessage(); code = CHILD_TEST_IGNORED; } catch (...) { // catch all exception generated by "user" code @@ -383,16 +368,10 @@ void RunChildProc(TestRunner::TestCase procChild) closeOutput(); } - DPL::Test::TestRunnerSingleton::Instance().getCurrentTestCasePerformanceResult(isPerformanceTest, - time_m, - timeMax_m); - - if (code == CHILD_TEST_PASS && isPerformanceTest){ - pipe.sendTime(code, - time_m, - timeMax_m); - } else { - pipe.send(code, msg); + pipe.send(code, msg); + if (code == CHILD_TEST_PASS){ + pipe.sendPerformance(TestRunnerSingleton::Instance() \ + .getCurrentTestCasePerformanceResult()); } } } diff --git a/src/framework/src/test_runner_multiprocess.cpp b/src/framework/src/test_runner_multiprocess.cpp index 989654a..55e889b 100644 --- a/src/framework/src/test_runner_multiprocess.cpp +++ b/src/framework/src/test_runner_multiprocess.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014-2015 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* +/** * @file test_runner_multiprocess.cpp * @author Marcin Niesluchowski (m.niesluchow@samsung.com) * @version 1.0 @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include #include @@ -141,16 +143,16 @@ void RunMultiProc(TestRunner::TestCase procMulti) pid_t top_pid = getpid(); if (!pipe.isReady()) { - throw TestRunner::TestFailed("Pipe creation failed"); + throw TestFailed("Pipe creation failed"); } // pipe try { procMulti(); - } catch (const TestRunner::TestFailed &e) { + } catch (const TestFailed &e) { code = MULTI_TEST_FAILED; msg = e.GetMessage(); - } catch (const TestRunner::Ignored &e) { + } catch (const TestIgnored &e) { code = MULTI_TEST_IGNORED; msg = e.GetMessage(); } catch (const std::exception &) { @@ -180,10 +182,10 @@ void RunMultiProc(TestRunner::TestCase procMulti) } if (pipeReturn == PipeWrapper::ERROR) { pipe.closeAll(); - throw TestRunner::TestFailed("Reading pipe error"); + throw TestFailed("Reading pipe error"); } else if (pipeReturn == PipeWrapper::TIMEOUT) { pipe.closeAll(); - throw TestRunner::TestFailed("Timeout error"); + throw TestFailed("Timeout error"); } msg = msg + "\n" + recMsg; } @@ -193,11 +195,11 @@ void RunMultiProc(TestRunner::TestCase procMulti) case MULTI_TEST_PASS: return; case MULTI_TEST_FAILED: - throw TestRunner::TestFailed(msg); + throw TestFailed(msg); case MULTI_TEST_IGNORED: - throw TestRunner::Ignored(msg); + throw TestIgnored(msg); default: - throw TestRunner::TestFailed(msg); + throw TestFailed(msg); } } else { pipe.setUsage(PipeWrapper::WRITEONLY); diff --git a/src/security-tests-all.sh b/src/security-tests-all.sh index a1fe677..653971a 100644 --- a/src/security-tests-all.sh +++ b/src/security-tests-all.sh @@ -54,7 +54,7 @@ function printSummary runTest smack runTest smack-dbus -#runTest libprivilege-control +runTest libprivilege-control #runTest ss-clientsmack #runTest ss-server #runTest ss-password @@ -62,6 +62,7 @@ runTest smack-dbus #runTest ss-stress runTest security-manager runTest cynara +runTest ckm printSummary diff --git a/src/security-tests.sh b/src/security-tests.sh index db3221c..f99127b 100644 --- a/src/security-tests.sh +++ b/src/security-tests.sh @@ -88,13 +88,19 @@ case $1 in echo cynara-test "${@:2}" ;; +"ckm") + echo "=========================================================================" + echo "KEY MANAGER TESTS" + echo + ckm-tests "${@:2}" + ;; *) echo "Correct using:" echo " security_test.sh " echo echo "modules: smack, smack-dbus, libprivilege-control, ss-clientsmack" echo " ss-server, ss-api-speed, ss-password, ss-stress" - echo " ss-privilege, security-manager, cynara" + echo " ss-privilege, security-manager, cynara, ckm" ;; esac diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..b1b4d87 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (c) 2015 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. +# + +cmake_minimum_required(VERSION 2.8.3) + +INCLUDE(FindPkgConfig) +SET(INNER_TARGET_TEST "security-tests-inner-test") + +PKG_CHECK_MODULES(INNER_TARGET_DEP + REQUIRED + glib-2.0 + ) + +#files to compile +SET(INNER_TARGET_TEST_SOURCES + ${PROJECT_SOURCE_DIR}/tests/inner-test.cpp + ${PROJECT_SOURCE_DIR}/tests/common/test_cases_timeout.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/test_cases_deferred.cpp + ) + +#header directories +INCLUDE_DIRECTORIES(SYSTEM + ${INNER_TARGET_DEP_INCLUDE_DIRS} + ) + +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR}/src/framework/include/ + ${PROJECT_SOURCE_DIR}/src/ + ) + +#output format +ADD_EXECUTABLE(${INNER_TARGET_TEST} ${INNER_TARGET_TEST_SOURCES}) + +#linker directories +TARGET_LINK_LIBRARIES(${INNER_TARGET_TEST} + ${INNER_TARGET_DEP_LIBRARIES} + tests-common + dpl-test-framework + ) + +#place for output file +INSTALL(TARGETS ${INNER_TARGET_TEST} + DESTINATION /usr/bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) diff --git a/tests/common/test_cases_timeout.cpp b/tests/common/test_cases_timeout.cpp new file mode 100644 index 0000000..f11ad41 --- /dev/null +++ b/tests/common/test_cases_timeout.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015 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 test_cases_timeout.cpp + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief Inner tests for timeout mechanism + */ + +#include +#include +#include + +#include +#include + +RUNNER_TEST_GROUP_INIT(TIMEOUT) + +void timeout_test_ret(int waitDuration, int functionDuration, Timeout::ExpectMode expect) { + float fRet = 3.1415; + auto ret = Timeout::callAndWait(std::chrono::seconds(waitDuration), expect, + Timeout::CancelFunction(), + ([fRet](int sec) -> float { + std::this_thread::sleep_for(std::chrono::seconds(sec)); + return fRet; + }), functionDuration); + RUNNER_ASSERT_MSG(ret == fRet, + "Function returned = " << ret << " while expected value was " << fRet); +} + +RUNNER_TEST(it01_expected_timeout) +{ + timeout_test_ret(3, 5, Timeout::ExpectMode::TIMEOUT); +} + +RUNNER_TEST(it02_unexpected_finish) +{ + bool thrown = false; + try { + timeout_test_ret(3, 5, Timeout::ExpectMode::FINISHED); + } catch (const DPL::Test::TestException&) { + thrown = true; + } + RUNNER_ASSERT_MSG(thrown, + "Test should throw DPL::Test::TestException"); +} + +RUNNER_TEST(it03_ignored_timeout) +{ + timeout_test_ret(3, 5, Timeout::ExpectMode::IGNORE); +} + +RUNNER_TEST(it04_expected_finish) +{ + timeout_test_ret(5, 3, Timeout::ExpectMode::FINISHED); +} + +RUNNER_TEST(it05_unexpected_timeout) +{ + bool thrown = false; + try { + timeout_test_ret(5, 3, Timeout::ExpectMode::TIMEOUT); + } catch (const DPL::Test::TestException&) { + thrown = true; + } + RUNNER_ASSERT_MSG(thrown, + "Test should throw DPL::Test::TestException"); +} + +RUNNER_TEST(it06_ignored_finish) +{ + timeout_test_ret(5, 3, Timeout::ExpectMode::IGNORE); +} + +void timeout_test_throw(int waitDuration, int functionDuration, Timeout::ExpectMode expect) { + std::string exceptionString("exceptionString"); + bool thrown = false; + try { + Timeout::callAndWait(std::chrono::seconds(waitDuration), expect, + Timeout::CancelFunction(), + ([exceptionString](int sec) -> float { + std::this_thread::sleep_for(std::chrono::seconds(sec)); + throw exceptionString; + }), functionDuration); + } catch (const std::string &str) { + RUNNER_ASSERT_MSG(str == exceptionString, + "Function thrown = " << str + << " while expected value was " << exceptionString); + thrown = true; + } + RUNNER_ASSERT_MSG(thrown, + "Test should throw std::string(" << exceptionString << ")"); +} + +RUNNER_TEST(it07_throw_expected_timeout) +{ + timeout_test_throw(3, 5, Timeout::ExpectMode::TIMEOUT); +} + +RUNNER_TEST(it08_throw_unexpected_finish) +{ + bool thrown = false; + try { + timeout_test_throw(3, 5, Timeout::ExpectMode::FINISHED); + } catch (const DPL::Test::TestException&) { + thrown = true; + } + RUNNER_ASSERT_MSG(thrown, + "Test should throw DPL::Test::TestException"); +} + +RUNNER_TEST(it09_throw_ignored_timeout) +{ + timeout_test_throw(3, 5, Timeout::ExpectMode::IGNORE); +} + +RUNNER_TEST(it10_throw_expected_finish) +{ + timeout_test_throw(5, 3, Timeout::ExpectMode::FINISHED); +} + +RUNNER_TEST(it11_throw_unexpected_timeout) +{ + bool thrown = false; + try { + timeout_test_throw(5, 3, Timeout::ExpectMode::TIMEOUT); + } catch (const DPL::Test::TestException&) { + thrown = true; + } + RUNNER_ASSERT_MSG(thrown, + "Test should throw DPL::Test::TestException"); +} + +RUNNER_TEST(it12_throw_ignored_finish) +{ + timeout_test_throw(5, 3, Timeout::ExpectMode::IGNORE); +} diff --git a/tests/framework/test_cases_deferred.cpp b/tests/framework/test_cases_deferred.cpp new file mode 100644 index 0000000..036bc0f --- /dev/null +++ b/tests/framework/test_cases_deferred.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015 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 test_cases_deferred.cpp + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief Inner tests for defer macros mechanism + */ + +#include +#include + +#define EXPECT_EXCEPTION(expectedCatch, F) { \ + bool catched = false; \ + try { \ + F; \ + } catch (const DPL::Test::TestException & ex) { \ + catched = true; \ + } \ + RUNNER_ASSERT_MSG(catched == expectedCatch, \ + "Exception catched = " << catched \ + << " while expected is = " << expectedCatch); \ +} + +#define FILTER(F) { \ + try { \ + F; \ + } catch (...) { \ + } \ +} + +#define TRYCATCH(F) { \ + RUNNER_DEFER_TRYCATCH( \ + F; \ + ); \ +} + +#define SCOPE(F) { \ + RUNNER_DEFER_SCOPE( \ + F; \ + ); \ +} + +void fail(void) +{ + RUNNER_FAIL_MSG("Oops!"); +} + +void pass(void) +{ +} + +RUNNER_TEST_GROUP_INIT(DEFERRED) + +RUNNER_TEST(id01_simple_fail) +{ + EXPECT_EXCEPTION(true, fail()); +} + +RUNNER_TEST(id02_filtred_fail) +{ + EXPECT_EXCEPTION(false, FILTER(fail())); +} + +RUNNER_TEST(id03_saved_filtred_rethrown_fail) +{ + EXPECT_EXCEPTION(true, SCOPE(FILTER(TRYCATCH(fail())))); +} + +RUNNER_TEST(id04_saved_filtred_fail) +{ + EXPECT_EXCEPTION(false, FILTER(TRYCATCH(fail()))); +} + +RUNNER_TEST(id05_filtred_rethrown_fail) +{ + EXPECT_EXCEPTION(false, SCOPE(FILTER(fail()))); +} + +RUNNER_TEST(id06_saved_rethrown_fail) +{ + EXPECT_EXCEPTION(true, SCOPE(TRYCATCH(fail()))); +} + +RUNNER_TEST(id07_saved_fail) +{ + EXPECT_EXCEPTION(true, TRYCATCH(fail())); +} + +RUNNER_TEST(id08_rethrown_fail) +{ + EXPECT_EXCEPTION(true, SCOPE(fail())); +} + +RUNNER_TEST(id09_nested_scope) +{ + EXPECT_EXCEPTION(true, SCOPE(SCOPE(SCOPE(FILTER(TRYCATCH(fail())))))); +} + +RUNNER_TEST(id10_nested_scope2) +{ + EXPECT_EXCEPTION(true, SCOPE(SCOPE(FILTER(SCOPE(TRYCATCH(fail())))))); +} + +RUNNER_TEST(id11_saved_filtred_rethrown_pass) +{ + EXPECT_EXCEPTION(false, SCOPE(FILTER(TRYCATCH(pass())))); +} diff --git a/tests/inner-test.cpp b/tests/inner-test.cpp new file mode 100644 index 0000000..052acfa --- /dev/null +++ b/tests/inner-test.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015 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. + */ + +#include + +int main (int argc, char *argv[]) +{ + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); + return status; +}