Newer
Older
<?php

Angie Byron
committed
/**
* @file

catch
committed
* Script for running tests on DrupalCI.
*
* This script is intended for use only by drupal.org's testing. In general,
* tests should be run directly with phpunit.
*
* @internal
*/
use Drupal\Component\FileSystem\FileSystem;

catch
committed
use Drupal\Component\Utility\Environment;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Timer;
use Drupal\Core\Composer\Composer;

Angie Byron
committed
use Drupal\Core\Database\Database;
use Drupal\Core\Test\EnvironmentCleaner;

Lee Rowlands
committed
use Drupal\Core\Test\PhpUnitTestRunner;
use Drupal\Core\Test\SimpletestTestRunResultsStorage;
use Drupal\Core\Test\RunTests\TestFileParser;

catch
committed
use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Test\TestRun;
use Drupal\Core\Test\TestRunnerKernel;
use Drupal\Core\Test\TestRunResultsStorageInterface;

Lee Rowlands
committed
use Drupal\Core\Test\TestDiscovery;

Alex Pott
committed
use Drupal\TestTools\PhpUnitCompatibility\ClassWriter;

Alex Pott
committed
use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\Version;
use Symfony\Component\Console\Output\ConsoleOutput;

Angie Byron
committed
use Symfony\Component\HttpFoundation\Request;

Alex Pott
committed
// Define some colors for display.
// A nice calming green.
const SIMPLETEST_SCRIPT_COLOR_PASS = 32;
// An alerting Red.
const SIMPLETEST_SCRIPT_COLOR_FAIL = 31;
// An annoying brown.
const SIMPLETEST_SCRIPT_COLOR_EXCEPTION = 33;

Angie Byron
committed
// Restricting the chunk of queries prevents memory exhaustion.
const SIMPLETEST_SCRIPT_SQLITE_VARIABLE_LIMIT = 350;

Dries Buytaert
committed
const SIMPLETEST_SCRIPT_EXIT_SUCCESS = 0;
const SIMPLETEST_SCRIPT_EXIT_FAILURE = 1;
const SIMPLETEST_SCRIPT_EXIT_EXCEPTION = 2;

Dries Buytaert
committed
// Set defaults and get overrides.

Lee Rowlands
committed
[$args, $count] = simpletest_script_parse_args();

Dries Buytaert
committed
if ($args['help'] || $count == 0) {
simpletest_script_help();
exit(($count == 0) ? SIMPLETEST_SCRIPT_EXIT_FAILURE : SIMPLETEST_SCRIPT_EXIT_SUCCESS);

Dries Buytaert
committed
}

Angie Byron
committed
simpletest_script_init();
if (!class_exists(TestCase::class)) {

Alex Pott
committed
echo "\nrun-tests.sh requires the PHPUnit testing framework. Please use 'composer install' to ensure that it is present.\n\n";
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}

Angie Byron
committed

Angie Byron
committed
if ($args['execute-test']) {

Angie Byron
committed
simpletest_script_setup_database();
$test_run_results_storage = simpletest_script_setup_test_run_results_storage();
$test_run = TestRun::get($test_run_results_storage, $args['test-id']);
simpletest_script_run_one_test($test_run, $args['execute-test']);

Angie Byron
committed
// Sub-process exited already; this is just for clarity.
exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);

Dries Buytaert
committed
}

Angie Byron
committed
if ($args['list']) {

Alex Pott
committed
// Display all available tests organized by one @group annotation.
echo "\nAvailable test groups & classes\n";

Alex Pott
committed
echo "-------------------------------\n\n";
$test_discovery = new TestDiscovery(
\Drupal::root(),
\Drupal::service('class_loader')
);
try {
$groups = $test_discovery->getTestClasses($args['module']);
}
catch (Exception $e) {

Alex Pott
committed
error_log((string) $e);
echo (string) $e;
exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
}

Alex Pott
committed
// A given class can appear in multiple groups. For historical reasons, we
// need to present each test only once. The test is shown in the group that is
// printed first.
$printed_tests = [];
foreach ($groups as $group => $tests) {
echo $group . "\n";

Alex Pott
committed
$tests = array_diff(array_keys($tests), $printed_tests);
foreach ($tests as $test) {
echo " - $test\n";
}

Alex Pott
committed
$printed_tests = array_merge($printed_tests, $tests);
}
exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
}

