Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_wearable / test / src / test_runner_multiprocess.cpp
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        test_runner_multiprocess.cpp
18  * @author      Marcin Niesluchowski (m.niesluchow@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of multiprocess test runner
21  */
22
23 #include <unistd.h>
24 #include <sys/file.h>
25 #include <dpl/test/test_runner.h>
26 #include <dpl/test/test_runner_child.h>
27 #include <dpl/test/test_runner_multiprocess.h>
28 #include <poll.h>
29 #include <limits.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32
33 namespace {
34
35 const int MULTI_TEST_ERROR    = -1;
36 const int MULTI_TEST_PASS     = 0;
37 const int MULTI_TEST_FAILED   = 1;
38 const int MULTI_TEST_IGNORED  = 2;
39 const int MULTI_TEST_INTERNAL = 3;
40
41 }
42
43 namespace DPL {
44 namespace Test {
45
46 SimplePipeWrapper::SimplePipeWrapper()
47 : PipeWrapper()
48 {
49
50 }
51
52 SimplePipeWrapper::~SimplePipeWrapper()
53 {
54
55 }
56
57 PipeWrapper::Status SimplePipeWrapper::send(std::string &message)
58 {
59     if (m_pipefd[1] == PIPE_CLOSED) {
60            return ERROR;
61     }
62
63     if (message.size() > PIPE_BUF-1) {
64         return ERROR;
65     }
66
67     char buffer[PIPE_BUF] = { 0 };
68
69
70     for(unsigned int i = 0; i < message.size(); ++i) {
71         buffer[i] = message[i];
72     }
73
74     return writeHelp(buffer, PIPE_BUF);
75 }
76
77 PipeWrapper::Status SimplePipeWrapper::receive(std::string &data, bool &empty, time_t deadline)
78 {
79     if (m_pipefd[0] == PIPE_CLOSED) {
80         return ERROR;
81     }
82
83     empty = false;
84
85     data.resize(PIPE_BUF);
86
87     char buffer[PIPE_BUF] = { 0 };
88
89     int ready = 0;
90     while (ready != PIPE_BUF) {
91         time_t wait = deadline - time(0);
92         wait = wait < 1 ? 1 : wait;
93         pollfd fds = { m_pipefd[0], POLLIN, 0 };
94
95         int pollReturn = poll(&fds, 1, wait * 1000);
96
97         if (pollReturn == 0) {
98             return TIMEOUT; // Timeout
99         }
100
101         if (pollReturn < -1) {
102             return ERROR;
103         }
104         int ret = read(m_pipefd[0], &buffer[ready], PIPE_BUF - ready);
105         if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
106             continue;
107         }
108
109         if (ret == -1) {
110             closeHelp(0);
111             return ERROR;
112         }
113         if (ret == 0) {
114             empty = true;
115             break;
116         }
117
118         ready += ret;
119     }
120
121
122     for(unsigned int i = 0; i < PIPE_BUF; ++i){
123         if(buffer[i] == 0) {
124             data.resize(i);
125             return SUCCESS;
126         }
127         data[i] = buffer[i];
128     }
129
130     return ERROR;
131 }
132
133 void RunMultiProc(TestRunner::TestCase procMulti)
134 {
135     SimplePipeWrapper pipe;
136     int code = MULTI_TEST_PASS;
137     std::string msg = "";
138     int pipeReturn;
139
140     int waitStatus;
141
142     pid_t top_pid = getpid();
143
144     if (!pipe.isReady()) {
145         throw TestRunner::TestFailed("Pipe creation failed");
146     }
147     // pipe
148
149     try {
150         procMulti();
151     } catch (const TestRunner::TestFailed &e) {
152         code = MULTI_TEST_FAILED;
153         msg = e.GetMessage();
154     } catch (const TestRunner::Ignored &e) {
155         code = MULTI_TEST_IGNORED;
156         msg = e.GetMessage();
157     } catch (const DPL::Exception &e) {
158         code = MULTI_TEST_INTERNAL;
159         msg = "DPL exception:" + e.GetMessage();
160     } catch (const std::exception &) {
161         code = MULTI_TEST_INTERNAL;
162         msg = "std exception";
163     } catch (...) {
164         // Unknown exception failure
165         code = MULTI_TEST_INTERNAL;
166         msg = "unknown exception";
167     }
168
169     while (true) {
170         pid_t child_pid = wait(&waitStatus);
171         if (child_pid == -1) {
172             if (errno == ECHILD) {
173                 if (top_pid == getpid()) {
174                     std::string recMsg="";
175
176                     pipe.setUsage(PipeWrapper::READONLY);
177
178                     bool empty=false;
179                     while(true) {
180                         pipeReturn = pipe.receive(recMsg, empty, time(0) + 10);
181
182                         if (empty) {
183                             break;
184                         }
185                         if (pipeReturn == PipeWrapper::ERROR) {
186                             pipe.closeAll();
187                             throw TestRunner::TestFailed("Reading pipe error");
188                         } else if (pipeReturn == PipeWrapper::TIMEOUT) {
189                             pipe.closeAll();
190                             throw TestRunner::TestFailed("Timeout error");
191                         }
192                         msg = msg + "\n" + recMsg;
193                     }
194                     pipe.closeAll();
195
196                     switch(code) {
197                     case MULTI_TEST_PASS:
198                         return;
199                     case MULTI_TEST_FAILED:
200                         throw TestRunner::TestFailed(msg);
201                     case MULTI_TEST_IGNORED:
202                         throw TestRunner::Ignored(msg);
203                     case MULTI_TEST_INTERNAL:
204                         throw TestRunner::TestFailed(msg);
205                     default:
206                         throw TestRunner::TestFailed(msg);
207                     }
208                 } else {
209                     pipe.setUsage(PipeWrapper::WRITEONLY);
210
211                     pipeReturn = pipe.send(msg);
212
213                     if (pipeReturn == PipeWrapper::ERROR) {
214                         pipe.closeAll();
215                         code = MULTI_TEST_ERROR;
216                     }
217
218                     exit(code);
219                 }
220             }
221         } else if (WIFEXITED(waitStatus)) {
222             if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_FAILED) {
223                 switch (code) {
224                     case MULTI_TEST_PASS:
225                         code = MULTI_TEST_FAILED;
226                         break;
227                     case MULTI_TEST_FAILED:
228                         break;
229                     case MULTI_TEST_IGNORED:
230                         code = MULTI_TEST_FAILED;
231                         break;
232                     case MULTI_TEST_INTERNAL:
233                         break;
234                     default:
235                         break;
236                     }
237             } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_IGNORED) {
238                 switch (code) {
239                 case MULTI_TEST_PASS:
240                     code = MULTI_TEST_IGNORED;
241                     break;
242                 case MULTI_TEST_FAILED:
243                     break;
244                 case MULTI_TEST_IGNORED:
245                     break;
246                 case MULTI_TEST_INTERNAL:
247                     break;
248                 default:
249                     break;
250                 }
251             } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_INTERNAL) {
252                 switch (code) {
253                 case MULTI_TEST_PASS:
254                     code = MULTI_TEST_INTERNAL;
255                     break;
256                 case MULTI_TEST_FAILED:
257                     code = MULTI_TEST_INTERNAL;
258                     break;
259                 case MULTI_TEST_IGNORED:
260                     code = MULTI_TEST_INTERNAL;
261                     break;
262                 case MULTI_TEST_INTERNAL:
263                     break;
264                 default:
265                     break;
266                 }
267             } else  if ((signed char)WEXITSTATUS(waitStatus) != MULTI_TEST_PASS) {
268                 code = MULTI_TEST_ERROR;
269                 msg = "PROCESS BAD CODE RETURN";
270             }
271         }
272     }
273 }
274 } // namespace Test
275 } // namespace DPL