annotate core/tests/Drupal/TestSite/Commands/TestSiteTearDownCommand.php @ 19:fa3358dc1485 tip

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