diff --git a/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php b/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php index 7af4c369bc..15bc1bb0a2 100644 --- a/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php +++ b/core/tests/Drupal/KernelTests/Setup/Commands/SetupDrupalTestScriptTest.php @@ -2,6 +2,7 @@ namespace Drupal\KernelTests\Setup\Commands; +use Drupal\Core\Database\Connection; use Drupal\KernelTests\KernelTestBase; use Drupal\Setup\Commands\TestInstallationSetupApplication; use Drupal\Setup\SetupDrupalTestScript; @@ -14,9 +15,6 @@ * * @group Setup * - * @todo Move this to the \Drupal\KernelTests\Setup\Commands\ namespace after - * https://www.drupal.org/project/drupal/issues/2878269 - * * @see \Drupal\Setup\TestInstallationSetup * @see \Drupal\Setup\Commands\TestInstallationSetupApplication * @see \Drupal\Setup\Commands\TestInstallationSetupCommand @@ -125,6 +123,9 @@ public function testInstallScript() { 'interactive' => FALSE, ] ); + + // Ensure that all the tables for this DB prefix are gone. + $this->assertCount(0, \Drupal::database()->schema()->findTables($db_prefix . '%')); } /** diff --git a/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php b/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php index f14bee5276..787c398f5d 100644 --- a/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php +++ b/core/tests/Drupal/Setup/Commands/TestInstallationSetupCommand.php @@ -2,9 +2,15 @@ namespace Drupal\Setup\Commands; +use Drupal\Core\Database\Database; use Drupal\Core\DrupalKernel; use Drupal\Core\Site\Settings; +use Drupal\Core\Test\FunctionalTestSetupTrait; +use Drupal\Core\Test\TestSetupTrait; use Drupal\Setup\TestInstallationSetup; +use Drupal\Setup\TestSetupInterface; +use Drupal\Tests\RandomGeneratorTrait; +use Drupal\Tests\SessionTestTrait; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -18,6 +24,40 @@ */ class TestInstallationSetupCommand extends Command { + use FunctionalTestSetupTrait; + use RandomGeneratorTrait; + use SessionTestTrait; + use TestSetupTrait; + + /** + * The install profile to use. + * + * @var string + */ + protected $profile; + + /** + * Time limit in seconds for the test. + * + * @var int + */ + protected $timeLimit = 500; + + /** + * The database prefix of this test run. + * + * @var string + */ + protected $databasePrefix; + + + /** + * The language to install the site in. + * + * @var string + */ + protected $langcode = 'en'; + /** * The used PHP autoloader. * @@ -64,15 +104,17 @@ protected function execute(InputInterface $input, OutputInterface $output) { $this->bootstrapDrupal(); // Manage site fixture. - $test = new TestInstallationSetup(); - $test->setup('testing', $input->getOption('setup_class'), $input->getOption('langcode')); + $this->setup('testing', $input->getOption('setup_class'), $input->getOption('langcode')); $output->writeln(json_encode([ - 'db_prefix' => $test->getDatabasePrefix(), - 'user_agent' => drupal_generate_test_ua($test->getDatabasePrefix()), + 'db_prefix' => $this->databasePrefix, + 'user_agent' => drupal_generate_test_ua($this->databasePrefix), ])); } + /** + * Bootstraps the drupal kernel. + */ protected function bootstrapDrupal() { $request = Request::createFromGlobals(); $kernel = DrupalKernel::createFromRequest($request, $this->autoloader, $this->getApplication()->getName()); @@ -85,4 +127,126 @@ protected function bootstrapDrupal() { ); } + /** + * Creates a test drupal installation. + * + * @param string $profile + * (optional) The installation profile to use. + * @param string $setup_class + * (optional) Setup class. A PHP class to setup configuration used by the + * test. + * @param string $langcode + * (optional) The language to install the site in. + */ + public function setup($profile = 'testing', $setup_class = NULL, $langcode = 'en') { + $this->profile = $profile; + $this->langcode = $langcode; + $this->setupBaseUrl(); + $this->prepareEnvironment(); + $this->installDrupal(); + + if ($setup_class) { + $this->executeSetupClass($setup_class); + } + } + + /** + * 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); + } + + /** + * Installs Drupal into the Simpletest site. + */ + protected function installDrupal() { + $this->initUserSession(); + $this->prepareSettings(); + $this->doInstall(); + $this->initSettings(); + $container = $this->initKernel(\Drupal::request()); + $this->initConfig($container); + $this->installModulesFromClassProperty($container); + $this->rebuildAll(); + } + + /** + * Uses the setup file to configure Drupal. + * + * @param string $class + * The full qualified class name, which should setup Drupal for tests. One + * common need for example would be to create the required content types and + * fields. The class needs to implement \Drupal\Setup\TestSetupInterface + * + * @see \Drupal\Setup\TestSetupInterface + */ + protected function executeSetupClass($class) { + if (!class_exists($class)) { + throw new \InvalidArgumentException("There was a problem loading {$class}"); + } + + if (!is_subclass_of($class, TestSetupInterface::class)) { + throw new \InvalidArgumentException(sprintf('You need to define a class implementing \Drupal\Setup\TestSetupInterface')); + } + + /** @var \Drupal\Setup\TestSetupInterface $instance */ + $instance = new $class; + $instance->setup(); + } + + /** + * {@inheritdoc} + */ + protected function installParameters() { + $connection_info = Database::getConnectionInfo(); + $driver = $connection_info['default']['driver']; + $connection_info['default']['prefix'] = $connection_info['default']['prefix']['default']; + unset($connection_info['default']['driver']); + unset($connection_info['default']['namespace']); + unset($connection_info['default']['pdo']); + unset($connection_info['default']['init_commands']); + $parameters = [ + 'interactive' => FALSE, + 'parameters' => [ + 'profile' => $this->profile, + 'langcode' => $this->langcode, + ], + 'forms' => [ + 'install_settings_form' => [ + 'driver' => $driver, + $driver => $connection_info['default'], + ], + 'install_configure_form' => [ + 'site_name' => 'Drupal', + 'site_mail' => 'simpletest@example.com', + 'account' => [ + 'name' => $this->rootUser->name, + 'mail' => $this->rootUser->getEmail(), + 'pass' => [ + 'pass1' => $this->rootUser->pass_raw, + 'pass2' => $this->rootUser->pass_raw, + ], + ], + // form_type_checkboxes_value() requires NULL instead of FALSE values + // for programmatic form submissions to disable a checkbox. + 'enable_update_status_module' => NULL, + 'enable_update_status_emails' => NULL, + ], + ], + ]; + return $parameters; + } + } diff --git a/core/tests/Drupal/Setup/Commands/TestTeardownCommand.php b/core/tests/Drupal/Setup/Commands/TestTeardownCommand.php index 7266207b42..ef09908ad3 100644 --- a/core/tests/Drupal/Setup/Commands/TestTeardownCommand.php +++ b/core/tests/Drupal/Setup/Commands/TestTeardownCommand.php @@ -2,8 +2,10 @@ namespace Drupal\Setup\Commands; +use Drupal\Core\Database\Database; use Drupal\Core\DrupalKernel; use Drupal\Core\Site\Settings; +use Drupal\Core\Test\TestDatabase; use Drupal\Setup\TestInstallationSetup; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -12,7 +14,7 @@ use Symfony\Component\HttpFoundation\Request; /** - * Tears down a test Drupal. + * Symfony console command to tear down Drupal. * * @internal */ @@ -26,7 +28,7 @@ class TestTeardownCommand extends Command { protected $autoloader; /** - * Constructs a new TestInstallationSetupCommand. + * Constructs a new TestTeardownCommand. * * @param string $autoloader * The used PHP autoloader. @@ -62,11 +64,32 @@ protected function execute(InputInterface $input, OutputInterface $output) { $this->bootstrapDrupal($db_prefix); - // Manage site fixture. - $test = new TestInstallationSetup(); - $test->teardown($db_prefix); + // Handle the cleanup of the test site. + $this->teardown($db_prefix); } + /** + * 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']); + } + + /** + * Bootstraps the drupal kernel. + */ protected function bootstrapDrupal($db_prefix) { $request = Request::createFromGlobals(); $_COOKIE['SIMPLETEST_USER_AGENT'] = drupal_generate_test_ua($db_prefix); diff --git a/core/tests/Drupal/Setup/TestInstallationSetup.php b/core/tests/Drupal/Setup/TestInstallationSetup.php index 25d33d530d..cbdfde3acc 100644 --- a/core/tests/Drupal/Setup/TestInstallationSetup.php +++ b/core/tests/Drupal/Setup/TestInstallationSetup.php @@ -16,188 +16,5 @@ */ class TestInstallationSetup { - use FunctionalTestSetupTrait; - use RandomGeneratorTrait; - use SessionTestTrait; - use TestSetupTrait; - - /** - * The install profile to use. - * - * @var string - */ - protected $profile; - - /** - * Time limit in seconds for the test. - * - * @var int - */ - protected $timeLimit = 500; - - /** - * The database prefix of this test run. - * - * @var string - */ - protected $databasePrefix; - - - /** - * The language to install the site in. - * - * @var string - */ - protected $langcode = 'en'; - - /** - * Creates a test drupal installation. - * - * @param string $profile - * (optional) The installation profile to use. - * @param string $setup_class - * (optional) Setup class. A PHP class to setup configuration used by the - * test. - * @param string $langcode - * (optional) The language to install the site in. - */ - public function setup($profile = 'testing', $setup_class = NULL, $langcode = 'en') { - $this->profile = $profile; - $this->langcode = $langcode; - $this->setupBaseUrl(); - $this->prepareEnvironment(); - $this->installDrupal(); - - if ($setup_class) { - $this->executeSetupClass($setup_class); - } - } - - /** - * 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. - * - * @return string - */ - public function getDatabasePrefix() { - return $this->databasePrefix; - } - - /** - * Installs Drupal into the Simpletest site. - */ - protected function installDrupal() { - $this->initUserSession(); - $this->prepareSettings(); - $this->doInstall(); - $this->initSettings(); - $container = $this->initKernel(\Drupal::request()); - $this->initConfig($container); - $this->installModulesFromClassProperty($container); - $this->rebuildAll(); - } - - /** - * Uses the setup file to configure Drupal. - * - * @param string $class - * The full qualified class name, which should setup Drupal for tests. One common need for - * example would be to create the required content types and fields. - * The class needs to implement \Drupal\Setup\TestSetupInterface - * - * @see \Drupal\Setup\TestSetupInterface - */ - protected function executeSetupClass($class) { - if (!class_exists($class)) { - throw new \InvalidArgumentException("There was a problem loading {$class}"); - } - - if (!is_subclass_of($class, TestSetupInterface::class)) { - throw new \InvalidArgumentException(sprintf('You need to define a class implementing \Drupal\Setup\TestSetupInterface')); - } - - /** @var \Drupal\Setup\TestSetupInterface $instance */ - $instance = new $class; - $instance->setup(); - } - - /** - * {@inheritdoc} - */ - protected function installParameters() { - $connection_info = Database::getConnectionInfo(); - $driver = $connection_info['default']['driver']; - $connection_info['default']['prefix'] = $connection_info['default']['prefix']['default']; - unset($connection_info['default']['driver']); - unset($connection_info['default']['namespace']); - unset($connection_info['default']['pdo']); - unset($connection_info['default']['init_commands']); - $parameters = [ - 'interactive' => FALSE, - 'parameters' => [ - 'profile' => $this->profile, - 'langcode' => $this->langcode, - ], - 'forms' => [ - 'install_settings_form' => [ - 'driver' => $driver, - $driver => $connection_info['default'], - ], - 'install_configure_form' => [ - 'site_name' => 'Drupal', - 'site_mail' => 'simpletest@example.com', - 'account' => [ - 'name' => $this->rootUser->name, - 'mail' => $this->rootUser->getEmail(), - 'pass' => [ - 'pass1' => $this->rootUser->pass_raw, - 'pass2' => $this->rootUser->pass_raw, - ], - ], - // form_type_checkboxes_value() requires NULL instead of FALSE values - // for programmatic form submissions to disable a checkbox. - 'enable_update_status_module' => NULL, - 'enable_update_status_emails' => NULL, - ], - ], - ]; - return $parameters; - } } diff --git a/core/tests/Drupal/Setup/TestSetupInterface.php b/core/tests/Drupal/Setup/TestSetupInterface.php index fe992161dc..5cd60c0df2 100644 --- a/core/tests/Drupal/Setup/TestSetupInterface.php +++ b/core/tests/Drupal/Setup/TestSetupInterface.php @@ -8,7 +8,7 @@ interface TestSetupInterface { /** - * Run code to setup the test. + * Run the code to setup the test environment. * * You have access to any API provided by any installed module. To install * modules use @@ -16,7 +16,8 @@ * \Drupal::service('module_installer')->install(['my_module']) * @endcode * - * Check out 'core/tests/Drupal/Setup/SetupDrupalTestScript.php' for an example. + * Check out 'core/tests/Drupal/Setup/SetupDrupalTestScript.php' for an + * example. */ public function setup();