diff --git a/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php b/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php index 0dcef01615..b8236f9b3f 100644 --- a/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php +++ b/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php @@ -28,6 +28,50 @@ protected function setUp() { $this->root = static::getDrupalRoot(); } + /** + * @coversNothing + */ + public function testInstallWithNonExistingClass() { + $autoloader = $this->root . '/autoload.php'; + $app = new TestInstallationSetupApplication(require $autoloader); + $app->setAutoExit(FALSE); + + $app_tester = new ApplicationTester($app); + $app_tester->run( + [ + 'command' => 'setup-drupal-test', + '--setup_class' => 'this-class-does-not-exist', + ], + [ + 'interactive' => FALSE, + ] + ); + + $this->assertContains('There was a problem loading this-class-does-not-exist', $app_tester->getDisplay()); + } + + /** + * @coversNothing + */ + public function testInstallWithNonSetupClass() { + $autoloader = $this->root . '/autoload.php'; + $app = new TestInstallationSetupApplication(require $autoloader); + $app->setAutoExit(FALSE); + + $app_tester = new ApplicationTester($app); + $app_tester->run( + [ + 'command' => 'setup-drupal-test', + '--setup_class' => static::class, + ], + [ + 'interactive' => FALSE, + ] + ); + + $this->assertContains('You need to define a class implementing \Drupal\Setup\TestSetupInterface ', $app_tester->getDisplay()); + } + /** * @coversNothing */ @@ -59,6 +103,17 @@ public function testInstallScript() { $response = $http_client->send($request); // Ensure the test_page_test module got installed. $this->assertContains('Test page | Drupal', (string) $response->getBody()); + + // Now test the tear down process as well. + $app_tester->run( + [ + 'command' => 'teardown-drupal-test', + 'db_prefix' => $this->databasePrefix, + ], + [ + 'interactive' => FALSE, + ] + ); } } diff --git a/core/tests/Drupal/Setup/Commands/TestInstallationSetupApplication.php b/core/tests/Drupal/Setup/Commands/TestInstallationSetupApplication.php index 9c205daf7c..f38c714ab1 100644 --- a/core/tests/Drupal/Setup/Commands/TestInstallationSetupApplication.php +++ b/core/tests/Drupal/Setup/Commands/TestInstallationSetupApplication.php @@ -30,13 +30,6 @@ public function __construct($autoloader) { parent::__construct('setup-drupal-test', '0.0.1'); } - /** - * {@inheritdoc} - */ - protected function getCommandName(InputInterface $input) { - return 'setup-drupal-test'; - } - /** * {@inheritdoc} */ @@ -44,6 +37,7 @@ protected function getDefaultCommands() { // Even though this is a single command, keep the HelpCommand (--help). $default_commands = parent::getDefaultCommands(); $default_commands[] = new TestInstallationSetupCommand($this->autoloader); + $default_commands[] = new TestTeardownCommand($this->autoloader); return $default_commands; } diff --git a/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php b/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php index 0b622a284a..325537db5e 100644 --- a/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php +++ b/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php @@ -59,7 +59,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { putenv("SIMPLETEST_DB=$db_url"); putenv("SIMPLETEST_BASE_URL=$base_url"); - $this->bootstrapDrupal($this->autoloader); + $this->bootstrapDrupal(); // Manage site fixture. $test = new TestInstallationSetup(); diff --git a/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php b/core/tests/Drupal/Setup/Commands/TestTeardownCommand.php similarity index 82% copy from core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php copy to core/tests/Drupal/Setup/Commands/TestTeardownCommand.php index 0b622a284a..7266207b42 100644 --- a/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php +++ b/core/tests/Drupal/Setup/Commands/TestTeardownCommand.php @@ -12,11 +12,11 @@ use Symfony\Component\HttpFoundation\Request; /** - * Symfony console command to setup Drupal. + * Tears down a test Drupal. * * @internal */ -class TestInstallationSetupCommand extends Command { +class TestTeardownCommand extends Command { /** * The used PHP autoloader. @@ -44,8 +44,8 @@ public function __construct($autoloader, $name = NULL) { * {@inheritdoc} */ protected function configure() { - $this->setName('setup-drupal-test') - ->addOption('setup_class', NULL, InputOption::VALUE_OPTIONAL) + $this->setName('teardown-drupal-test') + ->addArgument('db_prefix') ->addOption('db_url', NULL, InputOption::VALUE_OPTIONAL, 'URL for database or SIMPLETEST_DB', getenv('SIMPLETEST_DB')) ->addOption('base_url', NULL, InputOption::VALUE_OPTIONAL, 'Base URL for site under test or SIMPLETEST_BASE_URL', getenv('SIMPLETEST_BASE_URL')); } @@ -55,21 +55,22 @@ protected function configure() { */ protected function execute(InputInterface $input, OutputInterface $output) { $db_url = $input->getOption('db_url'); + $db_prefix = $input->getArgument('db_prefix'); $base_url = $input->getOption('base_url'); putenv("SIMPLETEST_DB=$db_url"); putenv("SIMPLETEST_BASE_URL=$base_url"); - $this->bootstrapDrupal($this->autoloader); + $this->bootstrapDrupal($db_prefix); // Manage site fixture. $test = new TestInstallationSetup(); - $test->setup('testing', $input->getOption('setup_class')); - - $output->writeln(drupal_generate_test_ua($test->getDatabasePrefix())); + $test->teardown($db_prefix); } - protected function bootstrapDrupal() { + protected function bootstrapDrupal($db_prefix) { $request = Request::createFromGlobals(); + $_COOKIE['SIMPLETEST_USER_AGENT'] = drupal_generate_test_ua($db_prefix); + $kernel = DrupalKernel::createFromRequest($request, $this->autoloader, $this->getApplication()->getName()); DrupalKernel::bootEnvironment($kernel->getAppRoot()); diff --git a/core/tests/Drupal/Setup/TestInstallationSetup.php b/core/tests/Drupal/Setup/TestInstallationSetup.php index 50b027a10a..4e816c1c06 100644 --- a/core/tests/Drupal/Setup/TestInstallationSetup.php +++ b/core/tests/Drupal/Setup/TestInstallationSetup.php @@ -4,6 +4,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Test\FunctionalTestSetupTrait; +use Drupal\Core\Test\TestDatabase; use Drupal\Core\Test\TestSetupTrait; use Drupal\Tests\RandomGeneratorTrait; use Drupal\Tests\SessionTestTrait; @@ -61,6 +62,43 @@ public function setup($profile = 'testing', $setup_class = NULL) { } } + /** + * Removes a given instance by deleting all the database tables. + * + * @param string $db_prefix + * The used database prefix. + */ + public function teardown($db_prefix) { + $tables = Database::getConnection()->schema()->findTables('%'); + foreach ($tables as $table) { + if (Database::getConnection()->schema()->dropTable($table)) { + unset($tables[$table]); + } + } + + // Delete test site directory. + $test_database = new TestDatabase($db_prefix); + file_unmanaged_delete_recursive($test_database->getTestSitePath(), [$this, 'filePreDeleteCallback']); + } + + /** + * Ensures test files are deletable within file_unmanaged_delete_recursive(). + * + * Some tests chmod generated files to be read only. During + * BrowserTestBase::cleanupEnvironment() and other cleanup operations, + * these files need to get deleted too. + * + * @param string $path + * The file path. + */ + public static function filePreDeleteCallback($path) { + // When the webserver runs with the same system user as phpunit, we can + // make read-only files writable again. If not, chmod will fail while the + // file deletion still works if file permissions have been configured + // correctly. Thus, we ignore any problems while running chmod. + @chmod($path, 0700); + } + /** * Gets the database prefix. *