summaryrefslogtreecommitdiffstatshomepage
path: root/core/scripts/run-tests.sh
diff options
context:
space:
mode:
Diffstat (limited to 'core/scripts/run-tests.sh')
-rwxr-xr-xcore/scripts/run-tests.sh222
1 files changed, 76 insertions, 146 deletions
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 96f16eed9c71..4545a00cc3ac 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -17,13 +17,14 @@ use Drupal\Component\Utility\Timer;
use Drupal\Core\Composer\Composer;
use Drupal\Core\Database\Database;
use Drupal\Core\Test\EnvironmentCleaner;
-use Drupal\Core\Test\PhpUnitTestDiscovery;
use Drupal\Core\Test\PhpUnitTestRunner;
use Drupal\Core\Test\SimpletestTestRunResultsStorage;
+use Drupal\Core\Test\RunTests\TestFileParser;
use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Test\TestRun;
use Drupal\Core\Test\TestRunnerKernel;
use Drupal\Core\Test\TestRunResultsStorageInterface;
+use Drupal\Core\Test\TestDiscovery;
use Drupal\BuildTests\Framework\BuildTestBase;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\KernelTests\KernelTestBase;
@@ -48,10 +49,6 @@ const SIMPLETEST_SCRIPT_COLOR_EXCEPTION = 33;
const SIMPLETEST_SCRIPT_COLOR_YELLOW = 33;
// A refreshing cyan.
const SIMPLETEST_SCRIPT_COLOR_CYAN = 36;
-// A fainting gray.
-const SIMPLETEST_SCRIPT_COLOR_GRAY = 90;
-// A notable white.
-const SIMPLETEST_SCRIPT_COLOR_BRIGHT_WHITE = "1;97";
// Restricting the chunk of queries prevents memory exhaustion.
const SIMPLETEST_SCRIPT_SQLITE_VARIABLE_LIMIT = 350;
@@ -89,12 +86,12 @@ if ($args['list']) {
// Display all available tests organized by one @group annotation.
echo "\nAvailable test groups & classes\n";
echo "-------------------------------\n\n";
- $test_discovery = new PhpUnitTestDiscovery(\Drupal::root() . \DIRECTORY_SEPARATOR . 'core');
+ $test_discovery = new TestDiscovery(
+ \Drupal::root(),
+ \Drupal::service('class_loader')
+ );
try {
$groups = $test_discovery->getTestClasses($args['module']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
}
catch (Exception $e) {
error_log((string) $e);
@@ -122,8 +119,11 @@ if ($args['list']) {
// @see https://www.drupal.org/node/2569585
if ($args['list-files'] || $args['list-files-json']) {
// List all files which could be run as tests.
- $test_discovery = new PhpUnitTestDiscovery(\Drupal::root() . \DIRECTORY_SEPARATOR . 'core');
- // PhpUnitTestDiscovery::findAllClassFiles() gives us a classmap similar to a
+ $test_discovery = new TestDiscovery(
+ \Drupal::root(),
+ \Drupal::service('class_loader')
+ );
+ // TestDiscovery::findAllClassFiles() gives us a classmap similar to a
// Composer 'classmap' array.
$test_classes = $test_discovery->findAllClassFiles();
// JSON output is the easiest.
@@ -177,15 +177,6 @@ if (!Composer::upgradePHPUnitCheck(Version::id())) {
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}
-echo "\n";
-echo "Drupal test run\n\n";
-echo sprintf("Drupal Version: %s\n", \Drupal::VERSION);
-echo sprintf("PHP Version: %s\n", \PHP_VERSION);
-echo sprintf("PHP Binary: %s\n", $php ?? getenv('_'));
-echo sprintf("PHPUnit Version: %s\n", Version::id());
-echo "-------------------------------\n";
-echo "\n";
-
$test_list = simpletest_script_get_test_list();
// Try to allocate unlimited time to run the tests.
@@ -364,11 +355,6 @@ All arguments are long options.
The index of the job in the job set.
- --debug-discovery
-
- If provided, dumps detailed information on the tests selected
- for execution, before the execution starts.
-
<test1>[,<test2>[,<test3> ...]]
One or more tests to be run. By default, these are interpreted
@@ -441,7 +427,6 @@ function simpletest_script_parse_args() {
'non-html' => FALSE,
'ci-parallel-node-index' => 1,
'ci-parallel-node-total' => 1,
- 'debug-discovery' => FALSE,
];
// Override with set values.
@@ -934,15 +919,17 @@ function simpletest_script_command(TestRun $test_run, string $test_class): array
function simpletest_script_get_test_list() {
global $args;
- $test_discovery = new PhpUnitTestDiscovery(\Drupal::root() . \DIRECTORY_SEPARATOR . 'core');
+ $test_discovery = new TestDiscovery(
+ \Drupal::root(),
+ \Drupal::service('class_loader')
+ );
+ $types_processed = empty($args['types']);
$test_list = [];
$slow_tests = [];
if ($args['all'] || $args['module'] || $args['directory']) {
try {
$groups = $test_discovery->getTestClasses($args['module'], $args['types'], $args['directory']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
+ $types_processed = TRUE;
}
catch (Exception $e) {
echo (string) $e;
@@ -951,34 +938,30 @@ function simpletest_script_get_test_list() {
// Ensure that tests marked explicitly as @group #slow are run at the
// beginning of each job.
if (key($groups) === '#slow') {
- $slow_tests = array_shift($groups);
+ $slow_tests = array_keys(array_shift($groups));
}
$not_slow_tests = [];
foreach ($groups as $group => $tests) {
- $not_slow_tests = array_merge($not_slow_tests, $tests);
+ $not_slow_tests = array_merge($not_slow_tests, array_keys($tests));
}
// Filter slow tests out of the not slow tests and ensure a unique list
// since tests may appear in more than one group.
- $not_slow_tests = array_diff_key($not_slow_tests, $slow_tests);
+ $not_slow_tests = array_unique(array_diff($not_slow_tests, $slow_tests));
// If the tests are not being run in parallel, then ensure slow tests run
// all together first.
if ((int) $args['ci-parallel-node-total'] <= 1 ) {
sort_tests_by_type_and_methods($slow_tests);
sort_tests_by_type_and_methods($not_slow_tests);
- $all_tests_list = array_merge($slow_tests, $not_slow_tests);
- assign_tests_sequence($all_tests_list);
- dump_tests_sequence($all_tests_list, $args);
- $test_list = array_keys($all_tests_list);
+ $test_list = array_merge($slow_tests, $not_slow_tests);
}
else {
- // Sort all tests by the number of test cases on the test class.
- // This is used in combination with @group #slow to start the slowest
- // tests first and distribute tests between test runners.
+ // Sort all tests by the number of public methods on the test class.
+ // This is a proxy for the approximate time taken to run the test,
+ // which is used in combination with @group #slow to start the slowest tests
+ // first and distribute tests between test runners.
sort_tests_by_public_method_count($slow_tests);
sort_tests_by_public_method_count($not_slow_tests);
- $all_tests_list = array_merge($slow_tests, $not_slow_tests);
- assign_tests_sequence($all_tests_list);
// Now set up a bin per test runner.
$bin_count = (int) $args['ci-parallel-node-total'];
@@ -992,8 +975,6 @@ function simpletest_script_get_test_list() {
$binned_other_tests = place_tests_into_bins($not_slow_tests, $bin_count);
$other_tests_for_job = $binned_other_tests[$args['ci-parallel-node-index'] - 1];
$test_list = array_merge($slow_tests_for_job, $other_tests_for_job);
- dump_bin_tests_sequence($args['ci-parallel-node-index'], $all_tests_list, $test_list, $args);
- $test_list = array_keys($test_list);
}
}
else {
@@ -1007,9 +988,6 @@ function simpletest_script_get_test_list() {
else {
try {
$groups = $test_discovery->getTestClasses(NULL, $args['types']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
}
catch (Exception $e) {
echo (string) $e;
@@ -1027,24 +1005,19 @@ function simpletest_script_get_test_list() {
}
elseif ($args['file']) {
// Extract test case class names from specified files.
+ $parser = new TestFileParser();
foreach ($args['test_names'] as $file) {
- if (!file_exists($file) || is_dir($file)) {
+ if (!file_exists($file)) {
simpletest_script_print_error('File not found: ' . $file);
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}
- $fileTests = current($test_discovery->getTestClasses(NULL, [], $file));
- $test_list = array_merge($test_list, $fileTests);
+ $test_list = array_merge($test_list, $parser->getTestListFromFile($file));
}
- assign_tests_sequence($test_list);
- dump_tests_sequence($test_list, $args);
- $test_list = array_keys($test_list);
}
else {
try {
$groups = $test_discovery->getTestClasses(NULL, $args['types']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
+ $types_processed = TRUE;
}
catch (Exception $e) {
echo (string) $e;
@@ -1061,15 +1034,22 @@ function simpletest_script_get_test_list() {
}
// Merge the tests from the groups together.
foreach ($args['test_names'] as $group_name) {
- $test_list = array_merge($test_list, $groups[$group_name]);
+ $test_list = array_merge($test_list, array_keys($groups[$group_name]));
}
- assign_tests_sequence($test_list);
- dump_tests_sequence($test_list, $args);
// Ensure our list of tests contains only one entry for each test.
- $test_list = array_keys($test_list);
+ $test_list = array_unique($test_list);
}
}
+ // If the test list creation does not automatically limit by test type then
+ // we need to do so here.
+ if (!$types_processed) {
+ $test_list = array_filter($test_list, function ($test_class) use ($args) {
+ $test_info = TestDiscovery::getTestInfo($test_class);
+ return in_array($test_info['type'], $args['types'], TRUE);
+ });
+ }
+
if (empty($test_list)) {
simpletest_script_print_error('No valid tests were specified.');
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
@@ -1082,11 +1062,11 @@ function simpletest_script_get_test_list() {
* Sort tests by test type and number of public methods.
*/
function sort_tests_by_type_and_methods(array &$tests): void {
- uasort($tests, function ($a, $b) {
- if (get_test_type_weight($a['name']) === get_test_type_weight($b['name'])) {
- return $b['tests_count'] <=> $a['tests_count'];
+ usort($tests, function ($a, $b) {
+ if (get_test_type_weight($a) === get_test_type_weight($b)) {
+ return get_test_class_method_count($b) <=> get_test_class_method_count($a);
}
- return get_test_type_weight($b['name']) <=> get_test_type_weight($a['name']);
+ return get_test_type_weight($b) <=> get_test_type_weight($a);
});
}
@@ -1103,8 +1083,8 @@ function sort_tests_by_type_and_methods(array &$tests): void {
* An array of test class names.
*/
function sort_tests_by_public_method_count(array &$tests): void {
- uasort($tests, function ($a, $b) {
- return $b['tests_count'] <=> $a['tests_count'];
+ usort($tests, function ($a, $b) {
+ return get_test_class_method_count($b) <=> get_test_class_method_count($a);
});
}
@@ -1125,46 +1105,28 @@ function get_test_type_weight(string $class): int {
}
/**
- * Assigns the test sequence.
+ * Get an approximate test method count for a test class.
*
- * @param array $tests
- * The array of test class info.
- */
-function assign_tests_sequence(array &$tests): void {
- $i = 0;
- foreach ($tests as &$testInfo) {
- $testInfo['sequence'] = ++$i;
- }
-}
-
-/**
- * Dumps the list of tests in order of execution after sorting.
- *
- * @param array $tests
- * The array of test class info.
- * @param array $args
- * The command line arguments.
+ * @param string $class
+ * The test class name.
*/
-function dump_tests_sequence(array $tests, array $args): void {
- if ($args['debug-discovery'] === FALSE) {
- return;
- }
- echo "Test execution sequence\n";
- echo "-----------------------\n\n";
- echo " Seq Slow? Group Cnt Class\n";
- echo "-----------------------------------------\n";
- $i = 0;
- foreach ($tests as $testInfo) {
- echo sprintf(
- "%4d %5s %15s %4d %s\n",
- $testInfo['sequence'],
- in_array('#slow', $testInfo['groups']) ? '#slow' : '',
- trim_with_ellipsis($testInfo['group'], 15, \STR_PAD_RIGHT),
- $testInfo['tests_count'],
- trim_with_ellipsis($testInfo['name'], 60, \STR_PAD_LEFT),
- );
+function get_test_class_method_count(string $class): int {
+ $reflection = new \ReflectionClass($class);
+ $count = 0;
+ foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
+ // If a method uses a dataProvider, increase the count by 20 since data
+ // providers result in a single method running multiple times.
+ $comments = $method->getDocComment();
+ preg_match_all('#@(.*?)\n#s', $comments, $annotations);
+ foreach ($annotations[1] as $annotation) {
+ if (str_starts_with($annotation, 'dataProvider')) {
+ $count = $count + 20;
+ continue;
+ }
+ }
+ $count++;
}
- echo "-----------------------------------------\n\n";
+ return $count;
}
/**
@@ -1187,51 +1149,13 @@ function place_tests_into_bins(array $tests, int $bin_count) {
// Create a bin corresponding to each parallel test job.
$bins = array_fill(0, $bin_count, []);
// Go through each test and add them to one bin at a time.
- $i = 0;
foreach ($tests as $key => $test) {
- $bins[($i++ % $bin_count)][$key] = $test;
+ $bins[($key % $bin_count)][] = $test;
}
return $bins;
}
/**
- * Dumps the list of tests in order of execution for a bin.
- *
- * @param int $bin
- * The bin.
- * @param array $allTests
- * The list of all test classes discovered.
- * @param array $tests
- * The list of test class to run for this bin.
- * @param array $args
- * The command line arguments.
- */
-function dump_bin_tests_sequence(int $bin, array $allTests, array $tests, array $args): void {
- if ($args['debug-discovery'] === FALSE) {
- return;
- }
- echo "Test execution sequence. ";
- echo "Tests marked *** will be executed in this PARALLEL BIN #{$bin}.\n";
- echo "-------------------------------------------------------------------------------------\n\n";
- echo "Bin Seq Slow? Group Cnt Class\n";
- echo "--------------------------------------------\n";
- foreach ($allTests as $testInfo) {
- $inBin = isset($tests[$testInfo['name']]);
- $message = sprintf(
- "%s %4d %5s %15s %4d %s\n",
- $inBin ? "***" : " ",
- $testInfo['sequence'],
- in_array('#slow', $testInfo['groups']) ? '#slow' : '',
- trim_with_ellipsis($testInfo['group'], 15, \STR_PAD_RIGHT),
- $testInfo['tests_count'],
- trim_with_ellipsis($testInfo['name'], 60, \STR_PAD_LEFT),
- );
- simpletest_script_print($message, $inBin ? SIMPLETEST_SCRIPT_COLOR_BRIGHT_WHITE : SIMPLETEST_SCRIPT_COLOR_GRAY);
- }
- echo "-------------------------------------------------\n\n";
-}
-
-/**
* Initialize the reporter.
*/
function simpletest_script_reporter_init(): void {
@@ -1246,6 +1170,12 @@ function simpletest_script_reporter_init(): void {
'debug' => 'Log',
];
+ echo "\n";
+ echo "Drupal test run\n";
+ echo "Using PHP Binary: $php\n";
+ echo "---------------\n";
+ echo "\n";
+
// Tell the user about what tests are to be run.
if ($args['all']) {
echo "All tests will run.\n\n";
@@ -1448,7 +1378,7 @@ function simpletest_script_reporter_display_results(TestRunResultsStorageInterfa
function simpletest_script_format_result($result): void {
global $args, $results_map, $color;
- $summary = sprintf("%-9.9s %9.3fs %s\n", $results_map[$result->status], $result->time, trim_with_ellipsis($result->function, 80, STR_PAD_LEFT));
+ $summary = sprintf("%-9.9s %9.3fs %-80.80s\n", $results_map[$result->status], $result->time, trim_with_ellipsis($result->function, 80, STR_PAD_LEFT));
simpletest_script_print($summary, simpletest_script_color_code($result->status));
@@ -1610,12 +1540,12 @@ function simpletest_script_load_messages_by_test_id(TestRunResultsStorageInterfa
*/
function trim_with_ellipsis(string $input, int $length, int $side): string {
if (strlen($input) < $length) {
- return str_pad($input, $length, ' ', \STR_PAD_RIGHT);
+ return str_pad($input, $length, ' ', STR_PAD_RIGHT);
}
elseif (strlen($input) > $length) {
return match($side) {
- \STR_PAD_RIGHT => substr($input, 0, $length - 1) . '…',
- default => '…' . substr($input, -$length + 1),
+ STR_PAD_RIGHT => substr($input, 0, $length - 3) . '...',
+ default => '...' . substr($input, -$length + 3),
};
}
return $input;