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