From a7ebffb2f71dd1f94d8eefc58f8fc7582915920d Mon Sep 17 00:00:00 2001 From: "sung-su.kim" Date: Wed, 4 Sep 2013 15:57:58 +0900 Subject: [PATCH] [Release] wrt-commons_0.2.151 Change-Id: Ib018f8e7921446fb4430f5f60eb189ef55ffef79 --- modules/core/config.cmake | 2 + modules/core/include/dpl/mutable_task_list.h | 53 ++++ modules/core/src/mutable_task_list.cpp | 104 +++++++ modules/test/config.cmake | 2 + modules/test/include/dpl/test/test_runner_child.h | 44 +++ .../include/dpl/test/test_runner_multiprocess.h | 60 ++++ modules/test/src/test_runner_child.cpp | 270 +++++++++--------- modules/test/src/test_runner_multiprocess.cpp | 273 ++++++++++++++++++ modules/utils/include/dpl/utils/path.h | 7 + modules/utils/src/path.cpp | 66 +++-- .../include/dpl/wrt-dao-ro/global_config.h | 15 + packaging/wrt-commons.spec | 2 +- tests/test/CMakeLists.txt | 1 + tests/test/runner_multiprocess.cpp | 309 +++++++++++++++++++++ tests/test/test_process_pipe.cpp | 4 +- tests/utils/path_tests.cpp | 57 +++- 16 files changed, 1102 insertions(+), 167 deletions(-) create mode 100644 modules/core/include/dpl/mutable_task_list.h create mode 100644 modules/core/src/mutable_task_list.cpp create mode 100644 modules/test/include/dpl/test/test_runner_multiprocess.h create mode 100644 modules/test/src/test_runner_multiprocess.cpp create mode 100644 tests/test/runner_multiprocess.cpp diff --git a/modules/core/config.cmake b/modules/core/config.cmake index 35bbbf3..33f25ea 100644 --- a/modules/core/config.cmake +++ b/modules/core/config.cmake @@ -38,6 +38,7 @@ SET(DPL_CORE_SOURCES ${PROJECT_SOURCE_DIR}/modules/core/src/file_input.cpp ${PROJECT_SOURCE_DIR}/modules/core/src/file_output.cpp ${PROJECT_SOURCE_DIR}/modules/core/src/lexical_cast.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/mutable_task_list.cpp ${PROJECT_SOURCE_DIR}/modules/core/src/mutex.cpp ${PROJECT_SOURCE_DIR}/modules/core/src/named_base_pipe.cpp ${PROJECT_SOURCE_DIR}/modules/core/src/named_output_pipe.cpp @@ -98,6 +99,7 @@ SET(DPL_CORE_HEADERS ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/foreach.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/generic_event.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/lexical_cast.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/mutable_task_list.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/mutex.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/named_base_pipe.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/named_input_pipe.h diff --git a/modules/core/include/dpl/mutable_task_list.h b/modules/core/include/dpl/mutable_task_list.h new file mode 100644 index 0000000..9facbd3 --- /dev/null +++ b/modules/core/include/dpl/mutable_task_list.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file mutable_task_list.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief Header file for task list + */ +#ifndef DPL_MUTABLE_TASK_LIST_H +#define DPL_MUTABLE_TASK_LIST_H + +#include +#include + +namespace DPL { +class MutableTaskList : + public Task +{ + private: + typedef std::list Tasks; + + Tasks m_tasks; + Tasks::iterator m_currentTask; + + bool m_running; + + protected: + void AddTask(Task *task); + + public: + MutableTaskList(); + virtual ~MutableTaskList(); + + bool NextStep(); + bool Abort(); + size_t GetStepCount() const; +}; +} // namespace DPL + +#endif // DPL_MUTABLE_TASK_LIST_H diff --git a/modules/core/src/mutable_task_list.cpp b/modules/core/src/mutable_task_list.cpp new file mode 100644 index 0000000..67576b8 --- /dev/null +++ b/modules/core/src/mutable_task_list.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file task_list.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief Implementation file for task list + */ +#include +#include +#include + +namespace DPL { +MutableTaskList::MutableTaskList() : + m_running(false) +{ + m_currentTask = m_tasks.end(); +} + +MutableTaskList::~MutableTaskList() +{ + for (Tasks::iterator i = m_tasks.begin(); i != m_tasks.end(); ++i) { + delete *i; + } +} + +void MutableTaskList::AddTask(Task *task) +{ + if(m_tasks.empty()) + { + m_tasks.push_back(task); + m_currentTask = m_tasks.begin(); + } + else + { + m_tasks.push_back(task); + } +} + +bool MutableTaskList::NextStep() +{ + m_running = true; + + Assert( + m_currentTask != m_tasks.end() && + "Task list is empty or all tasks done"); + + bool result = (*m_currentTask)->NextStep(); + + if (result) { + return true; + } + + return ++m_currentTask != m_tasks.end(); +} + +bool MutableTaskList::Abort() +{ + m_tasks.erase(m_currentTask, m_tasks.end()); + m_tasks.reverse(); + for (Tasks::iterator i = m_tasks.begin(); i != m_tasks.end();) { + //If given task does not have any "abortSteps", remove it from the list + if (!(*i)->Abort()) { + delete *i; + i = m_tasks.erase(i); + continue; + } + ++i; + } + + if (m_tasks.empty()) { + return false; + } + + m_currentTask = m_tasks.begin(); + + return true; +} + +size_t MutableTaskList::GetStepCount() const +{ + size_t count = 0; + + for (Tasks::const_iterator i = m_tasks.begin(); i != m_tasks.end(); ++i) { + count += (*i)->GetStepCount(); + } + + return count; +} + +} // namespace DPL diff --git a/modules/test/config.cmake b/modules/test/config.cmake index d08366c..7938eaf 100644 --- a/modules/test/config.cmake +++ b/modules/test/config.cmake @@ -23,6 +23,7 @@ SET(DPL_TEST_ENGINE_SOURCES ${PROJECT_SOURCE_DIR}/modules/test/src/test_results_collector.cpp ${PROJECT_SOURCE_DIR}/modules/test/src/test_runner.cpp ${PROJECT_SOURCE_DIR}/modules/test/src/test_runner_child.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/test_runner_multiprocess.cpp ${PROJECT_SOURCE_DIR}/modules/test/src/process_pipe.cpp PARENT_SCOPE ) @@ -32,6 +33,7 @@ SET(DPL_TEST_ENGINE_HEADERS ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_results_collector.h ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_runner.h ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_runner_child.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_runner_multiprocess.h ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/process_pipe.h PARENT_SCOPE ) diff --git a/modules/test/include/dpl/test/test_runner_child.h b/modules/test/include/dpl/test/test_runner_child.h index b20c371..1da0f1b 100644 --- a/modules/test/include/dpl/test/test_runner_child.h +++ b/modules/test/include/dpl/test/test_runner_child.h @@ -26,6 +26,50 @@ namespace DPL { namespace Test { + +class PipeWrapper : DPL::Noncopyable +{ + public: + enum Usage { + READONLY, + WRITEONLY + }; + + enum Status { + SUCCESS, + TIMEOUT, + ERROR + }; + + PipeWrapper(); + + bool isReady(); + + void setUsage(Usage usage); + + virtual ~PipeWrapper(); + + Status send(int code, std::string &message); + + Status receive(int &code, std::string &data, time_t deadline); + + void closeAll(); + + protected: + + std::string toBinaryString(int data); + + void closeHelp(int desc); + + Status writeHelp(const void *buffer, int size); + + Status readHelp(void *buf, int size, time_t deadline); + + static const int PIPE_CLOSED = -1; + + int m_pipefd[2]; +}; + void RunChildProc(TestRunner::TestCase procChild); } // namespace Test } // namespace DPL diff --git a/modules/test/include/dpl/test/test_runner_multiprocess.h b/modules/test/include/dpl/test/test_runner_multiprocess.h new file mode 100644 index 0000000..279b5ef --- /dev/null +++ b/modules/test/include/dpl/test/test_runner_multiprocess.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the header file of multiprocess test runner + */ +#ifndef DPL_TEST_RUNNER_MULTIPROCESS_H +#define DPL_TEST_RUNNER_MULTIPROCESS_H + +#include + +namespace DPL { +namespace Test { + +class SimplePipeWrapper : + public PipeWrapper +{ + public: + SimplePipeWrapper(); + + virtual ~SimplePipeWrapper(); + + Status send(std::string &message); + Status receive(std::string &data, bool &empty, time_t deadline); +}; + +void RunMultiProc(TestRunner::TestCase procMulti); +} // namespace Test +} // namespace DPL + +#define RUNNER_MULTIPROCESS_TEST(Proc) \ + void Proc(); \ + void Proc##Multi(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + DPL::Test::RunMultiProc(&Proc##Multi); \ + } \ + void Proc##Multi() + +#endif // DPL_TEST_RUNNER_MULTIPROCESS_H diff --git a/modules/test/src/test_runner_child.cpp b/modules/test/src/test_runner_child.cpp index db1ba29..8e793e8 100644 --- a/modules/test/src/test_runner_child.cpp +++ b/modules/test/src/test_runner_child.cpp @@ -45,8 +45,6 @@ #include namespace { -const int PIPE_CLOSED = -1; - const int CHILD_TEST_FAIL = 0; const int CHILD_TEST_PASS = 1; const int CHILD_TEST_IGNORED = 2; @@ -76,188 +74,172 @@ end: namespace DPL { namespace Test { -class PipeWrapper : DPL::Noncopyable + +PipeWrapper::PipeWrapper() { - public: - enum Usage { - READONLY, - WRITEONLY - }; - - enum Status { - SUCCESS, - TIMEOUT, - ERROR - }; - - PipeWrapper() - { - if (-1 == pipe(m_pipefd)) { - m_pipefd[0] = PIPE_CLOSED; - m_pipefd[1] = PIPE_CLOSED; - } + if (-1 == pipe(m_pipefd)) { + m_pipefd[0] = PIPE_CLOSED; + m_pipefd[1] = PIPE_CLOSED; } +} - bool isReady() - { - return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED; - } +PipeWrapper::~PipeWrapper() +{ + closeHelp(0); + closeHelp(1); +} - void setUsage(Usage usage) - { - if (usage == READONLY) { - closeHelp(1); - } - if (usage == WRITEONLY) { - closeHelp(0); - } +bool PipeWrapper::isReady() +{ + return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED; +} + +void PipeWrapper::setUsage(Usage usage) +{ + if (usage == READONLY) { + closeHelp(1); } - ~PipeWrapper() - { + if (usage == WRITEONLY) { closeHelp(0); - closeHelp(1); } +} - Status send(int code, std::string &message) - { - if (m_pipefd[1] == PIPE_CLOSED) { - return ERROR; - } +PipeWrapper::Status PipeWrapper::send(int code, std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } - std::ostringstream output; - output << toBinaryString(code); - output << toBinaryString(static_cast(message.size())); - output << message; + std::ostringstream output; + output << toBinaryString(code); + output << toBinaryString(static_cast(message.size())); + output << message; - std::string binary = output.str(); - int size = binary.size(); + std::string binary = output.str(); + int size = binary.size(); - if ((writeHelp(&size, - sizeof(int)) == ERROR) || - (writeHelp(binary.c_str(), size) == ERROR)) - { - return ERROR; - } - return SUCCESS; + if ((writeHelp(&size, + sizeof(int)) == ERROR) || + (writeHelp(binary.c_str(), size) == ERROR)) + { + return ERROR; } + return SUCCESS; +} - Status receive(int &code, std::string &data, time_t deadline) - { - if (m_pipefd[0] == PIPE_CLOSED) { - return ERROR; - } +PipeWrapper::Status PipeWrapper::receive(int &code, std::string &data, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } - int size; - Status ret; + int size; + Status ret; - if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) { - return ret; - } + if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) { + return ret; + } - std::vector buffer; - buffer.resize(size); + std::vector buffer; + buffer.resize(size); - if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS) { - return ret; - } + if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS) { + return ret; + } - try { - DPL::BinaryQueue queue; - queue.AppendCopy(&buffer[0], size); + try { + DPL::BinaryQueue queue; + queue.AppendCopy(&buffer[0], size); - queue.FlattenConsume(&code, sizeof(int)); - queue.FlattenConsume(&size, sizeof(int)); + queue.FlattenConsume(&code, sizeof(int)); + queue.FlattenConsume(&size, sizeof(int)); - buffer.resize(size); + buffer.resize(size); - queue.FlattenConsume(&buffer[0], size); - data.assign(buffer.begin(), buffer.end()); - } catch (DPL::BinaryQueue::Exception::Base &e) { - return ERROR; - } - return SUCCESS; + queue.FlattenConsume(&buffer[0], size); + data.assign(buffer.begin(), buffer.end()); + } catch (DPL::BinaryQueue::Exception::Base &e) { + return ERROR; } + return SUCCESS; +} - void closeAll() - { - closeHelp(0); - closeHelp(1); - } +void PipeWrapper::closeAll() +{ + closeHelp(0); + closeHelp(1); +} - private: - std::string toBinaryString(int data) - { - char buffer[sizeof(int)]; - memcpy(buffer, &data, sizeof(int)); - return std::string(buffer, buffer + sizeof(int)); - } +std::string PipeWrapper::toBinaryString(int data) +{ + char buffer[sizeof(int)]; + memcpy(buffer, &data, sizeof(int)); + return std::string(buffer, buffer + sizeof(int)); +} - void closeHelp(int desc) - { - if (m_pipefd[desc] != PIPE_CLOSED) { - TEMP_FAILURE_RETRY(close(m_pipefd[desc])); - m_pipefd[desc] = PIPE_CLOSED; - } +void PipeWrapper::closeHelp(int desc) +{ + if (m_pipefd[desc] != PIPE_CLOSED) { + TEMP_FAILURE_RETRY(close(m_pipefd[desc])); + m_pipefd[desc] = PIPE_CLOSED; } +} - Status writeHelp(const void *buffer, int size) - { - int ready = 0; - const char *p = static_cast(buffer); - while (ready != size) { - int ret = write(m_pipefd[1], &p[ready], size - ready); - - if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { - continue; - } +PipeWrapper::Status PipeWrapper::writeHelp(const void *buffer, int size) +{ + int ready = 0; + const char *p = static_cast(buffer); + while (ready != size) { + int ret = write(m_pipefd[1], &p[ready], size - ready); - if (ret == -1) { - closeHelp(1); - return ERROR; - } + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } - ready += ret; + if (ret == -1) { + closeHelp(1); + return ERROR; } - return SUCCESS; - } - Status readHelp(void *buf, int size, time_t deadline) - { - int ready = 0; - char *buffer = static_cast(buf); - while (ready != size) { - time_t wait = deadline - time(0); - wait = wait < 1 ? 1 : wait; - pollfd fds = { m_pipefd[0], POLLIN, 0 }; + ready += ret; + } + return SUCCESS; +} - int pollReturn = poll(&fds, 1, wait * 1000); +PipeWrapper::Status PipeWrapper::readHelp(void *buf, int size, time_t deadline) +{ + int ready = 0; + char *buffer = static_cast(buf); + while (ready != size) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; - if (pollReturn == 0) { - return TIMEOUT; // Timeout - } + int pollReturn = poll(&fds, 1, wait * 1000); - if (pollReturn < -1) { - return ERROR; - } + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } - int ret = read(m_pipefd[0], &buffer[ready], size - ready); + if (pollReturn < -1) { + return ERROR; + } - if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { - continue; - } + int ret = read(m_pipefd[0], &buffer[ready], size - ready); - if (ret == -1 || ret == 0) { - closeHelp(0); - return ERROR; - } + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } - ready += ret; + if (ret == -1 || ret == 0) { + closeHelp(0); + return ERROR; } - return SUCCESS; - } - int m_pipefd[2]; -}; + ready += ret; + } + return SUCCESS; +} void RunChildProc(TestRunner::TestCase procChild) { diff --git a/modules/test/src/test_runner_multiprocess.cpp b/modules/test/src/test_runner_multiprocess.cpp new file mode 100644 index 0000000..c242480 --- /dev/null +++ b/modules/test/src/test_runner_multiprocess.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.cpp + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of multiprocess test runner + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +const int MULTI_TEST_ERROR = -1; +const int MULTI_TEST_PASS = 0; +const int MULTI_TEST_FAILED = 1; +const int MULTI_TEST_IGNORED = 2; +const int MULTI_TEST_INTERNAL = 3; + +} + +namespace DPL { +namespace Test { + +SimplePipeWrapper::SimplePipeWrapper() +: PipeWrapper() +{ + +} + +SimplePipeWrapper::~SimplePipeWrapper() +{ + +} + +PipeWrapper::Status SimplePipeWrapper::send(std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + if (message.size() > PIPE_BUF-1) { + return ERROR; + } + + char buffer[PIPE_BUF] = { 0 }; + + + for(unsigned int i = 0; i < message.size(); ++i) { + buffer[i] = message[i]; + } + + return writeHelp(buffer, PIPE_BUF); +} + +PipeWrapper::Status SimplePipeWrapper::receive(std::string &data, bool &empty, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + empty = false; + + data.resize(PIPE_BUF); + + char buffer[PIPE_BUF] = { 0 }; + + int ready = 0; + while (ready != PIPE_BUF) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + int ret = read(m_pipefd[0], &buffer[ready], PIPE_BUF - ready); + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(0); + return ERROR; + } + if (ret == 0) { + empty = true; + break; + } + + ready += ret; + } + + + for(unsigned int i = 0; i < PIPE_BUF; ++i){ + if(buffer[i] == 0) { + data.resize(i); + return SUCCESS; + } + data[i] = buffer[i]; + } + + return ERROR; +} + +void RunMultiProc(TestRunner::TestCase procMulti) +{ + SimplePipeWrapper pipe; + int code = MULTI_TEST_PASS; + std::string msg = ""; + int pipeReturn; + + int waitStatus; + + pid_t top_pid = getpid(); + + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + // pipe + + try { + procMulti(); + } catch (const TestRunner::TestFailed &e) { + code = MULTI_TEST_FAILED; + msg = e.GetMessage(); + } catch (const TestRunner::Ignored &e) { + code = MULTI_TEST_IGNORED; + msg = e.GetMessage(); + } catch (const DPL::Exception &e) { + code = MULTI_TEST_INTERNAL; + msg = "DPL exception:" + e.GetMessage(); + } catch (const std::exception &) { + code = MULTI_TEST_INTERNAL; + msg = "std exception"; + } catch (...) { + // Unknown exception failure + code = MULTI_TEST_INTERNAL; + msg = "unknown exception"; + } + + while (true) { + pid_t child_pid = wait(&waitStatus); + if (child_pid == -1) { + if (errno == ECHILD) { + if (top_pid == getpid()) { + std::string recMsg=""; + + pipe.setUsage(PipeWrapper::READONLY); + + bool empty=false; + while(true) { + pipeReturn = pipe.receive(recMsg, empty, time(0) + 10); + + if (empty) { + break; + } + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + throw TestRunner::TestFailed("Reading pipe error"); + } else if (pipeReturn == PipeWrapper::TIMEOUT) { + pipe.closeAll(); + throw TestRunner::TestFailed("Timeout error"); + } + msg = msg + "\n" + recMsg; + } + pipe.closeAll(); + + switch(code) { + case MULTI_TEST_PASS: + return; + case MULTI_TEST_FAILED: + throw TestRunner::TestFailed(msg); + case MULTI_TEST_IGNORED: + throw TestRunner::Ignored(msg); + case MULTI_TEST_INTERNAL: + throw TestRunner::TestFailed(msg); + default: + throw TestRunner::TestFailed(msg); + } + } else { + pipe.setUsage(PipeWrapper::WRITEONLY); + + pipeReturn = pipe.send(msg); + + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + code = MULTI_TEST_ERROR; + } + + exit(code); + } + } + } else if (WIFEXITED(waitStatus)) { + if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_FAILED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_IGNORED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_IGNORED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_INTERNAL) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_FAILED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) != MULTI_TEST_PASS) { + code = MULTI_TEST_ERROR; + msg = "PROCESS BAD CODE RETURN"; + } + } + } +} +} // namespace Test +} // namespace DPL diff --git a/modules/utils/include/dpl/utils/path.h b/modules/utils/include/dpl/utils/path.h index ff7b544..67ffd43 100644 --- a/modules/utils/include/dpl/utils/path.h +++ b/modules/utils/include/dpl/utils/path.h @@ -116,10 +116,17 @@ public: * @return full path */ std::string Fullpath() const; + /** + * @brief Extension + * @return extension + */ + std::string Extension() const; bool Exists() const; bool IsDir() const; bool IsFile() const; + bool ExistsAndIsFile() const; + bool ExistsAndIsDir() const; bool IsSymlink() const; std::size_t Size() const; /** diff --git a/modules/utils/src/path.cpp b/modules/utils/src/path.cpp index 51b54aa..ea1653f 100644 --- a/modules/utils/src/path.cpp +++ b/modules/utils/src/path.cpp @@ -163,6 +163,23 @@ std::string Path::Fullpath() const return std::string ("/") + ret; } +std::string Path::Extension() const +{ + if(m_parts.empty()) return ""; + + const std::string& last = *--m_parts.end(); + + std::string::size_type pos = last.find_last_of("."); + if(pos != std::string::npos) + { + return last.substr(pos + 1); + } + else + { + return ""; + } +} + //foreach Path::Iterator Path::begin() const { @@ -215,6 +232,30 @@ bool Path::IsFile() const return S_ISREG(tmp.st_mode); } +bool Path::ExistsAndIsFile() const +{ + bool flag = false; + Try + { + flag = this->IsFile(); + } Catch (Path::NotExists) { + LogPedantic(*this << "is not a file."); + } + return flag; +} + +bool Path::ExistsAndIsDir() const +{ + bool flag = false; + Try + { + flag = this->IsDir(); + } Catch (Path::NotExists) { + LogPedantic(*this << "is not a directory."); + } + return flag; +} + bool Path::IsSymlink() const { struct stat tmp; @@ -316,23 +357,16 @@ bool Path::isSubPath(const Path & other) const bool Path::hasExtension(const std::string& extension) const { - LogDebug("Looking for extension " << extension << " in: " << this->Filename()); - - size_t extLen = extension.length(); - - if(m_parts.empty()) return false; - if(extLen == 0) return false; - - const std::string& last = *--m_parts.end(); - size_t lastLen = last.length(); - - if(lastLen < (1 + extLen)) return false; - - const char last_tmp = last[ lastLen - (1 + extLen) ]; - if(last_tmp != '.') return false; + LogPedantic("Looking for extension " << extension); - if(last.substr(lastLen - extLen) != extension) return false; - return true; + if(Extension() == extension) + { + return true; + } + else + { + return false; + } } void MakeDir(const Path & path, mode_t mode) diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h b/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h index 0eba4e4..ab41158 100644 --- a/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h @@ -292,6 +292,21 @@ inline const char* GetBackupDatabaseSuffix() { return ".backup"; } + +inline const char* GetManifestPath() +{ + return "/opt/share/packages"; +} + +inline const char* GetPreloadManifestPath() +{ + return "/usr/share/packages"; +} + +inline const char* GetRecoveryStatusPath() +{ + return "/usr/share/packages/.recovery/wgt"; +} } // namespace GlobalConfig } // namespace WrtDB diff --git a/packaging/wrt-commons.spec b/packaging/wrt-commons.spec index 5c31d04..4d6817a 100644 --- a/packaging/wrt-commons.spec +++ b/packaging/wrt-commons.spec @@ -1,7 +1,7 @@ #git:framework/web/wrt-commons Name: wrt-commons Summary: Wrt common library -Version: 0.2.150 +Version: 0.2.151 Release: 1 Group: Development/Libraries License: Apache License, Version 2.0 diff --git a/tests/test/CMakeLists.txt b/tests/test/CMakeLists.txt index 48fb045..500e52b 100644 --- a/tests/test/CMakeLists.txt +++ b/tests/test/CMakeLists.txt @@ -23,6 +23,7 @@ SET(TARGET_NAME "wrt-commons-tests-test") # Set DPL tests sources SET(DPL_TESTS_UTIL_SOURCES ${TESTS_DIR}/test/main.cpp + ${TESTS_DIR}/test/runner_multiprocess.cpp ${TESTS_DIR}/test/runner_child.cpp ${TESTS_DIR}/test/test_process_pipe.cpp ) diff --git a/tests/test/runner_multiprocess.cpp b/tests/test/runner_multiprocess.cpp new file mode 100644 index 0000000..fcac88e --- /dev/null +++ b/tests/test/runner_multiprocess.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file runner_multiprocess.cpp + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for engine internal tests + */ + +#include +#include +#include +#include + +namespace { +std::list split_string(std::string str, std::string delimiter) +{ + size_t pos = 0; + std::string token; + std::list stringList; + while ((pos = str.find(delimiter)) != std::string::npos) { + token = str.substr(0, pos); + stringList.push_back(token); + str.erase(0, pos + delimiter.length()); + } + if(str.length() != 0){ + stringList.push_back(token); + } + return stringList; +} +} + +#define RUNNER_MULTIPROCESS_TEST_EXPECT(name, messages) \ + static void testExpectFunction##name(); \ + RUNNER_TEST(name) \ + { \ + Try \ + { \ + DPL::Test::RunMultiProc(&testExpectFunction##name); \ + } \ + Catch(DPL::Test::TestRunner::TestFailed) \ + { \ + std::string eMsg = messages; \ + std::list eMessages = split_string(eMsg, "|"); \ + std::string rMessage = _rethrown_exception.GetMessage(); \ + if(eMsg.length() == 0 && rMessage.length() != 0) { \ + RUNNER_ASSERT_MSG(false, rMessage); \ + } \ + bool failedFound = false; \ + for(std::list::iterator it = eMessages.begin(); \ + it != eMessages.end(); \ + ++it) \ + { \ + if (!(*it).compare("TEST_FAILED")) { \ + failedFound = true; \ + continue; \ + } \ + RUNNER_ASSERT_MSG(rMessage.find(*it)!=std::string::npos, \ + "Key word " << *it << " not found in " << rMessage); \ + } \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Reading pipe error")==std::string::npos, \ + "Reading pipe error"); \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Timeout error")==std::string::npos, \ + "Timeout error"); \ + RUNNER_ASSERT_MSG(failedFound, "No TEST_FAILED found"); \ + } \ + Catch(DPL::Test::TestRunner::Ignored) \ + { \ + std::string eMsg = messages; \ + std::list eMessages = split_string(eMsg, "|"); \ + std::string rMessage = _rethrown_exception.GetMessage(); \ + if(eMsg.length() == 0 && rMessage.length() != 0) { \ + RUNNER_ASSERT_MSG(false, rMessage); \ + } \ + bool ignoredFound = false; \ + for(std::list::iterator it = eMessages.begin(); \ + it != eMessages.end(); \ + ++it) \ + { \ + if (!(*it).compare("TEST_IGNORED")) { \ + ignoredFound = true; \ + continue; \ + } \ + RUNNER_ASSERT_MSG(rMessage.find(*it)!=std::string::npos, \ + "Key word " << *it << " not found in " << rMessage); \ + } \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Reading pipe error")==std::string::npos, \ + "Reading pipe error"); \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Timeout error")==std::string::npos, \ + "Timeout error"); \ + RUNNER_ASSERT_MSG(ignoredFound, "No TEST_IGNORED found"); \ + } \ + } \ + void testExpectFunction##name() \ + +RUNNER_TEST_GROUP_INIT(DPL_TESTS_TEST_MULTIPROCESS) + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm00_pass, "") +{ + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm01_pass, "") +{ + pid_t pid = fork(); + if(pid){ + sleep(2); + RUNNER_ASSERT_MSG(1, "This test should pass"); + } else { + RUNNER_ASSERT_MSG(1, "This test should pass"); + } + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm02_pass, "") +{ + pid_t pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(1, "This test should pass"); + } else { + sleep(2); + RUNNER_ASSERT_MSG(1, "This test should pass"); + } + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm03_pass, "") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + sleep(1); + } else { + sleep(2); + } + } else { + if(pid){ + sleep(2); + } else { + sleep(1); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm04_fail, "TEST_FAILED|" + "This test should fail") +{ + RUNNER_ASSERT_MSG(0, "This test should fail"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm05_fail,"TEST_FAILED|" + "Test failed 1|" + "Test failed 2|" + "Test failed 3|" + "Test failed 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 2"); + } + } else { + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 3"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm06_fail, "TEST_FAILED|" + "Test failed 1|" + "Test failed 2|" + "Test failed 3|" + "Test failed 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + sleep(2); + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 2"); + } + } else { + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 3"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm07_fail, "TEST_FAILED|" + "Test failed 1|" + "Test failed 2|" + "Test failed 3|" + "Test failed 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 2"); + } + } else { + pid = fork(); + if(pid){ + sleep(2); + RUNNER_ASSERT_MSG(0, "Test failed 3"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm08_fail_unknown_exception, "TEST_FAILED|" + "unknown exception") +{ + throw("hello"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm09_fail_unknown_exception, "TEST_FAILED|" + "unknown exception") +{ + throw(1); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm10_ignore, "TEST_IGNORED|" + "Test ignored") +{ + RUNNER_IGNORED_MSG("Test ignored"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm11_ignore, "TEST_IGNORED|" + "Test ignored 1|" + "Test ignored 2|" + "Test ignored 3|" + "Test ignored 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_IGNORED_MSG("Test ignored 1"); + } else { + RUNNER_IGNORED_MSG("Test ignored 2"); + } + } else { + pid = fork(); + if(pid){ + sleep(2); + RUNNER_IGNORED_MSG("Test ignored 3"); + } else { + RUNNER_IGNORED_MSG("Test ignored 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm12_fail, "TEST_FAILED|" + "Test failed 1|" + "Test ignored 2|" + "Test ignored 3|" + "Test ignored 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_IGNORED_MSG("Test ignored 2"); + } + } else { + pid = fork(); + if(pid){ + sleep(2); + RUNNER_IGNORED_MSG("Test ignored 3"); + } else { + RUNNER_IGNORED_MSG("Test ignored 4"); + } + } +} diff --git a/tests/test/test_process_pipe.cpp b/tests/test/test_process_pipe.cpp index ffc8a8d..46405f9 100644 --- a/tests/test/test_process_pipe.cpp +++ b/tests/test/test_process_pipe.cpp @@ -58,7 +58,7 @@ RUNNER_TEST(ProcessPipe_echo) npp.Close(); char buffer[100] = ""; - result.FlattenConsume(buffer, 99); + result.FlattenConsume(buffer, std::min(result.Size(), sizeof(buffer))); RUNNER_ASSERT_MSG(strcmp(buffer, "Test echo text\nAnd new line\n") == 0, "Echoed text in not equal"); } @@ -113,7 +113,7 @@ RUNNER_TEST(ProcessPipe_pipeerror_pipe) readAll(npp, result); npp.Close(); char buffer[100] = ""; - result.FlattenConsume(buffer, 99); + result.FlattenConsume(buffer, std::min(result.Size(), sizeof(buffer))); RUNNER_ASSERT_MSG(strcmp(buffer, "ls: cannot access /nonexistingdirectory: No such file or directory\n") == 0, "Ls error text in not equal"); } diff --git a/tests/utils/path_tests.cpp b/tests/utils/path_tests.cpp index 7ad96d2..0d29057 100644 --- a/tests/utils/path_tests.cpp +++ b/tests/utils/path_tests.cpp @@ -102,6 +102,26 @@ RUNNER_TEST(path_mkfile_exists) } /* +Name: path_exists_and_is_file_or_dir +Description: test for checking for existence of directory or file +Expected: success +*/ +RUNNER_TEST(path_exists_and_is_file_or_dir) +{ + DPL::ScopedDir sd(rootTest); + + Path file = Path(rootTest) / "testfile.txt"; + MakeEmptyFile(file); + RUNNER_ASSERT_MSG(file.ExistsAndIsFile(), "File should exist"); + RUNNER_ASSERT_MSG(!file.ExistsAndIsDir(), "It should not be a directory"); + + Path dir = Path(rootTest) / "testdir"; + MakeDir(dir); + RUNNER_ASSERT_MSG(dir.ExistsAndIsDir(), "Directory should exist"); + RUNNER_ASSERT_MSG(!dir.ExistsAndIsFile(), "Is should not be a file"); +} + +/* Name: path_mkfile_invalid_path Description: tries to create file in not exisitng directory Expected: failure at creation @@ -842,6 +862,36 @@ Expected: Proper recognition of extensions */ RUNNER_TEST(path_extension_test) { + Path path1("/path/to/file.dot"); + Path path2("/path/to/file..dot"); + Path path3("/path/to/file..dot."); + Path path4("/path/to/file..dot.dot"); + Path path5("/path/to.dot/file"); + Path path6("./path/to/file"); + Path path7("./path/to/file"); + Path path8("/path/../file.xml"); + Path path9("/path/../file.XML"); + Path path10("/path/../file.myfileextension"); + + RUNNER_ASSERT(path1.Extension() == "dot"); + RUNNER_ASSERT(path2.Extension() == "dot"); + RUNNER_ASSERT(path3.Extension() == ""); + RUNNER_ASSERT(path4.Extension() == "dot"); + RUNNER_ASSERT(path5.Extension() == ""); + RUNNER_ASSERT(path6.Extension() == ""); + RUNNER_ASSERT(path7.Extension() == ""); + RUNNER_ASSERT(path8.Extension() == "xml"); + RUNNER_ASSERT(path9.Extension() != "xml"); + RUNNER_ASSERT(path10.Extension() == "myfileextension"); +} + +/* +Name: path_has_extension_test +Description: Tests if file extension is correct +Expected: Proper recognition of extensions +*/ +RUNNER_TEST(path_has_extension_test) +{ Path dirTest = Path("extension"); @@ -873,7 +923,6 @@ RUNNER_TEST(path_extension_test) RUNNER_ASSERT_MSG(!path6.hasExtension(".JS"), "Wrong argument in hasExtension() function"); - RUNNER_ASSERT_MSG(!path3.hasExtension(""), "Extension length is 0"); - - RUNNER_ASSERT_MSG(!path4.hasExtension(""), "Not a directory"); -} \ No newline at end of file + RUNNER_ASSERT_MSG(path3.hasExtension(""), "Extension length should be 0"); + RUNNER_ASSERT_MSG(path4.hasExtension(""), "There should be no extension"); +} -- 2.7.4