annotate core/tests/Drupal/TestSite/Commands/TestSiteTearDownCommand.php @ 4:a9cd425dd02b

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:11:55 +0000
parents
children
rev   line source
Chris@4 1 <?php
Chris@4 2
Chris@4 3 namespace Drupal\TestSite\Commands;
Chris@4 4
Chris@4 5 use Drupal\Core\Database\Database;
Chris@4 6 use Drupal\Core\Test\TestDatabase;
Chris@4 7 use Drupal\Tests\BrowserTestBase;
Chris@4 8 use Symfony\Component\Console\Command\Command;
Chris@4 9 use Symfony\Component\Console\Input\InputArgument;
Chris@4 10 use Symfony\Component\Console\Input\InputInterface;
Chris@4 11 use Symfony\Component\Console\Input\InputOption;
Chris@4 12 use Symfony\Component\Console\Output\OutputInterface;
Chris@4 13 use Symfony\Component\Console\Style\SymfonyStyle;
Chris@4 14
Chris@4 15 /**
Chris@4 16 * Command to tear down a test Drupal site.
Chris@4 17 *
Chris@4 18 * @internal
Chris@4 19 */
Chris@4 20 class TestSiteTearDownCommand extends Command {
Chris@4 21
Chris@4 22 /**
Chris@4 23 * {@inheritdoc}
Chris@4 24 */
Chris@4 25 protected function configure() {
Chris@4 26 $this->setName('tear-down')
Chris@4 27 ->setDescription('Removes a test site added by the install command')
Chris@4 28 ->setHelp('All the database tables and files will be removed.')
Chris@4 29 ->addArgument('db-prefix', InputArgument::REQUIRED, 'The database prefix for the test site.')
Chris@4 30 ->addOption('db-url', NULL, InputOption::VALUE_OPTIONAL, 'URL for database. Defaults to the environment variable SIMPLETEST_DB.', getenv('SIMPLETEST_DB'))
Chris@4 31 ->addOption('keep-lock', NULL, InputOption::VALUE_NONE, 'Keeps the database prefix lock. Useful for ensuring test isolation when running concurrent tests.')
Chris@4 32 ->addUsage('test12345678')
Chris@4 33 ->addUsage('test12345678 --db-url "mysql://username:password@localhost/databasename#table_prefix"')
Chris@4 34 ->addUsage('test12345678 --keep-lock');
Chris@4 35 }
Chris@4 36
Chris@4 37 /**
Chris@4 38 * {@inheritdoc}
Chris@4 39 */
Chris@4 40 protected function execute(InputInterface $input, OutputInterface $output) {
Chris@4 41 $db_prefix = $input->getArgument('db-prefix');
Chris@4 42 // Validate the db_prefix argument.
Chris@4 43 try {
Chris@4 44 $test_database = new TestDatabase($db_prefix);
Chris@4 45 }
Chris@4 46 catch (\InvalidArgumentException $e) {
Chris@4 47 $io = new SymfonyStyle($input, $output);
Chris@4 48 $io->getErrorStyle()->error("Invalid database prefix: $db_prefix\n\nValid database prefixes match the regular expression '/test(\d+)$/'. For example, 'test12345678'.");
Chris@4 49 // Display the synopsis of the command like Composer does.
Chris@4 50 $output->writeln(sprintf('<info>%s</info>', sprintf($this->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
Chris@4 51 return 1;
Chris@4 52 }
Chris@4 53
Chris@4 54 $db_url = $input->getOption('db-url');
Chris@4 55 putenv("SIMPLETEST_DB=$db_url");
Chris@4 56
Chris@4 57 // Handle the cleanup of the test site.
Chris@4 58 $this->tearDown($test_database, $db_url);
Chris@4 59
Chris@4 60 // Release the test database prefix lock.
Chris@4 61 if (!$input->getOption('keep-lock')) {
Chris@4 62 $test_database->releaseLock();
Chris@4 63 }
Chris@4 64
Chris@4 65 $output->writeln("<info>Successfully uninstalled $db_prefix test site</info>");
Chris@4 66 }
Chris@4 67
Chris@4 68 /**
Chris@4 69 * Removes a given instance by deleting all the database tables and files.
Chris@4 70 *
Chris@4 71 * @param \Drupal\Core\Test\TestDatabase $test_database
Chris@4 72 * The test database object.
Chris@4 73 * @param string $db_url
Chris@4 74 * The database URL.
Chris@4 75 *
Chris@4 76 * @see \Drupal\Tests\BrowserTestBase::cleanupEnvironment()
Chris@4 77 */
Chris@4 78 protected function tearDown(TestDatabase $test_database, $db_url) {
Chris@4 79 // Connect to the test database.
Chris@4 80 $root = dirname(dirname(dirname(dirname(dirname(__DIR__)))));
Chris@4 81 $database = Database::convertDbUrlToConnectionInfo($db_url, $root);
Chris@4 82 $database['prefix'] = ['default' => $test_database->getDatabasePrefix()];
Chris@4 83 Database::addConnectionInfo(__CLASS__, 'default', $database);
Chris@4 84
Chris@4 85 // Remove all the tables.
Chris@4 86 $schema = Database::getConnection('default', __CLASS__)->schema();
Chris@4 87 $tables = $schema->findTables('%');
Chris@4 88 array_walk($tables, [$schema, 'dropTable']);
Chris@4 89
Chris@4 90 // Delete test site directory.
Chris@4 91 $this->fileUnmanagedDeleteRecursive($root . DIRECTORY_SEPARATOR . $test_database->getTestSitePath(), [BrowserTestBase::class, 'filePreDeleteCallback']);
Chris@4 92 }
Chris@4 93
Chris@4 94 /**
Chris@4 95 * Deletes all files and directories in the specified path recursively.
Chris@4 96 *
Chris@4 97 * Note this method has no dependencies on Drupal core to ensure that the
Chris@4 98 * test site can be torn down even if something in the test site is broken.
Chris@4 99 *
Chris@4 100 * @param string $path
Chris@4 101 * A string containing either an URI or a file or directory path.
Chris@4 102 * @param callable $callback
Chris@4 103 * (optional) Callback function to run on each file prior to deleting it and
Chris@4 104 * on each directory prior to traversing it. For example, can be used to
Chris@4 105 * modify permissions.
Chris@4 106 *
Chris@4 107 * @return bool
Chris@4 108 * TRUE for success or if path does not exist, FALSE in the event of an
Chris@4 109 * error.
Chris@4 110 *
Chris@4 111 * @see file_unmanaged_delete_recursive()
Chris@4 112 */
Chris@4 113 protected function fileUnmanagedDeleteRecursive($path, $callback = NULL) {
Chris@4 114 if (isset($callback)) {
Chris@4 115 call_user_func($callback, $path);
Chris@4 116 }
Chris@4 117 if (is_dir($path)) {
Chris@4 118 $dir = dir($path);
Chris@4 119 while (($entry = $dir->read()) !== FALSE) {
Chris@4 120 if ($entry == '.' || $entry == '..') {
Chris@4 121 continue;
Chris@4 122 }
Chris@4 123 $entry_path = $path . '/' . $entry;
Chris@4 124 $this->fileUnmanagedDeleteRecursive($entry_path, $callback);
Chris@4 125 }
Chris@4 126 $dir->close();
Chris@4 127
Chris@4 128 return rmdir($path);
Chris@4 129 }
Chris@4 130 return unlink($path);
Chris@4 131 }
Chris@4 132
Chris@4 133 }