From 914d47f168f0a9192fee3e79ea51546bef7b40ff Mon Sep 17 00:00:00 2001 From: Lee Rowlands <lee.rowlands@previousnext.com.au> Date: Thu, 12 Sep 2019 13:01:25 +1000 Subject: [PATCH] Issue #2800267 by Mile23, Lendude, drugan, dawehner, mondrake: Turn simpletest_clean*() functions into a helper class --- .../Drupal/Core/Test/EnvironmentCleaner.php | 194 ++++++++++++++++++ .../Core/Test/EnvironmentCleanerInterface.php | 57 +++++ core/lib/Drupal/Core/Test/TestDatabase.php | 2 +- core/modules/simpletest/simpletest.install | 2 +- core/modules/simpletest/simpletest.module | 117 ++++------- .../simpletest/simpletest.services.yml | 8 +- .../src/EnvironmentCleanerFactory.php | 55 +++++ .../src/EnvironmentCleanerService.php | 124 +++++++++++ .../src/Form/SimpletestResultsForm.php | 16 +- .../tests/src/Functional/SimpletestTest.php | 36 ++++ .../src/Kernel/DeprecatedCleanupTest.php | 65 ++++++ core/scripts/run-tests.sh | 20 +- .../Core/Test/EnvironmentCleanerTest.php | 55 +++++ 13 files changed, 668 insertions(+), 83 deletions(-) create mode 100644 core/lib/Drupal/Core/Test/EnvironmentCleaner.php create mode 100644 core/lib/Drupal/Core/Test/EnvironmentCleanerInterface.php create mode 100644 core/modules/simpletest/src/EnvironmentCleanerFactory.php create mode 100644 core/modules/simpletest/src/EnvironmentCleanerService.php create mode 100644 core/modules/simpletest/tests/src/Functional/SimpletestTest.php create mode 100644 core/modules/simpletest/tests/src/Kernel/DeprecatedCleanupTest.php create mode 100644 core/tests/Drupal/KernelTests/Core/Test/EnvironmentCleanerTest.php diff --git a/core/lib/Drupal/Core/Test/EnvironmentCleaner.php b/core/lib/Drupal/Core/Test/EnvironmentCleaner.php new file mode 100644 index 000000000000..31da3cfc07b0 --- /dev/null +++ b/core/lib/Drupal/Core/Test/EnvironmentCleaner.php @@ -0,0 +1,194 @@ +<?php + +namespace Drupal\Core\Test; + +use Drupal\Core\Database\Connection; +use Drupal\Core\File\FileSystemInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Helper class for cleaning test environments. + */ +class EnvironmentCleaner implements EnvironmentCleanerInterface { + + /** + * Path to Drupal root directory. + * + * @var string + */ + protected $root; + + /** + * Connection to the database being used for tests. + * + * @var \Drupal\Core\Database\Connection + */ + protected $testDatabase; + + /** + * Connection to the database where test results are stored. + * + * This could be the same as $testDatabase, or it could be different. + * run-tests.sh allows you to specify a different results database with the + * --sqlite parameter. + * + * @var \Drupal\Core\Database\Connection + */ + protected $resultsDatabase; + + /** + * The file system service. + * + * @var \Drupal\Core\File\FileSystemInterface + */ + protected $fileSystem; + + /** + * Console output. + * + * @var \Symfony\Component\Console\Output\OutputInterface + */ + protected $output; + + /** + * Construct an environment cleaner. + * + * @param string $root + * The path to the root of the Drupal installation. + * @param \Drupal\Core\Database\Connection $test_database + * Connection to the database against which tests were run. + * @param \Drupal\Core\Database\Connection $results_database + * Connection to the database where test results were stored. This could be + * the same as $test_database, or it could be different. + * @param \Symfony\Component\Console\Output\OutputInterface $output + * A symfony console output object. + * @param \Drupal\Core\File\FileSystemInterface $file_system + * The file_system service. + */ + public function __construct($root, Connection $test_database, Connection $results_database, OutputInterface $output, FileSystemInterface $file_system) { + $this->root = $root; + $this->testDatabase = $test_database; + $this->resultsDatabase = $results_database; + $this->output = $output; + $this->fileSystem = $file_system; + } + + /** + * {@inheritdoc} + */ + public function cleanEnvironment($clear_results = TRUE, $clear_temp_directories = TRUE, $clear_database = TRUE) { + $count = 0; + if ($clear_database) { + $this->doCleanDatabase(); + } + if ($clear_temp_directories) { + $this->doCleanTemporaryDirectories(); + } + if ($clear_results) { + $count = $this->cleanResultsTable(); + $this->output->write('Test results removed: ' . $count); + } + else { + $this->output->write('Test results were not removed.'); + } + } + + /** + * {@inheritdoc} + */ + public function cleanDatabase() { + $count = $this->doCleanDatabase(); + if ($count > 0) { + $this->output->write('Leftover tables removed: ' . $count); + } + else { + $this->output->write('No leftover tables to remove.'); + } + } + + /** + * Performs the fixture database cleanup. + * + * @return int + * The number of tables that were removed. + */ + protected function doCleanDatabase() { + /* @var $schema \Drupal\Core\Database\Schema */ + $schema = $this->testDatabase->schema(); + $tables = $schema->findTables('test%'); + $count = 0; + foreach ($tables as $table) { + // Only drop tables which begin wih 'test' followed by digits, for example, + // {test12345678node__body}. + if (preg_match('/^test\d+.*/', $table, $matches)) { + $schema->dropTable($matches[0]); + $count++; + } + } + return $count; + } + + /** + * {@inheritdoc} + */ + public function cleanTemporaryDirectories() { + $count = $this->doCleanTemporaryDirectories(); + if ($count > 0) { + $this->output->write('Temporary directories removed: ' . $count); + } + else { + $this->output->write('No temporary directories to remove.'); + } + } + + /** + * Performs the cleanup of temporary test directories. + * + * @return int + * The count of temporary directories removed. + */ + protected function doCleanTemporaryDirectories() { + $count = 0; + $simpletest_dir = $this->root . '/sites/simpletest'; + if (is_dir($simpletest_dir)) { + $files = scandir($simpletest_dir); + foreach ($files as $file) { + if ($file[0] != '.') { + $path = $simpletest_dir . '/' . $file; + $this->fileSystem->deleteRecursive($path, function ($any_path) { + @chmod($any_path, 0700); + }); + $count++; + } + } + } + return $count; + } + + /** + * {@inheritdoc} + */ + public function cleanResultsTable($test_id = NULL) { + $count = 0; + if ($test_id) { + $count = $this->resultsDatabase->query('SELECT COUNT(test_id) FROM {simpletest_test_id} WHERE test_id = :test_id', [':test_id' => $test_id])->fetchField(); + + $this->resultsDatabase->delete('simpletest') + ->condition('test_id', $test_id) + ->execute(); + $this->resultsDatabase->delete('simpletest_test_id') + ->condition('test_id', $test_id) + ->execute(); + } + else { + $count = $this->resultsDatabase->query('SELECT COUNT(test_id) FROM {simpletest_test_id}')->fetchField(); + + // Clear test results. + $this->resultsDatabase->delete('simpletest')->execute(); + $this->resultsDatabase->delete('simpletest_test_id')->execute(); + } + + return $count; + } + +} diff --git a/core/lib/Drupal/Core/Test/EnvironmentCleanerInterface.php b/core/lib/Drupal/Core/Test/EnvironmentCleanerInterface.php new file mode 100644 index 000000000000..4487278ad2e9 --- /dev/null +++ b/core/lib/Drupal/Core/Test/EnvironmentCleanerInterface.php @@ -0,0 +1,57 @@ +<?php + +namespace Drupal\Core\Test; + +/** + * Defines an interface for cleaning up test results and fixtures. + * + * This interface is marked internal. It does not imply an API. + * + * @todo Formalize this interface in + * https://www.drupal.org/project/drupal/issues/3075490 and + * https://www.drupal.org/project/drupal/issues/3075608 + * + * @see https://www.drupal.org/project/drupal/issues/3075490 + * @see https://www.drupal.org/project/drupal/issues/3075608 + * + * @internal + */ +interface EnvironmentCleanerInterface { + + /** + * Removes all test-related database tables and directories. + * + * This method removes fixture files and database entries from the system + * under test. + * + * @param bool $clear_results + * (optional) Whether to clear the test results database. Defaults to TRUE. + * @param bool $clear_temp_directories + * (optional) Whether to clear the test site directories. Defaults to TRUE. + * @param bool $clear_database + * (optional) Whether to clean up the fixture database. Defaults to TRUE. + */ + public function cleanEnvironment($clear_results = TRUE, $clear_temp_directories = TRUE, $clear_database = TRUE); + + /** + * Remove database entries left over in the fixture database. + */ + public function cleanDatabase(); + + /** + * Finds all leftover fixture site directories and removes them. + */ + public function cleanTemporaryDirectories(); + + /** + * Clears test result tables from the results database. + * + * @param $test_id + * Test ID to remove results for, or NULL to remove all results. + * + * @return int + * The number of results that were removed. + */ + public function cleanResultsTable($test_id = NULL); + +} diff --git a/core/lib/Drupal/Core/Test/TestDatabase.php b/core/lib/Drupal/Core/Test/TestDatabase.php index 70c5c084fe10..115568f67b47 100644 --- a/core/lib/Drupal/Core/Test/TestDatabase.php +++ b/core/lib/Drupal/Core/Test/TestDatabase.php @@ -7,7 +7,7 @@ use Drupal\Core\Database\Database; /** - * Provides helper methods for interacting with the Simpletest database. + * Provides helper methods for interacting with the fixture database. */ class TestDatabase { diff --git a/core/modules/simpletest/simpletest.install b/core/modules/simpletest/simpletest.install index 424502789135..ae3cf832391d 100644 --- a/core/modules/simpletest/simpletest.install +++ b/core/modules/simpletest/simpletest.install @@ -90,7 +90,7 @@ function simpletest_uninstall() { // in a (recursive) test for itself, since simpletest_clean_environment() // would also delete the test site of the parent test process. if (!drupal_valid_test_ua()) { - simpletest_clean_environment(); + \Drupal::service('environment_cleaner')->cleanEnvironment(); } // Delete verbose test output and any other testing framework files. try { diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module index 07a2588602cc..5775c1d83da2 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -6,7 +6,6 @@ */ use Drupal\Core\Asset\AttachedAssetsInterface; -use Drupal\Core\Database\Database; use Drupal\Core\File\Exception\FileException; use Drupal\Core\Render\Element; use Drupal\Core\Routing\RouteMatchInterface; @@ -596,72 +595,51 @@ function simpletest_generate_file($filename, $width, $lines, $type = 'binary-tex /** * Removes all temporary database tables and directories. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the + * environment_cleaner service and call its cleanEnvironment() method, or use + * \Drupal\Core\Test\EnvironmentCleaner::cleanEnvironment() instead. + * + * @see https://www.drupal.org/node/3076634 */ function simpletest_clean_environment() { - simpletest_clean_database(); - simpletest_clean_temporary_directories(); - if (\Drupal::config('simpletest.settings')->get('clear_results')) { - $count = simpletest_clean_results_table(); - \Drupal::messenger()->addStatus(\Drupal::translation()->formatPlural($count, 'Removed 1 test result.', 'Removed @count test results.')); - } - else { - \Drupal::messenger()->addWarning(t('Clear results is disabled and the test results table will not be cleared.'), 'warning'); - } + @trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanEnvironment() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanEnvironment() instead.. See https://www.drupal.org/node/3076634', E_USER_DEPRECATED); + /* @var $cleaner \Drupal\simpletest\EnvironmentCleanerService */ + $cleaner = \Drupal::service('environment_cleaner'); + $cleaner->cleanEnvironment(); } /** * Removes prefixed tables from the database from crashed tests. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the + * environment_cleaner service and call its cleanDatabase() method, or use + * \Drupal\Core\Test\EnvironmentCleaner::cleanDatabase() instead. + * + * @see https://www.drupal.org/node/3076634 */ function simpletest_clean_database() { - $schema = Database::getConnection()->schema(); - $tables = $schema->findTables('test%'); - $count = 0; - foreach ($tables as $table) { - // Only drop tables which begin wih 'test' followed by digits, for example, - // {test12345678node__body}. - if (preg_match('/^test\d+.*/', $table, $matches)) { - $schema->dropTable($matches[0]); - $count++; - } - } - - if ($count > 0) { - \Drupal::messenger()->addStatus(\Drupal::translation()->formatPlural($count, 'Removed 1 leftover table.', 'Removed @count leftover tables.')); - } - else { - \Drupal::messenger()->addStatus(t('No leftover tables to remove.')); - } + @trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanDatabase() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanDatabase() instead. See https://www.drupal.org/node/3076634', E_USER_DEPRECATED); + /* @var $cleaner \Drupal\simpletest\EnvironmentCleanerService */ + $cleaner = \Drupal::service('environment_cleaner'); + $cleaner->cleanDatabase(); } /** * Finds all leftover temporary directories and removes them. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the + * environment_cleaner service and call its cleanTemporaryDirectories() + * method, or use + * \Drupal\Core\Test\EnvironmentCleaner::cleanTemporaryDirectories() instead. + * + * @see https://www.drupal.org/node/3076634 */ function simpletest_clean_temporary_directories() { - $count = 0; - if (is_dir(DRUPAL_ROOT . '/sites/simpletest')) { - $files = scandir(DRUPAL_ROOT . '/sites/simpletest'); - foreach ($files as $file) { - if ($file[0] != '.') { - $path = DRUPAL_ROOT . '/sites/simpletest/' . $file; - try { - \Drupal::service('file_system')->deleteRecursive($path, function ($any_path) { - @chmod($any_path, 0700); - }); - } - catch (FileException $e) { - // Ignore failed deletes. - } - $count++; - } - } - } - - if ($count > 0) { - \Drupal::messenger()->addStatus(\Drupal::translation()->formatPlural($count, 'Removed 1 temporary directory.', 'Removed @count temporary directories.')); - } - else { - \Drupal::messenger()->addStatus(t('No temporary directories to remove.')); - } + @trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanTemporaryDirectories() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanTemporaryDirectories() instead. See https://www.drupal.org/node/3076634', E_USER_DEPRECATED); + /* @var $cleaner \Drupal\simpletest\EnvironmentCleanerService */ + $cleaner = \Drupal::service('environment_cleaner'); + $cleaner->cleanTemporaryDirectories(); } /** @@ -672,31 +650,22 @@ function simpletest_clean_temporary_directories() { * * @return int * The number of results that were removed. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the + * environment_cleaner service and call its cleanResultsTable() method, or use + * \Drupal\Core\Test\EnvironmentCleaner::cleanResultsTable() instead. + * + * @see https://www.drupal.org/node/3076634 */ function simpletest_clean_results_table($test_id = NULL) { + @trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanResultsTable() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanResultsTable() instead. See https://www.drupal.org/node/3076634', E_USER_DEPRECATED); + $count = 0; if (\Drupal::config('simpletest.settings')->get('clear_results')) { - $connection = TestDatabase::getConnection(); - if ($test_id) { - $count = $connection->query('SELECT COUNT(test_id) FROM {simpletest_test_id} WHERE test_id = :test_id', [':test_id' => $test_id])->fetchField(); - - $connection->delete('simpletest') - ->condition('test_id', $test_id) - ->execute(); - $connection->delete('simpletest_test_id') - ->condition('test_id', $test_id) - ->execute(); - } - else { - $count = $connection->query('SELECT COUNT(test_id) FROM {simpletest_test_id}')->fetchField(); - - // Clear test results. - $connection->delete('simpletest')->execute(); - $connection->delete('simpletest_test_id')->execute(); - } - - return $count; + /* @var $cleaner \Drupal\simpletest\EnvironmentCleanerService */ + $cleaner = \Drupal::service('environment_cleaner'); + $count = $cleaner->cleanResultsTable($test_id); } - return 0; + return $count; } /** diff --git a/core/modules/simpletest/simpletest.services.yml b/core/modules/simpletest/simpletest.services.yml index 241519795798..afae7c4358c4 100644 --- a/core/modules/simpletest/simpletest.services.yml +++ b/core/modules/simpletest/simpletest.services.yml @@ -1,9 +1,13 @@ services: test_discovery: - # @todo Change this service so that it uses \Drupal\Core\Test\TestDiscovery - # in https://www.drupal.org/node/1667822 class: Drupal\simpletest\TestDiscovery arguments: ['@app.root', '@class_loader', '@module_handler'] + environment_cleaner_factory: + class: Drupal\simpletest\EnvironmentCleanerFactory + arguments: ['@service_container'] + environment_cleaner: + class: Drupal\simpletest\EnvironmentCleanerService + factory: 'environment_cleaner_factory:createCleaner' cache_context.test_discovery: class: Drupal\simpletest\Cache\Context\TestDiscoveryCacheContext arguments: ['@test_discovery', '@private_key'] diff --git a/core/modules/simpletest/src/EnvironmentCleanerFactory.php b/core/modules/simpletest/src/EnvironmentCleanerFactory.php new file mode 100644 index 000000000000..dc48b50a214f --- /dev/null +++ b/core/modules/simpletest/src/EnvironmentCleanerFactory.php @@ -0,0 +1,55 @@ +<?php + +namespace Drupal\simpletest; + +use Drupal\Core\DependencyInjection\Container; +use Drupal\Core\Test\TestDatabase; +use Drupal\Core\Database\Database; + +/** + * Test environment cleaner factory. + * + * We use a factory pattern here so that we can inject the test results database + * which is not a service (and should not be). + */ +class EnvironmentCleanerFactory { + + /** + * The container. + * + * @var \Drupal\Core\DependencyInjection\Container + */ + protected $container; + + /** + * Construct an environment cleaner factory. + * + * @param \Drupal\Core\DependencyInjection\Container $container + * The container. + */ + public function __construct(Container $container) { + $this->container = $container; + } + + /** + * Factory method to create the environment cleaner service. + * + * @return \Drupal\simpletest\EnvironmentCleanerService + * The environment cleaner service. + */ + public function createCleaner() { + $cleaner = new EnvironmentCleanerService( + $this->container->get('app.root'), + Database::getConnection(), + TestDatabase::getConnection(), + $this->container->get('messenger'), + $this->container->get('string_translation'), + $this->container->get('config.factory'), + $this->container->get('cache.default'), + $this->container->get('file_system') + ); + + return $cleaner; + } + +} diff --git a/core/modules/simpletest/src/EnvironmentCleanerService.php b/core/modules/simpletest/src/EnvironmentCleanerService.php new file mode 100644 index 000000000000..b4de5789ea9b --- /dev/null +++ b/core/modules/simpletest/src/EnvironmentCleanerService.php @@ -0,0 +1,124 @@ +<?php + +namespace Drupal\simpletest; + +use Drupal\Core\Database\Connection; +use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\Core\Config\ConfigFactory; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\File\FileSystem; +use Drupal\Core\Test\EnvironmentCleaner; + +/** + * Uses containerized services to perform post-test cleanup. + */ +class EnvironmentCleanerService extends EnvironmentCleaner { + + /** + * Messenger service. + * + * @var \Drupal\Core\Messenger\MessengerInterface + */ + protected $messenger; + + /** + * The translation service. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface + */ + protected $translation; + + /** + * The config factory. + * + * @var \Drupal\Core\Config\ConfigFactory + */ + protected $configFactory; + + /** + * Default cache. + * + * @var \Drupal\Core\Cache\CacheBackendInterface + */ + protected $cacheDefault; + + /** + * Construct an environment cleaner. + * + * @param string $root + * The path to the root of the Drupal installation. + * @param \Drupal\Core\Database\Connection $test_database + * Connection to the database against which tests were run. + * @param \Drupal\Core\Database\Connection $results_database + * Connection to the database where test results were stored. This could be + * the same as $test_database, or it could be different. + * @param \Drupal\Core\StringTranslation\TranslationInterface|null $translation + * (optional) The translation service. If none is supplied, this class will + * attempt to discover one using \Drupal. + */ + public function __construct($root, Connection $test_database, Connection $results_database, MessengerInterface $messenger, TranslationInterface $translation, ConfigFactory $config, CacheBackendInterface $cache_default, FileSystem $file_system) { + $this->root = $root; + $this->testDatabase = $test_database; + $this->resultsDatabase = $results_database; + $this->messenger = $messenger; + $this->translation = $translation; + $this->configFactory = $config; + $this->cacheDefault = $cache_default; + $this->fileSystem = $file_system; + } + + /** + * {@inheritdoc} + */ + public function cleanEnvironment($clear_results = TRUE, $clear_temp_directories = TRUE, $clear_database = TRUE) { + $results_removed = 0; + $clear_results = $this->configFactory->get('simpletest.settings')->get('clear_results'); + + if ($clear_database) { + $this->cleanDatabase(); + } + if ($clear_temp_directories) { + $this->cleanTemporaryDirectories(); + } + if ($clear_results) { + $results_removed = $this->cleanResultsTable(); + } + $this->cacheDefault->delete('simpletest'); + $this->cacheDefault->delete('simpletest_phpunit'); + + if ($clear_results) { + $this->messenger->addMessage($this->translation->formatPlural($results_removed, 'Removed 1 test result.', 'Removed @count test results.')); + } + else { + $this->messenger->addMessage($this->translation->translate('Clear results is disabled and the test results table will not be cleared.'), 'warning'); + } + } + + /** + * {@inheritdoc} + */ + public function cleanDatabase() { + $tables_removed = $this->doCleanDatabase(); + if ($tables_removed > 0) { + $this->messenger->addMessage($this->translation->formatPlural($tables_removed, 'Removed 1 leftover table.', 'Removed @count leftover tables.')); + } + else { + $this->messenger->addMessage($this->translation->translate('No leftover tables to remove.')); + } + } + + /** + * {@inheritdoc} + */ + public function cleanTemporaryDirectories() { + $directories_removed = $this->doCleanTemporaryDirectories(); + if ($directories_removed > 0) { + $this->messenger->addMessage($this->translation->formatPlural($directories_removed, 'Removed 1 temporary directory.', 'Removed @count temporary directories.')); + } + else { + $this->messenger->addMessage($this->translation->translate('No temporary directories to remove.')); + } + } + +} diff --git a/core/modules/simpletest/src/Form/SimpletestResultsForm.php b/core/modules/simpletest/src/Form/SimpletestResultsForm.php index 5db8846353fb..adc1d4a5bbbe 100644 --- a/core/modules/simpletest/src/Form/SimpletestResultsForm.php +++ b/core/modules/simpletest/src/Form/SimpletestResultsForm.php @@ -6,6 +6,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Test\EnvironmentCleanerInterface; use Drupal\Core\Url; use Drupal\simpletest\TestDiscovery; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -37,12 +38,20 @@ class SimpletestResultsForm extends FormBase { */ protected $database; + /** + * The environment cleaner service. + * + * @var \Drupal\Core\Test\EnvironmentCleanerInterface + */ + protected $cleaner; + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( - $container->get('database') + $container->get('database'), + $container->get('environment_cleaner') ); } @@ -52,8 +61,9 @@ public static function create(ContainerInterface $container) { * @param \Drupal\Core\Database\Connection $database * The database connection service. */ - public function __construct(Connection $database) { + public function __construct(Connection $database, EnvironmentCleanerInterface $cleaner) { $this->database = $database; + $this->cleaner = $cleaner; } /** @@ -162,7 +172,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $test_id ]; if (is_numeric($test_id)) { - simpletest_clean_results_table($test_id); + $this->cleaner->cleanResultsTable($test_id); } return $form; diff --git a/core/modules/simpletest/tests/src/Functional/SimpletestTest.php b/core/modules/simpletest/tests/src/Functional/SimpletestTest.php new file mode 100644 index 000000000000..a7f634deb0fd --- /dev/null +++ b/core/modules/simpletest/tests/src/Functional/SimpletestTest.php @@ -0,0 +1,36 @@ +<?php + +namespace Drupal\Tests\simpletest\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Basic functionality of the Testing module. + * + * @group simpletest + */ +class SimpletestTest extends BrowserTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = ['simpletest']; + + /** + * Test that we can uninstall the module without mishap. + * + * Upon uninstall, simpletest will clean up after itself. This should neither + * break the test runner's expectations, nor cause any kind of exception. + * + * Note that this might break run-tests.sh test runs that don't use the + * --sqlite argument. + */ + public function testUninstallModule() { + /* @var $installer \Drupal\Core\Extension\ModuleInstallerInterface */ + $installer = $this->container->get('module_installer'); + $this->assertTrue($installer->uninstall(['simpletest'])); + } + +} diff --git a/core/modules/simpletest/tests/src/Kernel/DeprecatedCleanupTest.php b/core/modules/simpletest/tests/src/Kernel/DeprecatedCleanupTest.php new file mode 100644 index 000000000000..ec29a7676868 --- /dev/null +++ b/core/modules/simpletest/tests/src/Kernel/DeprecatedCleanupTest.php @@ -0,0 +1,65 @@ +<?php + +namespace Drupal\Tests\simpletest\Kernel; + +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Test\EnvironmentCleanerInterface; +use Drupal\KernelTests\KernelTestBase; +use Symfony\Component\DependencyInjection\Definition; + +/** + * Verify deprecation errors for the cleanup functions. + * + * @group simpletest + * @group legacy + */ +class DeprecatedCleanupTest extends KernelTestBase { + + public static $modules = ['simpletest']; + + /** + * {@inheritdoc} + */ + public function register(ContainerBuilder $container) { + parent::register($container); + $cleaner_definition = new Definition(StubEnvironmentCleanerService::class); + $container->setDefinition('environment_cleaner', $cleaner_definition); + } + + /** + * @expectedDeprecation simpletest_clean_environment is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanEnvironment() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanEnvironment() instead.. See https://www.drupal.org/node/3076634 + * @expectedDeprecation simpletest_clean_database is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanDatabase() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanDatabase() instead. See https://www.drupal.org/node/3076634 + * @expectedDeprecation simpletest_clean_temporary_directories is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanTemporaryDirectories() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanTemporaryDirectories() instead. See https://www.drupal.org/node/3076634 + * @expectedDeprecation simpletest_clean_results_table is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Access the environment_cleaner service and call its cleanResultsTable() method, or use \Drupal\Core\Test\EnvironmentCleaner::cleanResultsTable() instead. See https://www.drupal.org/node/3076634 + */ + public function testDeprecatedCleanFunctions() { + $this->assertNull(simpletest_clean_environment()); + $this->assertNull(simpletest_clean_database()); + $this->assertNull(simpletest_clean_temporary_directories()); + $this->assertEquals(0, simpletest_clean_results_table()); + } + +} + +/** + * Mock environment_cleaner service that does not perform any cleaning. + */ +class StubEnvironmentCleanerService implements EnvironmentCleanerInterface { + + public function cleanDatabase() { + + } + + public function cleanEnvironment($clear_results = TRUE, $clear_temp_directories = TRUE, $clear_database = TRUE) { + + } + + public function cleanResultsTable($test_id = NULL) { + + } + + public function cleanTemporaryDirectories() { + + } + +} diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh index c4f910e2024d..c3f9d1a73aa8 100755 --- a/core/scripts/run-tests.sh +++ b/core/scripts/run-tests.sh @@ -14,12 +14,14 @@ use Drupal\Core\File\Exception\FileException; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\StreamWrapper\PublicStream; +use Drupal\Core\Test\EnvironmentCleaner; use Drupal\Core\Test\PhpUnitTestRunner; use Drupal\Core\Test\TestDatabase; use Drupal\Core\Test\TestRunnerKernel; use Drupal\simpletest\Form\SimpletestResultsForm; use Drupal\Core\Test\TestDiscovery; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\HttpFoundation\Request; // Define some colors for display. @@ -126,8 +128,15 @@ if ($args['clean']) { // Clean up left-over tables and directories. + $cleaner = new EnvironmentCleaner( + DRUPAL_ROOT, + Database::getConnection(), + TestDatabase::getConnection(), + new ConsoleOutput(), + \Drupal::service('file_system') + ); try { - simpletest_clean_environment(); + $cleaner->cleanEnvironment(); } catch (Exception $e) { echo (string) $e; @@ -181,7 +190,14 @@ // Clean up all test results. if (!$args['keep-results']) { try { - simpletest_clean_results_table(); + $cleaner = new EnvironmentCleaner( + DRUPAL_ROOT, + Database::getConnection(), + TestDatabase::getConnection(), + new ConsoleOutput(), + \Drupal::service('file_system') + ); + $cleaner->cleanResultsTable(); } catch (Exception $e) { echo (string) $e; diff --git a/core/tests/Drupal/KernelTests/Core/Test/EnvironmentCleanerTest.php b/core/tests/Drupal/KernelTests/Core/Test/EnvironmentCleanerTest.php new file mode 100644 index 000000000000..0ca66926007d --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Test/EnvironmentCleanerTest.php @@ -0,0 +1,55 @@ +<?php + +namespace Drupal\KernelTests\Core\Test; + +use Drupal\Core\Database\Connection; +use Drupal\Core\Test\EnvironmentCleaner; +use Drupal\KernelTests\KernelTestBase; +use org\bovigo\vfs\vfsStream; +use Symfony\Component\Console\Output\NullOutput; + +/** + * @coversDefaultClass \Drupal\Core\Test\EnvironmentCleaner + * @group Test + */ +class EnvironmentCleanerTest extends KernelTestBase { + + /** + * @covers ::doCleanTemporaryDirectories + */ + public function testDoCleanTemporaryDirectories() { + vfsStream::setup('cleanup_test', NULL, [ + 'sites' => [ + 'simpletest' => [ + 'delete_dir' => [ + 'delete.me' => 'I am a gonner.', + ], + 'delete_me.too' => 'delete this file.', + ], + ], + ]); + + $connection = $this->prophesize(Connection::class); + + $cleaner = new EnvironmentCleaner( + vfsStream::url('cleanup_test'), + $connection->reveal(), + $connection->reveal(), + new NullOutput(), + \Drupal::service('file_system') + ); + + $do_cleanup_ref = new \ReflectionMethod($cleaner, 'doCleanTemporaryDirectories'); + $do_cleanup_ref->setAccessible(TRUE); + + $this->assertFileExists(vfsStream::url('cleanup_test/sites/simpletest/delete_dir/delete.me')); + $this->assertFileExists(vfsStream::url('cleanup_test/sites/simpletest/delete_me.too')); + + $this->assertEquals(2, $do_cleanup_ref->invoke($cleaner)); + + $this->assertDirectoryNotExists(vfsStream::url('cleanup_test/sites/simpletest/delete_dir')); + $this->assertFileNotExists(vfsStream::url('cleanup_test/sites/simpletest/delete_dir/delete.me')); + $this->assertFileNotExists(vfsStream::url('cleanup_test/sites/simpletest/delete_me.too')); + } + +} -- GitLab