summaryrefslogtreecommitdiff
path: root/scripts/run-tests.sh
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2008-06-29 12:22:28 +0000
committerDries Buytaert <dries@buytaert.net>2008-06-29 12:22:28 +0000
commit0d76c733e7873f2451763e77d3c840c8d95cdf85 (patch)
tree055f35fe04f0519fc742a2424c9a8a4892e02610 /scripts/run-tests.sh
parent2e7dbff6b8fef54cc8dbb107e934ea8e0702208b (diff)
downloadbrdo-0d76c733e7873f2451763e77d3c840c8d95cdf85.tar.gz
brdo-0d76c733e7873f2451763e77d3c840c8d95cdf85.tar.bz2
- Patch #274794 by Damien Tournoud et al: make scripts/run-tests.php work again.
Diffstat (limited to 'scripts/run-tests.sh')
-rwxr-xr-xscripts/run-tests.sh240
1 files changed, 175 insertions, 65 deletions
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index 9b9786a33..db7600b20 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -1,4 +1,3 @@
-#!/Applications/MAMP/bin/php5/bin/php
<?php
// $Id$
@@ -10,11 +9,12 @@
* If no arguments are provided, the help text will print.
*/
-$reporter = 'text';
$test_names = array();
$host = 'localhost';
$path = '';
$script = basename(array_shift($_SERVER['argv']));
+// XXX: is there a way to get the interpreter path dynamically?
+$php = "/usr/bin/php";
if (in_array('--help', $_SERVER['argv']) || empty($_SERVER['argv'])) {
echo <<<EOF
@@ -37,12 +37,14 @@ All arguments are long options.
need this parameter if Drupal is in a subdirectory on your
localhost and you have not set \$base_url in settings.php.
- --reporter Immediatly preceeds the name of the output reporter to use. This
- Defaults to "text", while other options include "xml" and "html".
+ --concurrency [num]
+
+ Run tests in parallel, up to [num] tests at a time.
+ This is not supported under Windows.
--all Run all available tests.
- --class Run tests identified by speficic class names.
+ --class Run tests identified by specific class names, instead of group names.
<test1>[,<test2>[,<test3> ...]]
@@ -66,8 +68,11 @@ EOF;
$list = FALSE;
$clean = FALSE;
$all = FALSE;
+$concurrency = 1;
$class_names = FALSE;
$test_names = array();
+$execute_batch = FALSE;
+$test_id = NULL;
while ($param = array_shift($_SERVER['argv'])) {
switch ($param) {
@@ -89,11 +94,14 @@ while ($param = array_shift($_SERVER['argv'])) {
case '--clean':
$clean = TRUE;
break;
- case '--reporter':
- $reporter = array_shift($_SERVER['argv']);
- if (!in_array($reporter, array("text", "xml", "html"))) {
- $reporter = "text";
- }
+ case '--concurrency':
+ $concurrency = array_shift($_SERVER['argv']);
+ break;
+ case '--test-id':
+ $test_id = array_shift($_SERVER['argv']);
+ break;
+ case '--execute-batch':
+ $execute_batch = TRUE;
break;
default:
$test_names += explode(',', $param);
@@ -113,6 +121,68 @@ $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
chdir(realpath(dirname(__FILE__) . '/..'));
require_once './includes/bootstrap.inc';
+
+if ($execute_batch) {
+ if (is_null($test_id)) {
+ echo "ERROR: --execute-batch should not be called interactively.\n";
+ exit;
+ }
+ if ($concurrency == 1 || !function_exists('pcntl_fork')) {
+ // Fallback to mono-threaded execution
+ if (count($test_names) > 1) {
+ foreach($test_names as $test_class) {
+ // Note: we still need to execute each test in its separate Drupal environment
+ passthru($php . " ./scripts/run-tests.sh --url $url --concurrency 1 --test-id $test_id --execute-batch $test_class");
+ }
+ exit;
+ }
+ else {
+ // Execute an individual test
+ $test_class = array_shift($test_names);
+ drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ simpletest_run_one_test($test_id, $test_class);
+ exit;
+ }
+ }
+ else {
+ // Multi-threaded execution
+ $children = array();
+ while (!empty($test_names) || !empty($children)) {
+ // Fork children
+ // Note: we can safely fork here, because Drupal is not bootstrapped yet
+ while(count($children) < $concurrency) {
+ if (empty($test_names)) break;
+
+ $child = array();
+ $child['test_class'] = $test_class = array_shift($test_names);
+ $child['pid'] = pcntl_fork();
+ if (!$child['pid']) {
+ // This is the child process, bootstrap and execute the test
+ drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ simpletest_run_one_test($test_id, $test_class);
+ exit;
+ }
+ else {
+ // Register our new child
+ $children[] = $child;
+ }
+ }
+
+ // Wait for children every 200ms
+ usleep(200000);
+
+ // Check if some children finished
+ foreach($children as $cid => $child) {
+ if (pcntl_waitpid($child['pid'], $status, WUNTRACED | WNOHANG)) {
+ // This particular child exited
+ unset($children[$cid]);
+ }
+ }
+ }
+ exit;
+ }
+}
+
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
if (!module_exists('simpletest')) {
@@ -126,7 +196,7 @@ if ($clean) {
// Get the status messages and print them.
$messages = array_pop(drupal_get_messages('status'));
foreach($messages as $text) {
- echo("- " . $text . "\n");
+ echo(" - " . $text . "\n");
}
exit;
}
@@ -134,92 +204,132 @@ if ($clean) {
// Run tests as user #1.
$GLOBALS['user'] = user_load(1);
-//Load simpletest files
-$total_test = &simpletest_get_total_test();
-
-$test_instances = $total_test->getTestInstances();
+// Load simpletest files
+$all_tests = simpletest_get_all_tests();
+$groups = simpletest_categorize_tests($all_tests);
+$test_list = array();
if ($list) {
// Display all availabe tests.
- echo("Available test groups:\n----------------------\n");
- foreach ($test_instances as $group_test) {
- echo($group_test->getLabel() . "\n");
+ echo("\nAvailable test groups\n---------------------\n\n");
+ foreach ($groups as $group => $tests) {
+ echo($group . "\n");
+ foreach ($tests as $class_name => $instance) {
+ $info = $instance->getInfo();
+ echo " - " . $info['name'] . ' (' . $class_name . ')' . "\n";
+ }
}
exit;
}
if ($all) {
- $test_list = NULL;
+ $test_list = array_keys($all_tests);
}
else {
if ($class_names) {
- $test_list = _run_tests_check_classes($test_names, $test_instances);
+ // Use only valid class names
+ foreach ($test_names as $class_name) {
+ if (isset($all_tests[$class_name])) {
+ $test_list[] = $class_name;
+ }
+ }
}
else {
- $test_list = _run_tests_find_classes($test_names, $test_instances);
+ // Resolve group names
+ foreach ($test_names as $group_name) {
+ if (isset($groups[$group_name])) {
+ foreach($groups[$group_name] as $class_name => $instance) {
+ $test_list[] = $class_name;
+ }
+ }
+ }
}
}
+
if (empty($test_list) && !$all) {
echo("ERROR: No valid tests were specified.\n");
exit;
}
-
// If not in 'safe mode', increase the maximum execution time:
if (!ini_get('safe_mode')) {
- set_time_limit(360);
+ set_time_limit(0);
}
+echo "\n";
+echo "Drupal test run\n";
+echo "---------------\n";
+echo "\n";
+
// Tell the user about what tests are to be run.
-if (!$all && $reporter == 'text') {
- echo("Tests to be run:\n");
- foreach ($test_list as $name) {
- echo("- " . $name . "\n");
+if ($all) {
+ echo "All tests will run.\n\n";
+}
+else {
+ echo "Tests to be run:\n";
+ foreach ($test_list as $class_name) {
+ $info = $all_tests[$class_name]->getInfo();
+ echo " - " . $info['name'] . ' (' . $class_name . ')' . "\n";
}
- echo("\n");
+ echo "\n";
}
-simpletest_run_tests(array_keys($test_list), $reporter);
-
-// Utility functions:
-/**
- * Check that each class name exists as a test, return the list of valid ones.
- */
-function _run_tests_check_classes($test_names, $test_instances) {
- $test_list = array();
- $test_names = array_flip($test_names);
-
- foreach ($test_instances as $group_test) {
- $tests = $group_test->getTestInstances();
- foreach ($tests as $test) {
- $class = get_class($test);
- $info = $test->getInfo();
- if (isset($test_names[$class])) {
- $test_list[$class] = $info['name'];
- }
- }
+echo "Test run started: " . format_date(time(), 'long') . "\n";
+echo "\n";
+
+db_query('INSERT INTO {simpletest_test_id} VALUES (default)');
+$test_id = db_last_insert_id('simpletest_test_id', 'test_id');
+
+echo "Test summary:\n";
+echo "-------------\n";
+echo "\n";
+
+// Now execute tests
+passthru($php . " ./scripts/run-tests.sh --url $url --test-id $test_id --concurrency $concurrency --execute-batch " . implode(",", $test_list));
+
+echo "\n";
+echo "Test run ended: " . format_date(time(), 'long') . "\n";
+echo "\n";
+
+// Report results
+echo "Detailed test results:\n";
+echo "----------------------\n";
+echo "\n";
+
+$results_map = array(
+ 'pass' => 'Pass',
+ 'fail' => 'Fail',
+ 'exception' => 'Exception'
+);
+
+$results = db_query("SELECT * FROM {simpletest} WHERE test_id = %d ORDER BY test_class, message_id", $test_id);
+while($result = db_fetch_object($results)) {
+ if (isset($results_map[$result->status])) {
+ $data = array(
+ '[' . $results_map[$result->status] . ']',
+ $result->message,
+ $result->message_group,
+ basename($result->file),
+ $result->line,
+ $result->caller,
+ );
+ echo implode("\t", $data) . "\n";
}
- return $test_list;
}
+// Cleanup our test results
+db_query("DELETE FROM {simpletest} WHERE test_id = %d", $test_id);
+
+// Support function:
+
/**
- * Check that each group name exists, return the list of class in valid groups.
+ * Run a single test (assume a Drupal bootstrapped environnement).
*/
-function _run_tests_find_classes($test_names, &$test_instances) {
- $test_list = array();
- $test_names = array_flip($test_names);
-
- uasort($test_instances, 'simpletest_compare_instances');
- foreach ($test_instances as $group_test) {
- $group = $group_test->getLabel();
- if (isset($test_names[$group])) {
- $tests = $group_test->getTestInstances();
- foreach ($tests as $test) {
- $info = $test->getInfo();
- $test_list[get_class($test)] = $info['name'];
- }
- }
- }
- return $test_list;
+function simpletest_run_one_test($test_id, $test_class) {
+ simpletest_get_all_tests();
+ $test = new $test_class($test_id);
+ $test->run();
+ $info = $test->getInfo();
+ echo $info['name'] . ' ' . _simpletest_format_summary_line($test->_results) . "\n";
}