annotate core/tests/Drupal/Tests/Scripts/TestSiteApplicationTest.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\Tests\Scripts;
Chris@17 4
Chris@17 5 use Drupal\Component\FileSystem\FileSystem;
Chris@17 6 use Drupal\Core\Database\Database;
Chris@17 7 use Drupal\Core\Test\TestDatabase;
Chris@17 8 use Drupal\Tests\UnitTestCase;
Chris@17 9 use GuzzleHttp\Client;
Chris@17 10 use GuzzleHttp\Psr7\Request;
Chris@17 11 use Symfony\Component\Process\PhpExecutableFinder;
Chris@17 12 use Symfony\Component\Process\Process;
Chris@17 13
Chris@17 14 /**
Chris@17 15 * Tests core/scripts/test-site.php.
Chris@17 16 *
Chris@17 17 * @group Setup
Chris@17 18 *
Chris@17 19 * This test uses the Drupal\Core\Database\Database class which has a static.
Chris@17 20 * Therefore run in a separate process to avoid side effects.
Chris@17 21 *
Chris@17 22 * @runTestsInSeparateProcesses
Chris@17 23 * @preserveGlobalState disabled
Chris@17 24 *
Chris@17 25 * @see \Drupal\TestSite\TestSiteApplication
Chris@17 26 * @see \Drupal\TestSite\Commands\TestSiteInstallCommand
Chris@17 27 * @see \Drupal\TestSite\Commands\TestSiteTearDownCommand
Chris@17 28 */
Chris@17 29 class TestSiteApplicationTest extends UnitTestCase {
Chris@17 30
Chris@17 31 /**
Chris@17 32 * The PHP executable path.
Chris@17 33 *
Chris@17 34 * @var string
Chris@17 35 */
Chris@17 36 protected $php;
Chris@17 37
Chris@17 38 /**
Chris@17 39 * {@inheritdoc}
Chris@17 40 */
Chris@17 41 protected function setUp() {
Chris@17 42 parent::setUp();
Chris@17 43 $php_executable_finder = new PhpExecutableFinder();
Chris@17 44 $this->php = $php_executable_finder->find();
Chris@17 45 $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
Chris@17 46 }
Chris@17 47
Chris@17 48 /**
Chris@17 49 * @coversNothing
Chris@17 50 */
Chris@17 51 public function testInstallWithNonExistingFile() {
Chris@17 52
Chris@17 53 // Create a connection to the DB configured in SIMPLETEST_DB.
Chris@17 54 $connection = Database::getConnection('default', $this->addTestDatabase(''));
Chris@17 55 $table_count = count($connection->schema()->findTables('%'));
Chris@17 56
Chris@17 57 $command_line = $this->php . ' core/scripts/test-site.php install --setup-file "this-class-does-not-exist" --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 58 $process = new Process($command_line, $this->root);
Chris@17 59 $process->run();
Chris@17 60
Chris@17 61 $this->assertContains('The file this-class-does-not-exist does not exist.', $process->getErrorOutput());
Chris@17 62 $this->assertSame(1, $process->getExitCode());
Chris@17 63 $this->assertCount($table_count, $connection->schema()->findTables('%'), 'No additional tables created in the database');
Chris@17 64 }
Chris@17 65
Chris@17 66 /**
Chris@17 67 * @coversNothing
Chris@17 68 */
Chris@17 69 public function testInstallWithFileWithNoClass() {
Chris@17 70
Chris@17 71 // Create a connection to the DB configured in SIMPLETEST_DB.
Chris@17 72 $connection = Database::getConnection('default', $this->addTestDatabase(''));
Chris@17 73 $table_count = count($connection->schema()->findTables('%'));
Chris@17 74
Chris@17 75 $command_line = $this->php . ' core/scripts/test-site.php install --setup-file core/tests/fixtures/empty_file.php.module --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 76 $process = new Process($command_line, $this->root);
Chris@17 77 $process->run();
Chris@17 78
Chris@17 79 $this->assertContains('The file core/tests/fixtures/empty_file.php.module does not contain a class', $process->getErrorOutput());
Chris@17 80 $this->assertSame(1, $process->getExitCode());
Chris@17 81 $this->assertCount($table_count, $connection->schema()->findTables('%'), 'No additional tables created in the database');
Chris@17 82 }
Chris@17 83
Chris@17 84 /**
Chris@17 85 * @coversNothing
Chris@17 86 */
Chris@17 87 public function testInstallWithNonSetupClass() {
Chris@17 88
Chris@17 89 // Create a connection to the DB configured in SIMPLETEST_DB.
Chris@17 90 $connection = Database::getConnection('default', $this->addTestDatabase(''));
Chris@17 91 $table_count = count($connection->schema()->findTables('%'));
Chris@17 92
Chris@17 93 // Use __FILE__ to test absolute paths.
Chris@17 94 $command_line = $this->php . ' core/scripts/test-site.php install --setup-file "' . __FILE__ . '" --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 95 $process = new Process($command_line, $this->root, ['COLUMNS' => PHP_INT_MAX]);
Chris@17 96 $process->run();
Chris@17 97
Chris@17 98 $this->assertContains('The class Drupal\Tests\Scripts\TestSiteApplicationTest contained in', $process->getErrorOutput());
Chris@17 99 $this->assertContains('needs to implement \Drupal\TestSite\TestSetupInterface', $process->getErrorOutput());
Chris@17 100 $this->assertSame(1, $process->getExitCode());
Chris@17 101 $this->assertCount($table_count, $connection->schema()->findTables('%'), 'No additional tables created in the database');
Chris@17 102 }
Chris@17 103
Chris@17 104 /**
Chris@17 105 * @coversNothing
Chris@17 106 */
Chris@17 107 public function testInstallScript() {
Chris@17 108 $simpletest_path = $this->root . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . 'simpletest';
Chris@17 109 if (!is_writable($simpletest_path)) {
Chris@17 110 $this->markTestSkipped("Requires the directory $simpletest_path to exist and be writable");
Chris@17 111 }
Chris@17 112
Chris@17 113 // Install a site using the JSON output.
Chris@17 114 $command_line = $this->php . ' core/scripts/test-site.php install --json --setup-file core/tests/Drupal/TestSite/TestSiteInstallTestScript.php --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 115 $process = new Process($command_line, $this->root);
Chris@17 116 // Set the timeout to a value that allows debugging.
Chris@17 117 $process->setTimeout(500);
Chris@17 118 $process->run();
Chris@17 119
Chris@17 120 $this->assertSame(0, $process->getExitCode());
Chris@17 121 $result = json_decode($process->getOutput(), TRUE);
Chris@17 122 $db_prefix = $result['db_prefix'];
Chris@17 123 $this->assertStringStartsWith('simpletest' . substr($db_prefix, 4) . ':', $result['user_agent']);
Chris@17 124
Chris@17 125 $http_client = new Client();
Chris@17 126 $request = (new Request('GET', getenv('SIMPLETEST_BASE_URL') . '/test-page'))
Chris@17 127 ->withHeader('User-Agent', trim($result['user_agent']));
Chris@17 128
Chris@17 129 $response = $http_client->send($request);
Chris@17 130 // Ensure the test_page_test module got installed.
Chris@17 131 $this->assertContains('Test page | Drupal', (string) $response->getBody());
Chris@17 132
Chris@17 133 // Ensure that there are files and database tables for the tear down command
Chris@17 134 // to clean up.
Chris@17 135 $key = $this->addTestDatabase($db_prefix);
Chris@17 136 $this->assertGreaterThan(0, count(Database::getConnection('default', $key)->schema()->findTables('%')));
Chris@17 137 $test_database = new TestDatabase($db_prefix);
Chris@17 138 $test_file = $this->root . DIRECTORY_SEPARATOR . $test_database->getTestSitePath() . DIRECTORY_SEPARATOR . '.htkey';
Chris@17 139 $this->assertFileExists($test_file);
Chris@17 140
Chris@17 141 // Ensure the lock file exists.
Chris@17 142 $this->assertFileExists($this->getTestLockFile($db_prefix));
Chris@17 143
Chris@17 144 // Install another site so we can ensure the tear down command only removes
Chris@17 145 // one site at a time. Use the regular output.
Chris@17 146 $command_line = $this->php . ' core/scripts/test-site.php install --setup-file core/tests/Drupal/TestSite/TestSiteInstallTestScript.php --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 147 $process = new Process($command_line, $this->root);
Chris@17 148 // Set the timeout to a value that allows debugging.
Chris@17 149 $process->setTimeout(500);
Chris@17 150 $process->run();
Chris@17 151 $this->assertContains('Successfully installed a test site', $process->getOutput());
Chris@17 152 $this->assertSame(0, $process->getExitCode());
Chris@17 153 $regex = '/Database prefix\s+([^\s]*)/';
Chris@17 154 $this->assertRegExp($regex, $process->getOutput());
Chris@17 155 preg_match('/Database prefix\s+([^\s]*)/', $process->getOutput(), $matches);
Chris@17 156 $other_db_prefix = $matches[1];
Chris@17 157 $other_key = $this->addTestDatabase($other_db_prefix);
Chris@17 158 $this->assertGreaterThan(0, count(Database::getConnection('default', $other_key)->schema()->findTables('%')));
Chris@17 159
Chris@17 160 // Ensure the lock file exists for the new install.
Chris@17 161 $this->assertFileExists($this->getTestLockFile($other_db_prefix));
Chris@17 162
Chris@17 163 // Now test the tear down process as well, but keep the lock.
Chris@17 164 $command_line = $this->php . ' core/scripts/test-site.php tear-down ' . $db_prefix . ' --keep-lock --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 165 $process = new Process($command_line, $this->root);
Chris@17 166 // Set the timeout to a value that allows debugging.
Chris@17 167 $process->setTimeout(500);
Chris@17 168 $process->run();
Chris@17 169 $this->assertSame(0, $process->getExitCode());
Chris@17 170 $this->assertContains("Successfully uninstalled $db_prefix test site", $process->getOutput());
Chris@17 171
Chris@17 172 // Ensure that all the tables and files for this DB prefix are gone.
Chris@17 173 $this->assertCount(0, Database::getConnection('default', $key)->schema()->findTables('%'));
Chris@17 174 $this->assertFileNotExists($test_file);
Chris@17 175
Chris@17 176 // Ensure the other site's tables and files still exist.
Chris@17 177 $this->assertGreaterThan(0, count(Database::getConnection('default', $other_key)->schema()->findTables('%')));
Chris@17 178 $test_database = new TestDatabase($other_db_prefix);
Chris@17 179 $test_file = $this->root . DIRECTORY_SEPARATOR . $test_database->getTestSitePath() . DIRECTORY_SEPARATOR . '.htkey';
Chris@17 180 $this->assertFileExists($test_file);
Chris@17 181
Chris@17 182 // Tear down the other site. Tear down should work if the test site is
Chris@17 183 // broken. Prove this by removing its settings.php.
Chris@17 184 $test_site_settings = $this->root . DIRECTORY_SEPARATOR . $test_database->getTestSitePath() . DIRECTORY_SEPARATOR . 'settings.php';
Chris@17 185 $this->assertTrue(unlink($test_site_settings));
Chris@17 186 $command_line = $this->php . ' core/scripts/test-site.php tear-down ' . $other_db_prefix . ' --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 187 $process = new Process($command_line, $this->root);
Chris@17 188 // Set the timeout to a value that allows debugging.
Chris@17 189 $process->setTimeout(500);
Chris@17 190 $process->run();
Chris@17 191 $this->assertSame(0, $process->getExitCode());
Chris@17 192 $this->assertContains("Successfully uninstalled $other_db_prefix test site", $process->getOutput());
Chris@17 193
Chris@17 194 // Ensure that all the tables and files for this DB prefix are gone.
Chris@17 195 $this->assertCount(0, Database::getConnection('default', $other_key)->schema()->findTables('%'));
Chris@17 196 $this->assertFileNotExists($test_file);
Chris@17 197
Chris@17 198 // The lock for the first site should still exist but the second site's lock
Chris@17 199 // is released during tear down.
Chris@17 200 $this->assertFileExists($this->getTestLockFile($db_prefix));
Chris@17 201 $this->assertFileNotExists($this->getTestLockFile($other_db_prefix));
Chris@17 202 }
Chris@17 203
Chris@17 204 /**
Chris@17 205 * @coversNothing
Chris@17 206 */
Chris@17 207 public function testInstallInDifferentLanguage() {
Chris@17 208 $simpletest_path = $this->root . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . 'simpletest';
Chris@17 209 if (!is_writable($simpletest_path)) {
Chris@17 210 $this->markTestSkipped("Requires the directory $simpletest_path to exist and be writable");
Chris@17 211 }
Chris@17 212
Chris@17 213 $command_line = $this->php . ' core/scripts/test-site.php install --json --langcode fr --setup-file core/tests/Drupal/TestSite/TestSiteInstallTestScript.php --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 214 $process = new Process($command_line, $this->root);
Chris@17 215 $process->setTimeout(500);
Chris@17 216 $process->run();
Chris@17 217 $this->assertEquals(0, $process->getExitCode());
Chris@17 218
Chris@17 219 $result = json_decode($process->getOutput(), TRUE);
Chris@17 220 $db_prefix = $result['db_prefix'];
Chris@17 221 $http_client = new Client();
Chris@17 222 $request = (new Request('GET', getenv('SIMPLETEST_BASE_URL') . '/test-page'))
Chris@17 223 ->withHeader('User-Agent', trim($result['user_agent']));
Chris@17 224
Chris@17 225 $response = $http_client->send($request);
Chris@17 226 // Ensure the test_page_test module got installed.
Chris@17 227 $this->assertContains('Test page | Drupal', (string) $response->getBody());
Chris@17 228 $this->assertContains('lang="fr"', (string) $response->getBody());
Chris@17 229
Chris@17 230 // Now test the tear down process as well.
Chris@17 231 $command_line = $this->php . ' core/scripts/test-site.php tear-down ' . $db_prefix . ' --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 232 $process = new Process($command_line, $this->root);
Chris@17 233 $process->setTimeout(500);
Chris@17 234 $process->run();
Chris@17 235 $this->assertSame(0, $process->getExitCode());
Chris@17 236
Chris@17 237 // Ensure that all the tables for this DB prefix are gone.
Chris@17 238 $this->assertCount(0, Database::getConnection('default', $this->addTestDatabase($db_prefix))->schema()->findTables('%'));
Chris@17 239 }
Chris@17 240
Chris@17 241 /**
Chris@17 242 * @coversNothing
Chris@17 243 */
Chris@17 244 public function testTearDownDbPrefixValidation() {
Chris@17 245 $command_line = $this->php . ' core/scripts/test-site.php tear-down not-a-valid-prefix';
Chris@17 246 $process = new Process($command_line, $this->root);
Chris@17 247 $process->setTimeout(500);
Chris@17 248 $process->run();
Chris@17 249 $this->assertSame(1, $process->getExitCode());
Chris@17 250 $this->assertContains('Invalid database prefix: not-a-valid-prefix', $process->getErrorOutput());
Chris@17 251 }
Chris@17 252
Chris@17 253 /**
Chris@17 254 * @coversNothing
Chris@17 255 */
Chris@17 256 public function testUserLogin() {
Chris@17 257 $simpletest_path = $this->root . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . 'simpletest';
Chris@17 258 if (!is_writable($simpletest_path)) {
Chris@17 259 $this->markTestSkipped("Requires the directory $simpletest_path to exist and be writable");
Chris@17 260 }
Chris@17 261
Chris@17 262 // Install a site using the JSON output.
Chris@17 263 $command_line = $this->php . ' core/scripts/test-site.php install --json --setup-file core/tests/Drupal/TestSite/TestSiteInstallTestScript.php --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 264 $process = new Process($command_line, $this->root);
Chris@17 265 // Set the timeout to a value that allows debugging.
Chris@17 266 $process->setTimeout(500);
Chris@17 267 $process->run();
Chris@17 268
Chris@17 269 $this->assertSame(0, $process->getExitCode());
Chris@17 270 $result = json_decode($process->getOutput(), TRUE);
Chris@17 271 $db_prefix = $result['db_prefix'];
Chris@17 272 $site_path = $result['site_path'];
Chris@17 273 $this->assertSame('sites/simpletest/' . str_replace('test', '', $db_prefix), $site_path);
Chris@17 274
Chris@17 275 // Test the user login command with valid uid.
Chris@17 276 $command_line = $this->php . ' core/scripts/test-site.php user-login 1 --site-path ' . $site_path;
Chris@17 277 $process = new Process($command_line, $this->root);
Chris@17 278 $process->run();
Chris@17 279 $this->assertSame(0, $process->getExitCode());
Chris@17 280 $this->assertContains('/user/reset/1/', $process->getOutput());
Chris@17 281
Chris@17 282 $http_client = new Client();
Chris@17 283 $request = (new Request('GET', getenv('SIMPLETEST_BASE_URL') . trim($process->getOutput())))
Chris@17 284 ->withHeader('User-Agent', trim($result['user_agent']));
Chris@17 285
Chris@17 286 $response = $http_client->send($request);
Chris@17 287
Chris@17 288 // Ensure the response sets a new session.
Chris@17 289 $this->assertTrue($response->getHeader('Set-Cookie'));
Chris@17 290
Chris@17 291 // Test the user login command with invalid uid.
Chris@17 292 $command_line = $this->php . ' core/scripts/test-site.php user-login invalid-uid --site-path ' . $site_path;
Chris@17 293 $process = new Process($command_line, $this->root);
Chris@17 294 $process->run();
Chris@17 295 $this->assertSame(1, $process->getExitCode());
Chris@17 296 $this->assertContains('The "uid" argument needs to be an integer, but it is "invalid-uid".', $process->getErrorOutput());
Chris@17 297
Chris@17 298 // Now tear down the test site.
Chris@17 299 $command_line = $this->php . ' core/scripts/test-site.php tear-down ' . $db_prefix . ' --db-url "' . getenv('SIMPLETEST_DB') . '"';
Chris@17 300 $process = new Process($command_line, $this->root);
Chris@17 301 // Set the timeout to a value that allows debugging.
Chris@17 302 $process->setTimeout(500);
Chris@17 303 $process->run();
Chris@17 304 $this->assertSame(0, $process->getExitCode());
Chris@17 305 $this->assertContains("Successfully uninstalled $db_prefix test site", $process->getOutput());
Chris@17 306 }
Chris@17 307
Chris@17 308 /**
Chris@17 309 * Adds the installed test site to the database connection info.
Chris@17 310 *
Chris@17 311 * @param string $db_prefix
Chris@17 312 * The prefix of the installed test site.
Chris@17 313 *
Chris@17 314 * @return string
Chris@17 315 * The database key of the added connection.
Chris@17 316 */
Chris@17 317 protected function addTestDatabase($db_prefix) {
Chris@17 318 $database = Database::convertDbUrlToConnectionInfo(getenv('SIMPLETEST_DB'), $this->root);
Chris@17 319 $database['prefix'] = ['default' => $db_prefix];
Chris@17 320 $target = __CLASS__ . $db_prefix;
Chris@17 321 Database::addConnectionInfo($target, 'default', $database);
Chris@17 322 return $target;
Chris@17 323 }
Chris@17 324
Chris@17 325 /**
Chris@17 326 * Gets the lock file path.
Chris@17 327 *
Chris@17 328 * @param string $db_prefix
Chris@17 329 * The prefix of the installed test site.
Chris@17 330 *
Chris@17 331 * @return string
Chris@17 332 * The lock file path.
Chris@17 333 */
Chris@17 334 protected function getTestLockFile($db_prefix) {
Chris@17 335 $lock_id = str_replace('test', '', $db_prefix);
Chris@17 336 return FileSystem::getOsTemporaryDirectory() . '/test_' . $lock_id;
Chris@17 337 }
Chris@17 338
Chris@17 339 }