case "$1" in
-r|--rebuild) opt_rebuild=true ; shift ;;
-n|--no-gen) opt_generate=false ; shift ;;
- --) shift ; break ;;
- *) shift ;; # Ignore
+ --) shift ; break ;;
+ *) shift ;; # Ignore
esac
done
#!/bin/bash
-TEMP=`getopt -o sr --long serial,rerun -n 'execute.sh' -- "$@"`
+TEMP=`getopt -o hsr --long help,serial,rerun -n 'execute.sh' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
-opt_parallel=1
+function usage
+{
+ echo -e "Usage: execute.sh\t\tExecute test cases from all modules in parallel"
+ echo -e " execute.sh <testmodule>\tExecute test cases from the given module in parallel"
+ echo -e " execute.sh -s\t\tExecute test cases in serial using Testkit-Lite"
+ echo -e " execute.sh -r\t\tExecute test cases in parallel, re-running failed test cases in serial afterwards"
+ echo -e " execute.sh <testcase>\tFind and execute the given test case"
+ exit 2
+}
+
+opt_serial=0
opt_rerun=""
while true ; do
case "$1" in
- -s|--serial) opt_parallel=0 ; shift ;;
+ -h|--help) usage ;;
+ -s|--serial) opt_serial=1 ; shift ;;
-r|--rerun) opt_rerun="-r" ; shift ;;
--) shift; break;;
- *) echo "Internal error $1!" ; exit 1 ;;
+ *) echo "Internal error $1!" ; exit 1 ;;
esac
done
scripts/add_style.pl $1
}
+
+
# Clean up old test results
rm -f tct*core-tests.xml
find build \( -name "*.gcda" \) -exec rm '{}' \;
-if [ $opt_parallel = 1 ] ; then
+ASCII_BOLD="\e[1m"
+ASCII_RESET="\e[0m"
+if [ $opt_serial = 1 ] ; then
+ # Run all test case executables serially, create XML output
if [ -n "$1" ] ; then
- if [ -f "build/src/$1/tct-$1-core" ] ; then
- build/src/$1/tct-$1-core -p $opt_rerun
- fi
+ execute $1 $*
else
for mod in `ls -1 src/ | grep -v CMakeList `
do
if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
- echo EXECUTING $mod
- build/src/$mod/tct-$mod-core -p $opt_rerun
+
+ echo -ne "$ASCII_BOLD"
+ echo -e "Executing $mod$ASCII_RESET"
+ execute $mod $*
fi
done
fi
+ scripts/summarize.pl
else
- if [ -n "$1" ] ; then
- execute $1 $*
+ # if $1 is an executable filename, execute it·
+
+ if [ -z "$1" ] ; then
+ # No arguments:
+ # Execute each test executable in turn, using parallel execution
+ for mod in `ls -1 src/ | grep -v CMakeList | grep -v common | grep -v manual`
+ do
+ echo -e "$ASCII_BOLD"
+ echo -e "Executing $mod$ASCII_RESET"
+ build/src/$mod/tct-$mod-core $opt_rerun
+ done
+
+ elif [ -f "build/src/$1/tct-$1-core" ] ; then
+ # First argument is an executable filename - execute only that with any
+ # remaining arguments
+ module=$1
+ shift;
+ build/src/$module/tct-$module-core $opt_rerun $*
+
else
- for mod in `ls -1 src/ | grep -v CMakeList `
+ # First argument is not an executable. Is it a test case name?
+ # Try executing each executable with the test case name until success/known failure
+ for mod in `ls -1 src/ | grep -v CMakeList | grep -v common | grep -v manual`
do
- if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
- echo EXECUTING $mod
- execute $mod $*
+ output=`build/src/$mod/tct-$mod-core $1`
+ ret=$?
+ if [ $ret -ne 6 ] ; then
+ echo $output
+ if [ $ret -eq 0 ] ; then echo -e "\nPassed" ; fi
+ exit $ret
fi
done
+ echo $1 not found
fi
-
- scripts/summarize.pl
fi
)
LIST(APPEND TC_SOURCES
+ ../dali/dali-test-suite-utils/test-harness.cpp
../dali/dali-test-suite-utils/dali-test-suite-utils.cpp
../dali/dali-test-suite-utils/test-application.cpp
../dali/dali-test-suite-utils/test-gesture-manager.cpp
-#include <stdio.h>
#include <string.h>
-#include "tct-dali-internal-core.h"
-#include <stdlib.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <vector>
-#include <map>
-
-int RunTestCase( struct testcase_s& testCase )
-{
- int result = 1;
- if( testCase.startup )
- {
- testCase.startup();
- }
- result = testCase.function();
- if( testCase.cleanup )
- {
- testCase.cleanup();
- }
- return result;
-}
-
-#define MAX_NUM_CHILDREN 16
-
-struct TestCase
-{
- int testCase;
- const char* testCaseName;
-
- TestCase()
- : testCase(0),
- testCaseName(NULL)
- {
- }
-
- TestCase(int tc, const char* name)
- : testCase(tc),
- testCaseName(name)
- {
- }
- TestCase(const TestCase& rhs)
- : testCase(rhs.testCase),
- testCaseName(rhs.testCaseName)
- {
- }
- TestCase& operator=(const TestCase& rhs)
- {
- testCase = rhs.testCase;
- testCaseName = rhs.testCaseName;
- return *this;
-
- }
-};
-
-
-typedef std::map<int, TestCase> RunningTestCases;
-
-// Constantly runs up to MAX_NUM_CHILDREN processes
-int RunAllInParallel(const char* processName, bool reRunFailed)
-{
- int numFailures = 0;
- int numPasses = 0;
- int numTestCases = sizeof(tc_array)/sizeof(struct testcase_s) - 1;
-
- RunningTestCases children;
- std::vector<int> failedTestCases;
-
- // Fork up to MAX_NUM_CHILDREN processes, then
- // wait. As soon as a proc completes, fork the next.
-
- int nextTestCase = 0;
- int numRunningChildren = 0;
- while( nextTestCase < numTestCases || numRunningChildren > 0)
- {
- if( nextTestCase < numTestCases )
- {
- while( numRunningChildren < MAX_NUM_CHILDREN )
- {
- int pid = fork();
- if( pid == 0 ) // Child process
- {
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- exit( RunTestCase( tc_array[nextTestCase] ) );
- }
- else if(pid == -1)
- {
- perror("fork");
- exit(2);
- }
- else // Parent process
- {
- TestCase tc(nextTestCase, tc_array[nextTestCase].name);
- children[pid] = tc;
- nextTestCase++;
- numRunningChildren++;
- }
- }
- }
-
- int status=0;
- int childPid = waitpid(-1, &status, 0);
- if( childPid == -1 )
- {
- perror("waitpid");
- exit(2);
- }
-
- if( WIFEXITED(status) )
- {
- if( childPid > 0 )
- {
- int testResult = WEXITSTATUS(status);
- if( testResult )
- {
- printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
- failedTestCases.push_back(children[childPid].testCase);
- numFailures++;
- }
- else
- {
- numPasses++;
- }
- numRunningChildren--;
- }
- }
-
- else if( WIFSIGNALED(status) )
- {
- if( childPid > 0 )
- {
- RunningTestCases::iterator iter = children.find(childPid);
- if( iter != children.end() )
- {
- printf("Test case %s exited with signal %d\n", iter->second.testCaseName, WTERMSIG(status));
- failedTestCases.push_back(iter->second.testCase);
- }
- else
- {
- printf("Unknown child process: %d signaled %d\n", childPid, WTERMSIG(status));
- }
-
- numFailures++;
- numRunningChildren--;
- }
- }
- }
-
- printf("\rNumber of test passes: %d \n", numPasses);
- printf("Number of test failures: %d\n", numFailures);
-
- if( reRunFailed )
- {
- for( unsigned int i=0; i<failedTestCases.size(); i++)
- {
- printf("Running test case %s:\n", tc_array[failedTestCases[i]].name );
- RunTestCase( tc_array[failedTestCases[i] ] );
- }
- }
-
- return numFailures;
-}
-
-int FindAndRunTestCase(const char* testCaseName)
-{
- int result = 2;
-
- for( int i = 0; tc_array[i].name; i++ )
- {
- if( !strcmp(testCaseName, tc_array[i].name) )
- {
- return RunTestCase( tc_array[i] );
- }
- }
-
- printf("Unknown testcase name: \"%s\"\n", testCaseName);
- return result;
-}
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-internal-core.h"
int main(int argc, char * const argv[])
{
- int result = -1;
+ int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
- const char* optString = "pr";
- bool optParallel(false);
+ const char* optString = "r";
bool optRerunFailed(false);
int nextOpt = 0;
nextOpt = getopt( argc, argv, optString );
switch(nextOpt)
{
- case 'p':
- optParallel = true;
- break;
case 'r':
optRerunFailed = true;
break;
+ case '?':
+ TestHarness::Usage(argv[0]);
+ exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+ break;
}
} while( nextOpt != -1 );
- if( optParallel )
+ if( optind == argc ) // no testcase name in argument list
{
- result = RunAllInParallel(argv[0], optRerunFailed);
+ result = TestHarness::RunAllInParallel(argv[0], tc_array, optRerunFailed);
}
else
{
- if (argc != 2) {
- printf("Usage: %s <testcase name>\n", argv[0]);
- return 2;
- }
- result = FindAndRunTestCase(argv[1]);
+ // optind is index of next argument - interpret as testcase name
+ result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
}
return result;
}
dali-test-suite-utils/mesh-builder.cpp
dali-test-suite-utils/test-dynamics.cpp
dali-test-suite-utils/test-platform-abstraction.cpp
+ ../dali/dali-test-suite-utils/test-harness.cpp
../dali/dali-test-suite-utils/dali-test-suite-utils.cpp
../dali/dali-test-suite-utils/test-application.cpp
../dali/dali-test-suite-utils/test-gesture-manager.cpp
-#include <stdio.h>
#include <string.h>
-#include "tct-dali-unmanaged-core.h"
-#include <stdlib.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <vector>
-#include <map>
-
-int RunTestCase( struct testcase_s& testCase )
-{
- int result = 1;
- if( testCase.startup )
- {
- testCase.startup();
- }
- result = testCase.function();
- if( testCase.cleanup )
- {
- testCase.cleanup();
- }
- return result;
-}
-
-#define MAX_NUM_CHILDREN 16
-
-struct TestCase
-{
- int testCase;
- const char* testCaseName;
-
- TestCase()
- : testCase(0),
- testCaseName(NULL)
- {
- }
-
- TestCase(int tc, const char* name)
- : testCase(tc),
- testCaseName(name)
- {
- }
- TestCase(const TestCase& rhs)
- : testCase(rhs.testCase),
- testCaseName(rhs.testCaseName)
- {
- }
- TestCase& operator=(const TestCase& rhs)
- {
- testCase = rhs.testCase;
- testCaseName = rhs.testCaseName;
- return *this;
-
- }
-};
-
-
-typedef std::map<int, TestCase> RunningTestCases;
-
-// Constantly runs up to MAX_NUM_CHILDREN processes
-int RunAllInParallel(const char* processName, bool reRunFailed)
-{
- int numFailures = 0;
- int numPasses = 0;
- int numTestCases = sizeof(tc_array)/sizeof(struct testcase_s) - 1;
-
- RunningTestCases children;
- std::vector<int> failedTestCases;
-
- // Fork up to MAX_NUM_CHILDREN processes, then
- // wait. As soon as a proc completes, fork the next.
-
- int nextTestCase = 0;
- int numRunningChildren = 0;
- while( nextTestCase < numTestCases || numRunningChildren > 0)
- {
- if( nextTestCase < numTestCases )
- {
- while( numRunningChildren < MAX_NUM_CHILDREN )
- {
- int pid = fork();
- if( pid == 0 ) // Child process
- {
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- exit( RunTestCase( tc_array[nextTestCase] ) );
- }
- else if(pid == -1)
- {
- perror("fork");
- exit(2);
- }
- else // Parent process
- {
- TestCase tc(nextTestCase, tc_array[nextTestCase].name);
- children[pid] = tc;
- nextTestCase++;
- numRunningChildren++;
- }
- }
- }
-
- int status=0;
- int childPid = waitpid(-1, &status, 0);
- if( childPid == -1 )
- {
- perror("waitpid");
- exit(2);
- }
-
- if( WIFEXITED(status) )
- {
- if( childPid > 0 )
- {
- int testResult = WEXITSTATUS(status);
- if( testResult )
- {
- printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
- failedTestCases.push_back(children[childPid].testCase);
- numFailures++;
- }
- else
- {
- numPasses++;
- }
- numRunningChildren--;
- }
- }
-
- else if( WIFSIGNALED(status) )
- {
- if( childPid > 0 )
- {
- RunningTestCases::iterator iter = children.find(childPid);
- if( iter != children.end() )
- {
- printf("Test case %s exited with signal %d\n", iter->second.testCaseName, WTERMSIG(status));
- failedTestCases.push_back(iter->second.testCase);
- }
- else
- {
- printf("Unknown child process: %d signaled %d\n", childPid, WTERMSIG(status));
- }
-
- numFailures++;
- numRunningChildren--;
- }
- }
- }
-
- printf("\rNumber of test passes: %d \n", numPasses);
- printf("Number of test failures: %d\n", numFailures);
-
- if( reRunFailed )
- {
- for( unsigned int i=0; i<failedTestCases.size(); i++)
- {
- printf("Running test case %s:\n", tc_array[failedTestCases[i]].name );
- RunTestCase( tc_array[failedTestCases[i] ] );
- }
- }
-
- return numFailures;
-}
-
-int FindAndRunTestCase(const char* testCaseName)
-{
- int result = 2;
-
- for( int i = 0; tc_array[i].name; i++ )
- {
- if( !strcmp(testCaseName, tc_array[i].name) )
- {
- return RunTestCase( tc_array[i] );
- }
- }
-
- printf("Unknown testcase name: \"%s\"\n", testCaseName);
- return result;
-}
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-unmanaged-core.h"
int main(int argc, char * const argv[])
{
- int result = -1;
+ int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
- const char* optString = "pr";
- bool optParallel(false);
+ const char* optString = "r";
bool optRerunFailed(false);
int nextOpt = 0;
nextOpt = getopt( argc, argv, optString );
switch(nextOpt)
{
- case 'p':
- optParallel = true;
- break;
case 'r':
optRerunFailed = true;
break;
+ case '?':
+ TestHarness::Usage(argv[0]);
+ exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+ break;
}
} while( nextOpt != -1 );
- if( optParallel )
+ if( optind == argc ) // no testcase name in argument list
{
- result = RunAllInParallel(argv[0], optRerunFailed);
+ result = TestHarness::RunAllInParallel(argv[0], tc_array, optRerunFailed);
}
else
{
- if (argc != 2) {
- printf("Usage: %s <testcase name>\n", argv[0]);
- return 2;
- }
- result = FindAndRunTestCase(argv[1]);
+ // optind is index of next argument - interpret as testcase name
+ result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
}
return result;
}
)
LIST(APPEND TC_SOURCES
+ dali-test-suite-utils/test-harness.cpp
dali-test-suite-utils/dali-test-suite-utils.cpp
dali-test-suite-utils/test-application.cpp
dali-test-suite-utils/test-gesture-manager.cpp
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test-harness.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <testcase.h>
+
+namespace TestHarness
+{
+
+typedef std::map<int, TestCase> RunningTestCases;
+
+namespace
+{
+const char* RED_COLOR="\e[1;31m";
+const char* GREEN_COLOR="\e[1;32m";
+const char* ASCII_RESET="\e[0m";
+const char* ASCII_BOLD="\e[1m";
+}
+
+
+int RunTestCase( struct ::testcase_s& testCase )
+{
+ int result = EXIT_STATUS_TESTCASE_FAILED;
+
+ try
+ {
+ if( testCase.startup )
+ {
+ testCase.startup();
+ }
+ result = testCase.function();
+ if( testCase.cleanup )
+ {
+ testCase.cleanup();
+ }
+ }
+ catch (...)
+ {
+ printf("Caught exception in test case.\n");
+ result = EXIT_STATUS_TESTCASE_ABORTED;
+ }
+
+ return result;
+}
+
+int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
+{
+ int testResult = EXIT_STATUS_TESTCASE_FAILED;
+
+ int pid = fork();
+ if( pid == 0 ) // Child process
+ {
+ if( suppressOutput )
+ {
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ }
+ exit( RunTestCase( testCase ) );
+ }
+ else if(pid == -1)
+ {
+ perror("fork");
+ exit(EXIT_STATUS_FORK_FAILED);
+ }
+ else // Parent process
+ {
+ int status = 0;
+ int childPid = waitpid(-1, &status, 0);
+ if( childPid == -1 )
+ {
+ perror("waitpid");
+ exit(EXIT_STATUS_WAITPID_FAILED);
+ }
+ if( WIFEXITED(status) )
+ {
+ if( childPid > 0 )
+ {
+ testResult = WEXITSTATUS(status);
+ if( testResult )
+ {
+ printf("Test case %s failed: %d\n", testCase.name, testResult);
+ }
+ }
+ }
+ else if(WIFSIGNALED(status) )
+ {
+ testResult = EXIT_STATUS_TESTCASE_ABORTED;
+
+#ifdef WCOREDUMP
+ if(WCOREDUMP(status))
+ {
+ printf("Test case %s crashed\n", testCase.name);
+ }
+#endif
+ printf("Test case %s exited with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
+ }
+ else if(WIFSTOPPED(status))
+ {
+ printf("Test case %s stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
+ }
+ }
+ return testResult;
+}
+
+void OutputStatistics( int numPasses, int numFailures )
+{
+ const char* failureColor = GREEN_COLOR;
+ if( numFailures > 0 )
+ {
+ failureColor = RED_COLOR;
+ }
+ printf("\rNumber of test passes: %s%4d (%5.2f%%)%s\n", ASCII_BOLD, numPasses, 100.0f * (float)numPasses / (numPasses+numFailures), ASCII_RESET);
+ printf("%sNumber of test failures:%s %s%4d%s\n", failureColor, ASCII_RESET, ASCII_BOLD, numFailures, ASCII_RESET);
+
+}
+
+
+int RunAll(const char* processName, ::testcase tc_array[], bool reRunFailed)
+{
+ int numFailures = 0;
+ int numPasses = 0;
+
+ // Run test cases in child process( to kill output/handle signals ), but run serially.
+ for( unsigned int i=0; tc_array[i].name; i++)
+ {
+ int result = RunTestCaseInChildProcess( tc_array[i], true );
+ if( result == 0 )
+ {
+ numPasses++;
+ }
+ else
+ {
+ numFailures++;
+ }
+ }
+
+ OutputStatistics(numPasses, numFailures);
+
+ return numFailures;
+}
+
+
+
+// Constantly runs up to MAX_NUM_CHILDREN processes
+int RunAllInParallel( const char* processName, ::testcase tc_array[], bool reRunFailed)
+{
+ int numFailures = 0;
+ int numPasses = 0;
+
+ RunningTestCases children;
+ std::vector<int> failedTestCases;
+
+ // Fork up to MAX_NUM_CHILDREN processes, then
+ // wait. As soon as a proc completes, fork the next.
+
+ int nextTestCase = 0;
+ int numRunningChildren = 0;
+
+ while( tc_array[nextTestCase].name || numRunningChildren > 0)
+ {
+ // Create more children (up to the max number or til the end of the array)
+ while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
+ {
+ int pid = fork();
+ if( pid == 0 ) // Child process
+ {
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ exit( RunTestCase( tc_array[nextTestCase] ) );
+ }
+ else if(pid == -1)
+ {
+ perror("fork");
+ exit(EXIT_STATUS_FORK_FAILED);
+ }
+ else // Parent process
+ {
+ TestCase tc(nextTestCase, tc_array[nextTestCase].name);
+ children[pid] = tc;
+ nextTestCase++;
+ numRunningChildren++;
+ }
+ }
+
+ // Wait for the next child to finish
+
+ int status=0;
+ int childPid = waitpid(-1, &status, 0);
+ if( childPid == -1 )
+ {
+ perror("waitpid");
+ exit(EXIT_STATUS_WAITPID_FAILED);
+ }
+
+ if( WIFEXITED(status) )
+ {
+ if( childPid > 0 )
+ {
+ int testResult = WEXITSTATUS(status);
+ if( testResult )
+ {
+ printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
+ failedTestCases.push_back(children[childPid].testCase);
+ numFailures++;
+ }
+ else
+ {
+ numPasses++;
+ }
+ numRunningChildren--;
+ }
+ }
+
+ else if( WIFSIGNALED(status) || WIFSTOPPED(status))
+ {
+ status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
+
+ if( childPid > 0 )
+ {
+ RunningTestCases::iterator iter = children.find(childPid);
+ if( iter != children.end() )
+ {
+ printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
+ failedTestCases.push_back(iter->second.testCase);
+ }
+ else
+ {
+ printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
+ }
+
+ numFailures++;
+ numRunningChildren--;
+ }
+ }
+ }
+
+ OutputStatistics( numPasses, numFailures );
+
+ if( reRunFailed )
+ {
+ for( unsigned int i=0; i<failedTestCases.size(); i++)
+ {
+ char* testCaseStrapline;
+ int numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
+ printf("\n%s\n", testCaseStrapline);
+ for(int j=0; j<numChars; j++)
+ {
+ printf("=");
+ }
+ printf("\n");
+ RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
+ }
+ }
+
+ return numFailures;
+}
+
+
+
+int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
+{
+ int result = EXIT_STATUS_TESTCASE_NOT_FOUND;
+
+ for( int i = 0; tc_array[i].name; i++ )
+ {
+ if( !strcmp(testCaseName, tc_array[i].name) )
+ {
+ return RunTestCase( tc_array[i] );
+ }
+ }
+
+ printf("Unknown testcase name: \"%s\"\n", testCaseName);
+ return result;
+}
+
+void Usage(const char* program)
+{
+ printf("Usage: \n"
+ " %s <testcase name>\t\t Execute a test case\n"
+ " %s \t\t Execute all test cases in parallel\n"
+ " %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n",
+ program, program, program);
+}
+
+} // namespace
--- /dev/null
+#ifndef TEST_HARNESS_H
+#define TEST_HARNESS_H
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <testcase.h>
+
+namespace TestHarness
+{
+
+enum ExitStatus
+{
+ EXIT_STATUS_TESTCASE_SUCCEEDED, // 0
+ EXIT_STATUS_TESTCASE_FAILED, // 1
+ EXIT_STATUS_TESTCASE_ABORTED, // 2
+ EXIT_STATUS_FORK_FAILED, // 3
+ EXIT_STATUS_WAITPID_FAILED, // 4
+ EXIT_STATUS_BAD_ARGUMENT, // 5
+ EXIT_STATUS_TESTCASE_NOT_FOUND // 6
+};
+
+const int MAX_NUM_CHILDREN(16);
+
+struct TestCase
+{
+ int testCase;
+ const char* testCaseName;
+
+ TestCase()
+ : testCase(0),
+ testCaseName(NULL)
+ {
+ }
+
+ TestCase(int tc, const char* name)
+ : testCase(tc),
+ testCaseName(name)
+ {
+ }
+ TestCase(const TestCase& rhs)
+ : testCase(rhs.testCase),
+ testCaseName(rhs.testCaseName)
+ {
+ }
+ TestCase& operator=(const TestCase& rhs)
+ {
+ testCase = rhs.testCase;
+ testCaseName = rhs.testCaseName;
+ return *this;
+
+ }
+};
+
+/**
+ * Run a test case
+ * @param[in] testCase The Testkit-lite test case to run
+ */
+int RunTestCase( struct testcase_s& testCase );
+
+/**
+ * Run all test cases in parallel
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] reRunFailed True if failed test cases should be re-run
+ * @return 0 on success
+ */
+int RunAllInParallel(const char* processName, testcase tc_array[], bool reRunFailed);
+
+/**
+ * Run all test cases in serial
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] reRunFailed True if failed test cases should be re-run
+ * @return 0 on success
+ */
+int RunAll(const char* processName, testcase tc_array[], bool reRunFailed);
+
+/**
+ * Find the named test case in the given array, and run it
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] testCaseName the name of the test case to run
+ * @return 0 on success
+ */
+int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName);
+
+/**
+ * Display usage instructions for this program
+ * @param[in] program The name of this program
+ */
+void Usage(const char* program);
+
+} // namespace TestHarness
+
+#endif
-#include <stdio.h>
#include <string.h>
-#include "tct-dali-core.h"
-#include <stdlib.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <vector>
-#include <map>
-
-int RunTestCase( struct testcase_s& testCase )
-{
- int result = 1;
- if( testCase.startup )
- {
- testCase.startup();
- }
- result = testCase.function();
- if( testCase.cleanup )
- {
- testCase.cleanup();
- }
- return result;
-}
-
-#define MAX_NUM_CHILDREN 16
-
-struct TestCase
-{
- int testCase;
- const char* testCaseName;
-
- TestCase()
- : testCase(0),
- testCaseName(NULL)
- {
- }
-
- TestCase(int tc, const char* name)
- : testCase(tc),
- testCaseName(name)
- {
- }
- TestCase(const TestCase& rhs)
- : testCase(rhs.testCase),
- testCaseName(rhs.testCaseName)
- {
- }
- TestCase& operator=(const TestCase& rhs)
- {
- testCase = rhs.testCase;
- testCaseName = rhs.testCaseName;
- return *this;
-
- }
-};
-
-
-typedef std::map<int, TestCase> RunningTestCases;
-
-// Constantly runs up to MAX_NUM_CHILDREN processes
-int RunAllInParallel(const char* processName, bool reRunFailed)
-{
- int numFailures = 0;
- int numPasses = 0;
- int numTestCases = sizeof(tc_array)/sizeof(struct testcase_s) - 1;
-
- RunningTestCases children;
- std::vector<int> failedTestCases;
-
- // Fork up to MAX_NUM_CHILDREN processes, then
- // wait. As soon as a proc completes, fork the next.
-
- int nextTestCase = 0;
- int numRunningChildren = 0;
- while( nextTestCase < numTestCases || numRunningChildren > 0)
- {
- if( nextTestCase < numTestCases )
- {
- while( numRunningChildren < MAX_NUM_CHILDREN )
- {
- int pid = fork();
- if( pid == 0 ) // Child process
- {
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- exit( RunTestCase( tc_array[nextTestCase] ) );
- }
- else if(pid == -1)
- {
- perror("fork");
- exit(2);
- }
- else // Parent process
- {
- TestCase tc(nextTestCase, tc_array[nextTestCase].name);
- children[pid] = tc;
- nextTestCase++;
- numRunningChildren++;
- }
- }
- }
-
- int status=0;
- int childPid = waitpid(-1, &status, 0);
- if( childPid == -1 )
- {
- perror("waitpid");
- exit(2);
- }
-
- if( WIFEXITED(status) )
- {
- if( childPid > 0 )
- {
- int testResult = WEXITSTATUS(status);
- if( testResult )
- {
- printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
- failedTestCases.push_back(children[childPid].testCase);
- numFailures++;
- }
- else
- {
- numPasses++;
- }
- numRunningChildren--;
- }
- }
-
- else if( WIFSIGNALED(status) )
- {
- if( childPid > 0 )
- {
- RunningTestCases::iterator iter = children.find(childPid);
- if( iter != children.end() )
- {
- printf("Test case %s exited with signal %d\n", iter->second.testCaseName, WTERMSIG(status));
- failedTestCases.push_back(iter->second.testCase);
- }
- else
- {
- printf("Unknown child process: %d signaled %d\n", childPid, WTERMSIG(status));
- }
-
- numFailures++;
- numRunningChildren--;
- }
- }
- }
-
- printf("\rNumber of test passes: %d \n", numPasses);
- printf("Number of test failures: %d\n", numFailures);
-
- if( reRunFailed )
- {
- for( unsigned int i=0; i<failedTestCases.size(); i++)
- {
- printf("Running test case %s:\n", tc_array[failedTestCases[i]].name );
- RunTestCase( tc_array[failedTestCases[i] ] );
- }
- }
-
- return numFailures;
-}
-
-int FindAndRunTestCase(const char* testCaseName)
-{
- int result = 2;
-
- for( int i = 0; tc_array[i].name; i++ )
- {
- if( !strcmp(testCaseName, tc_array[i].name) )
- {
- return RunTestCase( tc_array[i] );
- }
- }
-
- printf("Unknown testcase name: \"%s\"\n", testCaseName);
- return result;
-}
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-core.h"
int main(int argc, char * const argv[])
{
- int result = -1;
+ int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
- const char* optString = "pr";
- bool optParallel(false);
+ const char* optString = "r";
bool optRerunFailed(false);
int nextOpt = 0;
nextOpt = getopt( argc, argv, optString );
switch(nextOpt)
{
- case 'p':
- optParallel = true;
- break;
case 'r':
optRerunFailed = true;
break;
+ case '?':
+ TestHarness::Usage(argv[0]);
+ exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+ break;
}
} while( nextOpt != -1 );
- if( optParallel )
+ if( optind == argc ) // no testcase name in argument list
{
- result = RunAllInParallel(argv[0], optRerunFailed);
+ result = TestHarness::RunAllInParallel(argv[0], tc_array, optRerunFailed);
}
else
{
- if (argc != 2) {
- printf("Usage: %s <testcase name>\n", argv[0]);
- return 2;
- }
- result = FindAndRunTestCase(argv[1]);
+ // optind is index of next argument - interpret as testcase name
+ result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
}
return result;
}