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