(Automated Tests) Update test suite after changes to PlatformAbstraction
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / test-harness.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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 #include "test-harness.h"
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <vector>
23 #include <map>
24 #include <cstring>
25 #include <testcase.h>
26
27 namespace TestHarness
28 {
29
30 typedef std::map<int, TestCase> RunningTestCases;
31
32 namespace
33 {
34 const char* RED_COLOR="\e[1;31m";
35 const char* GREEN_COLOR="\e[1;32m";
36 const char* ASCII_RESET="\e[0m";
37 const char* ASCII_BOLD="\e[1m";
38 }
39
40
41 int RunTestCase( struct ::testcase_s& testCase )
42 {
43   int result = EXIT_STATUS_TESTCASE_FAILED;
44
45 // dont want to catch exception as we want to be able to get
46 // gdb stack trace from the first error
47 // by default tests should all always pass with no exceptions
48   if( testCase.startup )
49   {
50     testCase.startup();
51   }
52   result = testCase.function();
53   if( testCase.cleanup )
54   {
55     testCase.cleanup();
56   }
57
58   return result;
59 }
60
61
62 int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
63 {
64   int testResult = EXIT_STATUS_TESTCASE_FAILED;
65
66   int pid = fork();
67   if( pid == 0 ) // Child process
68   {
69     if( suppressOutput )
70     {
71       close(STDOUT_FILENO);
72       close(STDERR_FILENO);
73     }
74     exit( RunTestCase( testCase ) );
75   }
76   else if(pid == -1)
77   {
78     perror("fork");
79     exit(EXIT_STATUS_FORK_FAILED);
80   }
81   else // Parent process
82   {
83     int status = 0;
84     int childPid = waitpid(-1, &status, 0);
85     if( childPid == -1 )
86     {
87       perror("waitpid");
88       exit(EXIT_STATUS_WAITPID_FAILED);
89     }
90     if( WIFEXITED(status) )
91     {
92       if( childPid > 0 )
93       {
94         testResult = WEXITSTATUS(status);
95         if( testResult )
96         {
97           printf("Test case %s failed: %d\n", testCase.name, testResult);
98         }
99       }
100     }
101     else if(WIFSIGNALED(status) )
102     {
103       testResult = EXIT_STATUS_TESTCASE_ABORTED;
104
105 #ifdef WCOREDUMP
106       if(WCOREDUMP(status))
107       {
108         printf("Test case %s failed: due to a crash\n", testCase.name);
109       }
110 #endif
111       printf("Test case %s failed: exit with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
112     }
113     else if(WIFSTOPPED(status))
114     {
115       printf("Test case %s failed: stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
116     }
117   }
118   return testResult;
119 }
120
121 void OutputStatistics( int numPasses, int numFailures )
122 {
123   const char* failureColor = GREEN_COLOR;
124   if( numFailures > 0 )
125   {
126     failureColor = RED_COLOR;
127   }
128   printf("\rNumber of test passes:   %s%4d (%5.2f%%)%s\n", ASCII_BOLD, numPasses, 100.0f * (float)numPasses / (numPasses+numFailures),  ASCII_RESET);
129   printf("%sNumber of test failures:%s %s%4d%s\n", failureColor, ASCII_RESET, ASCII_BOLD, numFailures, ASCII_RESET);
130
131 }
132
133
134 int RunAll(const char* processName, ::testcase tc_array[], bool reRunFailed)
135 {
136   int numFailures = 0;
137   int numPasses = 0;
138
139   // Run test cases in child process( to kill output/handle signals ), but run serially.
140   for( unsigned int i=0; tc_array[i].name; i++)
141   {
142     int result = RunTestCaseInChildProcess( tc_array[i], true );
143     if( result == 0 )
144     {
145       numPasses++;
146     }
147     else
148     {
149       numFailures++;
150     }
151   }
152
153   OutputStatistics(numPasses, numFailures);
154
155   return numFailures;
156 }
157
158
159
160 // Constantly runs up to MAX_NUM_CHILDREN processes
161 int RunAllInParallel(  const char* processName, ::testcase tc_array[], bool reRunFailed)
162 {
163   int numFailures = 0;
164   int numPasses = 0;
165
166   RunningTestCases children;
167   std::vector<int> failedTestCases;
168
169   // Fork up to MAX_NUM_CHILDREN processes, then
170   // wait. As soon as a proc completes, fork the next.
171
172   int nextTestCase = 0;
173   int numRunningChildren = 0;
174
175   while( tc_array[nextTestCase].name || numRunningChildren > 0)
176   {
177     // Create more children (up to the max number or til the end of the array)
178     while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
179     {
180       int pid = fork();
181       if( pid == 0 ) // Child process
182       {
183         close(STDOUT_FILENO);
184         close(STDERR_FILENO);
185         exit( RunTestCase( tc_array[nextTestCase] ) );
186       }
187       else if(pid == -1)
188       {
189         perror("fork");
190         exit(EXIT_STATUS_FORK_FAILED);
191       }
192       else // Parent process
193       {
194         TestCase tc(nextTestCase, tc_array[nextTestCase].name);
195         children[pid] = tc;
196         nextTestCase++;
197         numRunningChildren++;
198       }
199     }
200
201     // Wait for the next child to finish
202
203     int status=0;
204     int childPid = waitpid(-1, &status, 0);
205     if( childPid == -1 )
206     {
207       perror("waitpid");
208       exit(EXIT_STATUS_WAITPID_FAILED);
209     }
210
211     if( WIFEXITED(status) )
212     {
213       if( childPid > 0 )
214       {
215         int testResult = WEXITSTATUS(status);
216         if( testResult )
217         {
218           printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
219           failedTestCases.push_back(children[childPid].testCase);
220           numFailures++;
221         }
222         else
223         {
224           numPasses++;
225         }
226         numRunningChildren--;
227       }
228     }
229
230     else if( WIFSIGNALED(status) || WIFSTOPPED(status))
231     {
232       status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
233
234       if( childPid > 0 )
235       {
236         RunningTestCases::iterator iter = children.find(childPid);
237         if( iter != children.end() )
238         {
239           printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
240           failedTestCases.push_back(iter->second.testCase);
241         }
242         else
243         {
244           printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
245         }
246
247         numFailures++;
248         numRunningChildren--;
249       }
250     }
251   }
252
253   OutputStatistics( numPasses, numFailures );
254
255   if( reRunFailed )
256   {
257     for( unsigned int i=0; i<failedTestCases.size(); i++)
258     {
259       char* testCaseStrapline;
260       int numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
261       printf("\n%s\n", testCaseStrapline);
262       for(int j=0; j<numChars; j++)
263       {
264         printf("=");
265       }
266       printf("\n");
267       RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
268     }
269   }
270
271   return numFailures;
272 }
273
274
275
276 int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
277 {
278   int result = EXIT_STATUS_TESTCASE_NOT_FOUND;
279
280   for( int i = 0; tc_array[i].name; i++ )
281   {
282     if( !strcmp(testCaseName, tc_array[i].name) )
283     {
284       return RunTestCase( tc_array[i] );
285     }
286   }
287
288   printf("Unknown testcase name: \"%s\"\n", testCaseName);
289   return result;
290 }
291
292 void Usage(const char* program)
293 {
294   printf("Usage: \n"
295          "   %s <testcase name>\t\t Execute a test case\n"
296          "   %s \t\t Execute all test cases in parallel\n"
297          "   %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n",
298          program, program, program);
299 }
300
301 } // namespace