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