2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "test-harness.h"
19 #include <sys/types.h>
30 typedef std::map<int, TestCase> RunningTestCases;
32 const char* basename(const char* path)
35 const char* slash=NULL;
36 for( ; *ptr != '\0' ; ++ptr )
38 if(*ptr == '/') slash=ptr;
40 if(slash != NULL) ++slash;
44 int RunTestCase( struct ::testcase_s& testCase )
46 int result = EXIT_STATUS_TESTCASE_FAILED;
48 // dont want to catch exception as we want to be able to get
49 // gdb stack trace from the first error
50 // by default tests should all always pass with no exceptions
51 if( testCase.startup )
55 result = testCase.function();
56 if( testCase.cleanup )
65 int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
67 int testResult = EXIT_STATUS_TESTCASE_FAILED;
70 if( pid == 0 ) // Child process
80 for(int i=0; i<80; ++i) printf("#");
81 printf("\nTC: %s\n", testCase.name);
85 int status = RunTestCase( testCase );
87 if( ! suppressOutput )
99 exit(EXIT_STATUS_FORK_FAILED);
101 else // Parent process
104 int childPid = waitpid(pid, &status, 0);
108 exit(EXIT_STATUS_WAITPID_FAILED);
110 if( WIFEXITED(status) )
114 testResult = WEXITSTATUS(status);
117 printf("Test case %s failed: %d\n", testCase.name, testResult);
121 else if(WIFSIGNALED(status) )
123 int signal = WTERMSIG(status);
124 testResult = EXIT_STATUS_TESTCASE_ABORTED;
125 if( signal == SIGABRT )
127 printf("Test case %s failed: test case asserted\n", testCase.name );
131 printf("Test case %s failed: exit with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
134 else if(WIFSTOPPED(status))
136 printf("Test case %s failed: stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
144 void OutputStatistics( const char* processName, int numPasses, int numFailures )
146 FILE* fp=fopen("summary.xml", "a");
150 " <suite name=\"%s\">\n"
151 " <total_case>%d</total_case>\n"
152 " <pass_case>%d</pass_case>\n"
153 " <pass_rate>%5.2f</pass_rate>\n"
154 " <fail_case>%d</fail_case>\n"
155 " <fail_rate>%5.2f</fail_rate>\n"
156 " <block_case>0</block_case>\n"
157 " <block_rate>0.00</block_rate>\n"
158 " <na_case>0</na_case>\n"
159 " <na_rate>0.00</na_rate>\n"
161 basename(processName),
162 numPasses+numFailures,
164 (float)numPasses/(numPasses+numFailures),
166 (float)numFailures/(numPasses+numFailures) );
171 int RunAll( const char* processName, ::testcase tc_array[] )
176 // Run test cases in child process( to kill output/handle signals ), but run serially.
177 for( unsigned int i=0; tc_array[i].name; i++)
179 int result = RunTestCaseInChildProcess( tc_array[i], false );
190 OutputStatistics( processName, numPasses, numFailures);
195 // Constantly runs up to MAX_NUM_CHILDREN processes
196 int RunAllInParallel( const char* processName, ::testcase tc_array[], bool reRunFailed)
201 RunningTestCases children;
202 std::vector<int> failedTestCases;
204 // Fork up to MAX_NUM_CHILDREN processes, then
205 // wait. As soon as a proc completes, fork the next.
207 int nextTestCase = 0;
208 int numRunningChildren = 0;
210 while( tc_array[nextTestCase].name || numRunningChildren > 0)
212 // Create more children (up to the max number or til the end of the array)
213 while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
216 if( pid == 0 ) // Child process
218 close(STDOUT_FILENO);
219 close(STDERR_FILENO);
220 exit( RunTestCase( tc_array[nextTestCase] ) );
225 exit(EXIT_STATUS_FORK_FAILED);
227 else // Parent process
229 TestCase tc(nextTestCase, tc_array[nextTestCase].name);
232 numRunningChildren++;
236 // Wait for the next child to finish
239 int childPid = waitpid(-1, &status, 0);
243 exit(EXIT_STATUS_WAITPID_FAILED);
246 if( WIFEXITED(status) )
250 int testResult = WEXITSTATUS(status);
253 printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
254 failedTestCases.push_back(children[childPid].testCase);
261 numRunningChildren--;
265 else if( WIFSIGNALED(status) || WIFSTOPPED(status))
267 status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
271 RunningTestCases::iterator iter = children.find(childPid);
272 if( iter != children.end() )
274 printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
275 failedTestCases.push_back(iter->second.testCase);
279 printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
283 numRunningChildren--;
288 OutputStatistics( processName, numPasses, numFailures );
292 for( unsigned int i=0; i<failedTestCases.size(); i++)
294 char* testCaseStrapline;
295 int numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
296 printf("\n%s\n", testCaseStrapline);
297 for(int j=0; j<numChars; j++)
302 RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
311 int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
313 int result = EXIT_STATUS_TESTCASE_NOT_FOUND;
315 for( int i = 0; tc_array[i].name; i++ )
317 if( !strcmp(testCaseName, tc_array[i].name) )
319 return RunTestCase( tc_array[i] );
323 printf("Unknown testcase name: \"%s\"\n", testCaseName);
327 void Usage(const char* program)
330 " %s <testcase name>\t\t Execute a test case\n"
331 " %s \t\t Execute all test cases in parallel\n"
332 " %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n"
333 " %s -s\t\t Execute all test cases serially\n",
334 program, program, program, program);