diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index 9b9786a33bfd18cc7609309c7b4f12df2e9dbde8..db7600b2073b2c6e34454e27f1665139d5ec6d44 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 @@
               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 @@
 $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 @@
     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 @@
 
 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 @@
   // 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 @@
 // 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";
 }