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;
51 class PipeWrapper : DPL::Noncopyable
67 if (-1 == pipe(m_pipefd)) {
68 m_pipefd[0] = PIPE_CLOSED;
69 m_pipefd[1] = PIPE_CLOSED;
75 return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED;
78 void setUsage(Usage usage)
80 if (usage == READONLY) {
83 if (usage == WRITEONLY) {
93 Status send(int code, std::string &message)
95 if (m_pipefd[1] == PIPE_CLOSED) {
99 std::ostringstream output;
100 output << toBinaryString(code);
101 output << toBinaryString(static_cast<int>(message.size()));
104 std::string binary = output.str();
105 int size = binary.size();
107 if ((writeHelp(&size,
108 sizeof(int)) == ERROR) ||
109 (writeHelp(binary.c_str(), size) == ERROR))
116 Status receive(int &code, std::string &data, time_t deadline)
118 if (m_pipefd[0] == PIPE_CLOSED) {
125 if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) {
129 std::vector<char> buffer;
132 if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS) {
137 DPL::BinaryQueue queue;
138 queue.AppendCopy(&buffer[0], size);
140 queue.FlattenConsume(&code, sizeof(int));
141 queue.FlattenConsume(&size, sizeof(int));
145 queue.FlattenConsume(&buffer[0], size);
146 data.assign(buffer.begin(), buffer.end());
147 } catch (DPL::BinaryQueue::Exception::Base &e) {
160 std::string toBinaryString(int data)
162 char buffer[sizeof(int)];
163 memcpy(buffer, &data, sizeof(int));
164 return std::string(buffer, buffer + sizeof(int));
167 void closeHelp(int desc)
169 if (m_pipefd[desc] != PIPE_CLOSED) {
170 TEMP_FAILURE_RETRY(close(m_pipefd[desc]));
171 m_pipefd[desc] = PIPE_CLOSED;
175 Status writeHelp(const void *buffer, int size)
178 const char *p = static_cast<const char *>(buffer);
179 while (ready != size) {
180 int ret = write(m_pipefd[1], &p[ready], size - ready);
182 if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
196 Status readHelp(void *buf, int size, time_t deadline)
199 char *buffer = static_cast<char*>(buf);
200 while (ready != size) {
201 time_t wait = deadline - time(0);
202 wait = wait < 1 ? 1 : wait;
203 pollfd fds = { m_pipefd[0], POLLIN, 0 };
205 int pollReturn = poll(&fds, 1, wait * 1000);
207 if (pollReturn == 0) {
208 return TIMEOUT; // Timeout
211 if (pollReturn < -1) {
215 int ret = read(m_pipefd[0], &buffer[ready], size - ready);
217 if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
221 if (ret == -1 || ret == 0) {
234 void RunChildProc(TestRunner::TestCase procChild)
237 if (!pipe.isReady()) {
238 throw TestRunner::TestFailed("Pipe creation failed");
244 throw TestRunner::TestFailed("Child creation failed");
249 pipe.setUsage(PipeWrapper::READONLY);
254 int pipeReturn = pipe.receive(code, message, time(0) + 10);
256 if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error
262 waitpid(pid, &status, 0);
264 if (pipeReturn == PipeWrapper::TIMEOUT) {
265 throw TestRunner::TestFailed("Timeout");
268 if (pipeReturn == PipeWrapper::ERROR) {
269 throw TestRunner::TestFailed("Reading pipe error");
273 throw TestRunner::TestFailed(message);
278 // End Runner after current test
279 TestRunnerSingleton::Instance().Terminate();
284 bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs();
292 pipe.setUsage(PipeWrapper::WRITEONLY);
296 } catch (DPL::Test::TestRunner::TestFailed &e) {
297 msg = e.GetMessage();
299 } catch (...) { // Pokemon Catch... cache them all...
300 msg = "unhandled exeception";
309 pipe.send(code, msg);