TestSiteTearDownCommand.php
Same filename in other branches
Namespace
Drupal\TestSite\CommandsFile
-
core/
tests/ Drupal/ TestSite/ Commands/ TestSiteTearDownCommand.php
View source
<?php
declare (strict_types=1);
namespace Drupal\TestSite\Commands;
use Drupal\Core\Database\Database;
use Drupal\Core\Test\TestDatabase;
use Drupal\Tests\BrowserTestBase;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Command to tear down a test Drupal site.
*
* @internal
*/
class TestSiteTearDownCommand extends Command {
/**
* {@inheritdoc}
*/
protected function configure() {
$this->setName('tear-down')
->setDescription('Removes a test site added by the install command')
->setHelp('All the database tables and files will be removed.')
->addArgument('db-prefix', InputArgument::REQUIRED, 'The database prefix for the test site.')
->addOption('db-url', NULL, InputOption::VALUE_OPTIONAL, 'URL for database. Defaults to the environment variable SIMPLETEST_DB.', getenv('SIMPLETEST_DB'))
->addOption('keep-lock', NULL, InputOption::VALUE_NONE, 'Keeps the database prefix lock. Useful for ensuring test isolation when running concurrent tests.')
->addUsage('test12345678')
->addUsage('test12345678 --db-url "mysql://username:password@localhost/database_name#table_prefix"')
->addUsage('test12345678 --keep-lock');
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) : int {
$root = dirname(__DIR__, 5);
chdir($root);
$db_prefix = $input->getArgument('db-prefix');
// Validate the db_prefix argument.
try {
$test_database = new TestDatabase($db_prefix);
} catch (\InvalidArgumentException $e) {
$io = new SymfonyStyle($input, $output);
$io->getErrorStyle()
->error("Invalid database prefix: {$db_prefix}\n\nValid database prefixes match the regular expression '/test(\\d+)\$/'. For example, 'test12345678'.");
// Display the synopsis of the command like Composer does.
$output->writeln(sprintf('<info>%s</info>', sprintf($this->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
return 1;
}
$db_url = $input->getOption('db-url');
putenv("SIMPLETEST_DB={$db_url}");
// Handle the cleanup of the test site.
$this->tearDown($test_database, $db_url);
// Release the test database prefix lock.
if (!$input->getOption('keep-lock')) {
$test_database->releaseLock();
}
$output->writeln("<info>Successfully uninstalled {$db_prefix} test site</info>");
return 0;
}
/**
* Removes a given instance by deleting all the database tables and files.
*
* @param \Drupal\Core\Test\TestDatabase $test_database
* The test database object.
* @param string $db_url
* The database URL.
*
* @see \Drupal\Tests\BrowserTestBase::cleanupEnvironment()
*/
protected function tearDown(TestDatabase $test_database, $db_url) : void {
// Connect to the test database.
$root = dirname(__DIR__, 5);
$database = Database::convertDbUrlToConnectionInfo($db_url, $root);
$database['prefix'] = $test_database->getDatabasePrefix();
Database::addConnectionInfo(__CLASS__, 'default', $database);
// Remove all the tables.
$schema = Database::getConnection('default', __CLASS__)->schema();
$tables = $schema->findTables('%');
array_walk($tables, [
$schema,
'dropTable',
]);
// Delete test site directory.
$this->fileUnmanagedDeleteRecursive($root . DIRECTORY_SEPARATOR . $test_database->getTestSitePath(), [
BrowserTestBase::class,
'filePreDeleteCallback',
]);
}
/**
* Deletes all files and directories in the specified path recursively.
*
* Note this method has no dependencies on Drupal core to ensure that the
* test site can be torn down even if something in the test site is broken.
*
* @param string $path
* A string containing either a URI or a file or directory path.
* @param callable $callback
* (optional) Callback function to run on each file prior to deleting it and
* on each directory prior to traversing it. For example, can be used to
* modify permissions.
*
* @return bool
* TRUE for success or if path does not exist, FALSE in the event of an
* error.
*
* @see \Drupal\Core\File\FileSystemInterface::deleteRecursive()
*/
protected function fileUnmanagedDeleteRecursive($path, $callback = NULL) {
if (isset($callback)) {
call_user_func($callback, $path);
}
if (is_dir($path)) {
$dir = dir($path);
while (($entry = $dir->read()) !== FALSE) {
if ($entry == '.' || $entry == '..') {
continue;
}
$entry_path = $path . '/' . $entry;
$this->fileUnmanagedDeleteRecursive($entry_path, $callback);
}
$dir->close();
return rmdir($path);
}
return unlink($path);
}
}
Classes
Title | Deprecated | Summary |
---|---|---|
TestSiteTearDownCommand | Command to tear down a test Drupal site. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.