From 5b85d5b5919f51cd5fab118a7bb86153a7120ccb Mon Sep 17 00:00:00 2001 From: Tomasz Iwanek Date: Thu, 11 Jul 2013 17:29:52 +0200 Subject: [PATCH] [DPL] ProcessPipe [Issue#] LINUXWRT-639 [Feature] Utility to spawn subprocess o read and write bytes through named pipes [Cause] N/A [Solution] This will be used in tests. Whats more this was problem in wrt-extra for some tests. [Verification] Build repository with tests and with WITH_CHILD ON. Run tests: wrt-commons-tests-test --output=text --regexp='ProcessPipe_' #all should pass Change-Id: I92915b53b9542cd2e523e42669e37ebd050eaf81 --- modules/test/config.cmake | 2 + modules/test/include/dpl/test/process_pipe.h | 62 ++++++++++ modules/test/src/process_pipe.cpp | 83 +++++++++++++ tests/test/CMakeLists.txt | 3 +- tests/test/test_process_pipe.cpp | 119 +++++++++++++++++++ 5 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 modules/test/include/dpl/test/process_pipe.h create mode 100644 modules/test/src/process_pipe.cpp create mode 100644 tests/test/test_process_pipe.cpp diff --git a/modules/test/config.cmake b/modules/test/config.cmake index d3485cf..d08366c 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/process_pipe.cpp PARENT_SCOPE ) @@ -31,6 +32,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/process_pipe.h PARENT_SCOPE ) diff --git a/modules/test/include/dpl/test/process_pipe.h b/modules/test/include/dpl/test/process_pipe.h new file mode 100644 index 0000000..52ab7e7 --- /dev/null +++ b/modules/test/include/dpl/test/process_pipe.h @@ -0,0 +1,62 @@ +/* + * 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 process_pipe.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation pipe from process + */ +#ifndef PROCESS_PIPE_H +#define PROCESS_PIPE_H + +#include +#include + +#include + +namespace DPL { + +class ProcessPipe : public FileInput +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DoubleOpen) + }; + + enum class PipeErrorPolicy + { + NONE, + OFF, + PIPE + }; + + explicit ProcessPipe(PipeErrorPolicy err = PipeErrorPolicy::NONE); + virtual ~ProcessPipe(); + + void Open(const std::string &command); + void Close(); + +private: + FILE * m_file; + PipeErrorPolicy m_errPolicy; +}; + +} + +#endif // PROCESS_PIPE_H diff --git a/modules/test/src/process_pipe.cpp b/modules/test/src/process_pipe.cpp new file mode 100644 index 0000000..68c910f --- /dev/null +++ b/modules/test/src/process_pipe.cpp @@ -0,0 +1,83 @@ +/* + * 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 process_pipe.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation pipe from process + */ + +#include +#include + +namespace DPL { + +ProcessPipe::ProcessPipe(PipeErrorPolicy err) : m_file(NULL), m_errPolicy(err) +{ +} + +ProcessPipe::~ProcessPipe() +{ +} + +void ProcessPipe::Open(const std::string & command) +{ + if(m_file != NULL) + { + ThrowMsg(Exception::DoubleOpen, "Trying to open pipe second time. Close it first"); + } + + std::string stdErrRedirection; + switch(m_errPolicy) + { + case PipeErrorPolicy::NONE: break; + case PipeErrorPolicy::OFF: stdErrRedirection = " 2>/dev/null"; break; + case PipeErrorPolicy::PIPE: stdErrRedirection = " 2>&1"; break; + default: break; + } + + std::string fcommand = command + stdErrRedirection; + FILE * file = popen(fcommand.c_str(), "r"); + + // Throw an exception if an error occurred + if (file == NULL) { + ThrowMsg(FileInput::Exception::OpenFailed, fcommand); + } + + // Save new descriptor + m_file = file; + m_fd = fileno(m_file); + + LogPedantic("Opened pipe: " << fcommand); +} + +void ProcessPipe::Close() +{ + if (m_fd == -1) { + return; + } + + if (pclose(m_file) == -1) { + Throw(FileInput::Exception::CloseFailed); + } + + m_fd = -1; + m_file = NULL; + + LogPedantic("Closed pipe"); +} + +} diff --git a/tests/test/CMakeLists.txt b/tests/test/CMakeLists.txt index 1c0bf55..48fb045 100644 --- a/tests/test/CMakeLists.txt +++ b/tests/test/CMakeLists.txt @@ -18,12 +18,13 @@ # @brief # -SET(TARGET_NAME "wrt-commons-tests-test-runner-child") +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_child.cpp + ${TESTS_DIR}/test/test_process_pipe.cpp ) #WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_UTILS_EFL}) diff --git a/tests/test/test_process_pipe.cpp b/tests/test/test_process_pipe.cpp new file mode 100644 index 0000000..ffc8a8d --- /dev/null +++ b/tests/test/test_process_pipe.cpp @@ -0,0 +1,119 @@ +/* + * 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_process_pipe.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of ProcessPipe tests + */ + +#include +#include +#include +#include + +#include + +using namespace DPL; + +RUNNER_TEST_GROUP_INIT(DPL) + +namespace { +void readAll(ProcessPipe & npp, BinaryQueue & result) +{ + do + { + BinaryQueueAutoPtr dataptr = npp.Read(4096); + + RUNNER_ASSERT_MSG(dataptr.get() != NULL, "Cannot read from pipe subprocess"); + + LogDebug("Size: " << dataptr->Size()); + + if(dataptr->Empty()) break; + result.AppendMoveFrom(*dataptr); + } + while(true); +} +} + +RUNNER_TEST(ProcessPipe_echo) +{ + ProcessPipe npp; + npp.Open("echo -e \"Test echo text\\nAnd new line\""); + BinaryQueue result; + readAll(npp, result); + npp.Close(); + + char buffer[100] = ""; + result.FlattenConsume(buffer, 99); + + RUNNER_ASSERT_MSG(strcmp(buffer, "Test echo text\nAnd new line\n") == 0, "Echoed text in not equal"); +} + +RUNNER_TEST(ProcessPipe_double_open) +{ + ProcessPipe npp; + npp.Open("echo \"Test \""); + Try + { + npp.Open("echo \"Test\""); + } + Catch(DPL::ProcessPipe::Exception::DoubleOpen) + { + npp.Close(); + return; + } + npp.Close(); + RUNNER_ASSERT_MSG(false, "DoubleOpen not thrown"); +} + +RUNNER_TEST(ProcessPipe_double_close) +{ + ProcessPipe npp; + npp.Open("echo \"Test invalid\""); + npp.Close(); + Try + { + npp.Close(); + } + Catch(DPL::Exception) + { + RUNNER_ASSERT_MSG(false, "Second Close throws exception"); + } +} + +RUNNER_TEST(ProcessPipe_pipeerror_off) +{ + ProcessPipe npp(ProcessPipe::PipeErrorPolicy::OFF); + npp.Open("ls /nonexistingdirectory"); + BinaryQueue result; + readAll(npp, result); //TODO: fix this test + npp.Close(); +} + +RUNNER_TEST(ProcessPipe_pipeerror_pipe) +{ + //ls output dependent... + ProcessPipe npp(ProcessPipe::PipeErrorPolicy::PIPE); + npp.Open("ls /nonexistingdirectory"); + BinaryQueue result; + readAll(npp, result); + npp.Close(); + char buffer[100] = ""; + result.FlattenConsume(buffer, 99); + + RUNNER_ASSERT_MSG(strcmp(buffer, "ls: cannot access /nonexistingdirectory: No such file or directory\n") == 0, "Ls error text in not equal"); +} -- 2.34.1