php = $php_executable_finder->find(); $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)))); chdir($this->root); if (!is_writable("{$this->root}/sites/simpletest")) { $this->markTestSkipped('This test requires a writable sites/simpletest directory'); } // Get a lock and a valid site path. $this->testDb = new TestDatabase(); } /** * {@inheritdoc} */ public function tearDown() { if ($this->testDb) { $test_site_directory = $this->root . DIRECTORY_SEPARATOR . $this->testDb->getTestSitePath(); if (file_exists($test_site_directory)) { // @todo use the tear down command from // https://www.drupal.org/project/drupal/issues/2926633 // Delete test site directory. $this->fileUnmanagedDeleteRecursive($test_site_directory, [ BrowserTestBase::class, 'filePreDeleteCallback', ]); } } parent::tearDown(); } /** * Tests the quick-start command. */ public function testQuickStartCommand() { // Install a site using the standard profile to ensure the one time login // link generation works. $install_command = "{$this->php} core/scripts/drupal quick-start standard --site-name='Test site {$this->testDb->getDatabasePrefix()}' --suppress-login"; $process = new Process($install_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]); $process->inheritEnvironmentVariables(); $process->setTimeout(500); $process->start(); $guzzle = new Client(); $port = FALSE; while ($process->isRunning()) { if (preg_match('/127.0.0.1:(\d+)/', $process->getOutput(), $match)) { $port = $match[1]; break; } // Wait for more output. sleep(1); } // The progress bar uses STDERR to write messages. $this->assertContains('Congratulations, you installed Drupal!', $process->getErrorOutput()); $this->assertNotFalse($port, "Web server running on port $port"); // Give the server a couple of seconds to be ready. sleep(2); $this->assertContains("127.0.0.1:$port/user/reset/1/", $process->getOutput()); // Generate a cookie so we can make a request against the installed site. include $this->root . '/core/includes/bootstrap.inc'; define('DRUPAL_TEST_IN_CHILD_SITE', FALSE); chmod($this->testDb->getTestSitePath(), 0755); $cookieJar = CookieJar::fromArray([ 'SIMPLETEST_USER_AGENT' => drupal_generate_test_ua($this->testDb->getDatabasePrefix()), ], '127.0.0.1'); $response = $guzzle->get('http://127.0.0.1:' . $port, ['cookies' => $cookieJar]); $content = (string) $response->getBody(); $this->assertContains('Test site ' . $this->testDb->getDatabasePrefix(), $content); // Stop the web server. $process->stop(); } /** * Tests the quick-start commands. */ public function testQuickStartInstallAndServerCommands() { // Install a site. $install_command = "{$this->php} core/scripts/drupal install testing --site-name='Test site {$this->testDb->getDatabasePrefix()}'"; $install_process = new Process($install_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]); $install_process->inheritEnvironmentVariables(); $install_process->setTimeout(500); $result = $install_process->run(); // The progress bar uses STDERR to write messages. $this->assertContains('Congratulations, you installed Drupal!', $install_process->getErrorOutput()); $this->assertSame(0, $result); // Run the PHP built-in webserver. $server_command = "{$this->php} core/scripts/drupal server --suppress-login"; $server_process = new Process($server_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]); $server_process->inheritEnvironmentVariables(); $server_process->start(); $guzzle = new Client(); $port = FALSE; while ($server_process->isRunning()) { if (preg_match('/127.0.0.1:(\d+)/', $server_process->getOutput(), $match)) { $port = $match[1]; break; } // Wait for more output. sleep(1); } $this->assertEquals('', $server_process->getErrorOutput()); $this->assertContains("127.0.0.1:$port/user/reset/1/", $server_process->getOutput()); $this->assertNotFalse($port, "Web server running on port $port"); // Give the server a couple of seconds to be ready. sleep(2); // Generate a cookie so we can make a request against the installed site. include $this->root . '/core/includes/bootstrap.inc'; define('DRUPAL_TEST_IN_CHILD_SITE', FALSE); chmod($this->testDb->getTestSitePath(), 0755); $cookieJar = CookieJar::fromArray([ 'SIMPLETEST_USER_AGENT' => drupal_generate_test_ua($this->testDb->getDatabasePrefix()), ], '127.0.0.1'); $response = $guzzle->get('http://127.0.0.1:' . $port, ['cookies' => $cookieJar]); $content = (string) $response->getBody(); $this->assertContains('Test site ' . $this->testDb->getDatabasePrefix(), $content); // Try to re-install over the top of an existing site. $install_command = "{$this->php} core/scripts/drupal install testing --site-name='Test another site {$this->testDb->getDatabasePrefix()}'"; $install_process = new Process($install_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]); $install_process->inheritEnvironmentVariables(); $install_process->setTimeout(500); $result = $install_process->run(); $this->assertContains('Drupal is already installed.', $install_process->getOutput()); $this->assertSame(0, $result); // Ensure the site name has not changed. $response = $guzzle->get('http://127.0.0.1:' . $port, ['cookies' => $cookieJar]); $content = (string) $response->getBody(); $this->assertContains('Test site ' . $this->testDb->getDatabasePrefix(), $content); // Stop the web server. $server_process->stop(); } /** * Tests the install command with an invalid profile. */ public function testQuickStartCommandProfileValidation() { // Install a site using the standard profile to ensure the one time login // link generation works. $install_command = "{$this->php} core/scripts/drupal quick-start umami --site-name='Test site {$this->testDb->getDatabasePrefix()}' --suppress-login"; $process = new Process($install_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]); $process->inheritEnvironmentVariables(); $process->run(); $this->assertContains('\'umami\' is not a valid install profile. Did you mean \'demo_umami\'?', $process->getErrorOutput()); } /** * Tests the server command when there is no installation. */ public function testServerWithNoInstall() { $server_command = "{$this->php} core/scripts/drupal server --suppress-login"; $server_process = new Process($server_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]); $server_process->inheritEnvironmentVariables(); $server_process->run(); $this->assertContains('No installation found. Use the \'install\' command.', $server_process->getErrorOutput()); } /** * 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 an 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 file_unmanaged_delete_recursive() */ 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); } }