Alex Pott
committed
// List-files and list-files-json provide a way for external tools such as the
// testbot to prioritize running changed tests.
// @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 TestDiscovery(
\Drupal::root(),
\Drupal::service('class_loader')
);

Alex Pott
committed
// TestDiscovery::findAllClassFiles() gives us a classmap similar to a
// Composer 'classmap' array.
$test_classes = $test_discovery->findAllClassFiles();
// JSON output is the easiest.
if ($args['list-files-json']) {
echo json_encode($test_classes);
exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
}
// Output the list of files.
else {

Lee Rowlands
committed
foreach (array_values($test_classes) as $test_class) {

Alex Pott
committed
echo $test_class . "\n";
}
}
exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
}

Angie Byron
committed
simpletest_script_setup_database(TRUE);

Dries Buytaert
committed
// Setup the test run results storage environment. Currently, this coincides
// with the simpletest database schema.
$test_run_results_storage = simpletest_script_setup_test_run_results_storage(TRUE);

Dries Buytaert
committed
if ($args['clean']) {

Angie Byron
committed
// Clean up left-over tables and directories.
$cleaner = new EnvironmentCleaner(
DRUPAL_ROOT,
Database::getConnection(),
$test_run_results_storage,
new ConsoleOutput(),
\Drupal::service('file_system')
);
try {
$cleaner->cleanEnvironment();
}
catch (Exception $e) {
echo (string) $e;
exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
}

Dries Buytaert
committed
echo "\nEnvironment cleaned.\n";
// Get the status messages and print them.
$messages = \Drupal::messenger()->messagesByType('status');
foreach ($messages as $text) {

Dries Buytaert
committed
echo " - " . $text . "\n";
}
exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);

Dries Buytaert
committed
}
if (!Composer::upgradePHPUnitCheck(Version::id())) {
simpletest_script_print_error("PHPUnit testing framework version 9 or greater is required when running on PHP 7.4 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.");
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}

Dries Buytaert
committed
$test_list = simpletest_script_get_test_list();
// Try to allocate unlimited time to run the tests.

catch
committed
Environment::setTimeLimit(0);

Dries Buytaert
committed
simpletest_script_reporter_init();

Lee Rowlands
committed
$tests_to_run = [];
for ($i = 0; $i < $args['repeat']; $i++) {

Dries Buytaert
committed
$tests_to_run = array_merge($tests_to_run, $test_list);

Angie Byron
committed
}

Dries Buytaert
committed

Dries Buytaert
committed
// Execute tests.
$status = simpletest_script_execute_batch($test_run_results_storage, $tests_to_run);

Dries Buytaert
committed

Dries Buytaert
committed
// Stop the timer.
simpletest_script_reporter_timer_stop();

catch
committed
// Ensure all test locks are released once finished. If tests are run with a
// concurrency of 1 the each test will clean up its own lock. Test locks are
// not released if using a higher concurrency to ensure each test has unique
// fixtures.

catch
committed
TestDatabase::releaseAllTestLocks();

Dries Buytaert
committed
// Display results before database is cleared.
simpletest_script_reporter_display_results($test_run_results_storage);

Dries Buytaert
committed

Dries Buytaert
committed
if ($args['xml']) {
simpletest_script_reporter_write_xml_results($test_run_results_storage);

Dries Buytaert
committed
}

Dries Buytaert
committed
// Clean up all test results.
if (!$args['keep-results']) {
Loading
Loading full blame...