2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file test_runner_child.cpp
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief This file is the implementation file of test runner
23 #include <dpl/test/test_runner.h>
24 #include <dpl/test/test_runner_child.h>
25 #include <dpl/test/test_results_collector.h>
26 #include <dpl/binary_queue.h>
27 #include <dpl/exception.h>
28 #include <dpl/scoped_free.h>
29 #include <dpl/foreach.h>
30 #include <dpl/colors.h>
41 #include <sys/types.h>
43 #include <dpl/utils/wrt_global_settings.h>
46 const int PIPE_CLOSED = -1;
54 class PipeWrapper : DPL::Noncopyable {
68 if (-1 == pipe(m_pipefd)) {
69 m_pipefd[0] = PIPE_CLOSED;
70 m_pipefd[1] = PIPE_CLOSED;
75 return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED;
78 void setUsage(Usage usage) {
79 if (usage == READONLY) {
82 if (usage == WRITEONLY) {
91 Status send(int code, std::string &message) {
92 if (m_pipefd[1] == PIPE_CLOSED)
95 std::ostringstream output;
96 output << toBinaryString(code);
97 output << toBinaryString(static_cast<int>(message.size()));
100 std::string binary = output.str();
101 int size = binary.size();
103 if ((writeHelp(&size, sizeof(int)) == ERROR) || (writeHelp(binary.c_str(), size) == ERROR)) {
109 Status receive(int &code, std::string &data, time_t deadline) {
110 if (m_pipefd[0] == PIPE_CLOSED)
116 if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS)
119 std::vector<char> buffer;
122 if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS)
126 DPL::BinaryQueue queue;
127 queue.AppendCopy(&buffer[0], size);
129 queue.FlattenConsume(&code, sizeof(int));
130 queue.FlattenConsume(&size, sizeof(int));
134 queue.FlattenConsume(&buffer[0], size);
135 data.assign(buffer.begin(), buffer.end());
136 } catch (DPL::BinaryQueue::Exception::Base &e) {
147 std::string toBinaryString(int data) {
148 char buffer[sizeof(int)];
149 memcpy(buffer, &data, sizeof(int));
150 return std::string(buffer, buffer+sizeof(int));
154 void closeHelp(int desc) {
155 if (m_pipefd[desc] != PIPE_CLOSED) {
156 TEMP_FAILURE_RETRY(close(m_pipefd[desc]));
157 m_pipefd[desc] = PIPE_CLOSED;
161 Status writeHelp(const void *buffer, int size) {
163 const char *p = static_cast<const char *>(buffer);
164 while (ready != size) {
165 int ret = write(m_pipefd[1], &p[ready], size-ready);
167 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
180 Status readHelp(void *buf, int size, time_t deadline) {
182 char *buffer = static_cast<char*>(buf);
183 while (ready != size) {
184 time_t wait = deadline - time(0);
185 wait = wait < 1 ? 1 : wait;
186 pollfd fds = { m_pipefd[0], POLLIN, 0};
188 int pollReturn = poll(&fds, 1, wait * 1000);
190 if (pollReturn == 0) {
191 return TIMEOUT; // Timeout
194 if (pollReturn < -1) {
198 int ret = read(m_pipefd[0], &buffer[ready], size-ready);
200 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
203 if (ret == -1 || ret == 0) {
216 void RunChildProc(TestRunner::TestCase procChild){
218 if (!pipe.isReady()) {
219 throw TestRunner::TestFailed("Pipe creation failed");
225 throw TestRunner::TestFailed("Child creation failed");
229 pipe.setUsage(PipeWrapper::READONLY);
234 int pipeReturn = pipe.receive(code, message, time(0)+10);
236 if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error
242 waitpid(pid, &status, 0);
244 if (pipeReturn == PipeWrapper::TIMEOUT) {
245 throw TestRunner::TestFailed("Timeout");
248 if (pipeReturn == PipeWrapper::ERROR) {
249 throw TestRunner::TestFailed("Reading pipe error");
253 throw TestRunner::TestFailed(message);
258 // End Runner after current test
259 TestRunnerSingleton::Instance().terminate();
263 // close(0); // stdin
267 pipe.setUsage(PipeWrapper::WRITEONLY);
271 } catch (DPL::Test::TestRunner::TestFailed &e) {
272 msg = e.GetMessage();
274 } catch (...) { // Pokemon Catch... cache them all...
275 msg = "unhandled exeception";
278 pipe.send(code, msg);