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;
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";
41 int RunTestCase( struct ::testcase_s& testCase )
43 int result = EXIT_STATUS_TESTCASE_FAILED;
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 )
52 result = testCase.function();
53 if( testCase.cleanup )
62 int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
64 int testResult = EXIT_STATUS_TESTCASE_FAILED;
67 if( pid == 0 ) // Child process
74 exit( RunTestCase( testCase ) );
79 exit(EXIT_STATUS_FORK_FAILED);
81 else // Parent process
84 int childPid = waitpid(-1, &status, 0);
88 exit(EXIT_STATUS_WAITPID_FAILED);
90 if( WIFEXITED(status) )
94 testResult = WEXITSTATUS(status);
97 printf("Test case %s failed: %d\n", testCase.name, testResult);
101 else if(WIFSIGNALED(status) )
103 testResult = EXIT_STATUS_TESTCASE_ABORTED;
106 if(WCOREDUMP(status))
108 printf("Test case %s failed: due to a crash\n", testCase.name);
111 printf("Test case %s failed: exit with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
113 else if(WIFSTOPPED(status))
115 printf("Test case %s failed: stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
121 void OutputStatistics( int numPasses, int numFailures )
123 const char* failureColor = GREEN_COLOR;
124 if( numFailures > 0 )
126 failureColor = RED_COLOR;
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);
134 int RunAll(const char* processName, ::testcase tc_array[], bool reRunFailed)
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++)
142 int result = RunTestCaseInChildProcess( tc_array[i], true );
153 OutputStatistics(numPasses, numFailures);
160 // Constantly runs up to MAX_NUM_CHILDREN processes
161 int RunAllInParallel( const char* processName, ::testcase tc_array[], bool reRunFailed)
166 RunningTestCases children;
167 std::vector<int> failedTestCases;
169 // Fork up to MAX_NUM_CHILDREN processes, then
170 // wait. As soon as a proc completes, fork the next.
172 int nextTestCase = 0;
173 int numRunningChildren = 0;
175 while( tc_array[nextTestCase].name || numRunningChildren > 0)
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 )
181 if( pid == 0 ) // Child process
183 close(STDOUT_FILENO);
184 close(STDERR_FILENO);
185 exit( RunTestCase( tc_array[nextTestCase] ) );
190 exit(EXIT_STATUS_FORK_FAILED);
192 else // Parent process
194 TestCase tc(nextTestCase, tc_array[nextTestCase].name);
197 numRunningChildren++;
201 // Wait for the next child to finish
204 int childPid = waitpid(-1, &status, 0);
208 exit(EXIT_STATUS_WAITPID_FAILED);
211 if( WIFEXITED(status) )
215 int testResult = WEXITSTATUS(status);
218 printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
219 failedTestCases.push_back(children[childPid].testCase);
226 numRunningChildren--;
230 else if( WIFSIGNALED(status) || WIFSTOPPED(status))
232 status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
236 RunningTestCases::iterator iter = children.find(childPid);
237 if( iter != children.end() )
239 printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
240 failedTestCases.push_back(iter->second.testCase);
244 printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
248 numRunningChildren--;
253 OutputStatistics( numPasses, numFailures );
257 for( unsigned int i=0; i<failedTestCases.size(); i++)
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++)
267 RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
276 int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
278 int result = EXIT_STATUS_TESTCASE_NOT_FOUND;
280 for( int i = 0; tc_array[i].name; i++ )
282 if( !strcmp(testCaseName, tc_array[i].name) )
284 return RunTestCase( tc_array[i] );
288 printf("Unknown testcase name: \"%s\"\n", testCaseName);
292 void Usage(const char* program)
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);