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