Initial Drupal 11 with DDEV setup
This commit is contained in:
		
							
								
								
									
										300
									
								
								web/core/tests/Drupal/BuildTests/QuickStart/QuickStartTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								web/core/tests/Drupal/BuildTests/QuickStart/QuickStartTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,300 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\BuildTests\QuickStart;
 | 
			
		||||
 | 
			
		||||
use Drupal\sqlite\Driver\Database\sqlite\Install\Tasks;
 | 
			
		||||
use Drupal\BuildTests\Framework\BuildTestBase;
 | 
			
		||||
use Drupal\Core\Test\TestDatabase;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use GuzzleHttp\Client;
 | 
			
		||||
use GuzzleHttp\Cookie\CookieJar;
 | 
			
		||||
use PHPUnit\Framework\Attributes\Group;
 | 
			
		||||
use PHPUnit\Framework\Attributes\PreserveGlobalState;
 | 
			
		||||
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
 | 
			
		||||
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 | 
			
		||||
use Symfony\Component\Process\PhpExecutableFinder;
 | 
			
		||||
use Symfony\Component\Process\Process;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the quick-start commands.
 | 
			
		||||
 *
 | 
			
		||||
 * These tests are run in a separate process because they load Drupal code via
 | 
			
		||||
 * an include.
 | 
			
		||||
 */
 | 
			
		||||
#[Group('Command')]
 | 
			
		||||
#[PreserveGlobalState(FALSE)]
 | 
			
		||||
#[RequiresPhpExtension('pdo_sqlite')]
 | 
			
		||||
#[RunTestsInSeparateProcesses]
 | 
			
		||||
class QuickStartTest extends BuildTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The PHP executable path.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $php;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * A test database object.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\Test\TestDatabase
 | 
			
		||||
   */
 | 
			
		||||
  protected $testDb;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The Drupal root directory.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $root;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    $php_executable_finder = new PhpExecutableFinder();
 | 
			
		||||
    $this->php = $php_executable_finder->find();
 | 
			
		||||
    $this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
 | 
			
		||||
    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}
 | 
			
		||||
   */
 | 
			
		||||
  protected function tearDown(): void {
 | 
			
		||||
    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(): void {
 | 
			
		||||
    $sqlite = (new \PDO('sqlite::memory:'))->query('select sqlite_version()')->fetch()[0];
 | 
			
		||||
    if (version_compare($sqlite, Tasks::SQLITE_MINIMUM_VERSION) < 0) {
 | 
			
		||||
      $this->markTestSkipped();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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->setTimeout(500);
 | 
			
		||||
    $process->start();
 | 
			
		||||
    $guzzle = new Client();
 | 
			
		||||
    $port = FALSE;
 | 
			
		||||
    $process->waitUntil(function ($type, $output) use (&$port) {
 | 
			
		||||
      if (preg_match('/127.0.0.1:(\d+)/', $output, $match)) {
 | 
			
		||||
        $port = $match[1];
 | 
			
		||||
        return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    // The progress bar uses STDERR to write messages.
 | 
			
		||||
    $this->assertStringContainsString('Congratulations, you installed Drupal!', $process->getErrorOutput());
 | 
			
		||||
    // Ensure the command does not trigger any PHP deprecations.
 | 
			
		||||
    $this->assertStringNotContainsString('Deprecated', $process->getErrorOutput());
 | 
			
		||||
    $this->assertNotFalse($port, "Web server running on port $port");
 | 
			
		||||
 | 
			
		||||
    // Give the server a couple of seconds to be ready.
 | 
			
		||||
    sleep(2);
 | 
			
		||||
    $this->assertStringContainsString("127.0.0.1:$port/user/reset/1/", $process->getOutput());
 | 
			
		||||
 | 
			
		||||
    // Generate a cookie so we can make a request against the installed site.
 | 
			
		||||
    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->assertStringContainsString('Test site ' . $this->testDb->getDatabasePrefix(), $content);
 | 
			
		||||
 | 
			
		||||
    // Stop the web server.
 | 
			
		||||
    $process->stop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the quick-start commands.
 | 
			
		||||
   */
 | 
			
		||||
  public function testQuickStartInstallAndServerCommands(): void {
 | 
			
		||||
    $sqlite = (new \PDO('sqlite::memory:'))->query('select sqlite_version()')->fetch()[0];
 | 
			
		||||
    if (version_compare($sqlite, Tasks::SQLITE_MINIMUM_VERSION) < 0) {
 | 
			
		||||
      $this->markTestSkipped();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Install a site.
 | 
			
		||||
    $install_command = [
 | 
			
		||||
      $this->php,
 | 
			
		||||
      'core/scripts/drupal',
 | 
			
		||||
      'install',
 | 
			
		||||
      'minimal',
 | 
			
		||||
      "--password='secret'",
 | 
			
		||||
      "--site-name='Test site {$this->testDb->getDatabasePrefix()}'",
 | 
			
		||||
    ];
 | 
			
		||||
    $install_process = new Process($install_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]);
 | 
			
		||||
    $install_process->setTimeout(500);
 | 
			
		||||
    $result = $install_process->run();
 | 
			
		||||
    // The progress bar uses STDERR to write messages.
 | 
			
		||||
    $this->assertStringContainsString('Congratulations, you installed Drupal!', $install_process->getErrorOutput());
 | 
			
		||||
    $this->assertStringContainsString("Password: 'secret'", $install_process->getOutput());
 | 
			
		||||
    $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->start();
 | 
			
		||||
    $guzzle = new Client();
 | 
			
		||||
    $port = FALSE;
 | 
			
		||||
    $server_process->waitUntil(function ($type, $output) use (&$port) {
 | 
			
		||||
      if (preg_match('/127.0.0.1:(\d+)\/user\/reset\/1\//', $output, $match)) {
 | 
			
		||||
        $port = $match[1];
 | 
			
		||||
        return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    $this->assertEquals('', $server_process->getErrorOutput());
 | 
			
		||||
    $this->assertStringContainsString("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.
 | 
			
		||||
    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->assertStringContainsString('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->setTimeout(500);
 | 
			
		||||
    $result = $install_process->run();
 | 
			
		||||
    $this->assertStringContainsString('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->assertStringContainsString('Test site ' . $this->testDb->getDatabasePrefix(), $content);
 | 
			
		||||
 | 
			
		||||
    // Stop the web server.
 | 
			
		||||
    $server_process->stop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the install command with an invalid profile.
 | 
			
		||||
   */
 | 
			
		||||
  public function testQuickStartCommandProfileValidation(): void {
 | 
			
		||||
    // 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->run();
 | 
			
		||||
    $this->assertMatchesRegularExpression("/'umami' is not a valid install profile or recipe\. Did you mean \W*'demo_umami'?/", $process->getErrorOutput());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the server command when there is no installation.
 | 
			
		||||
   */
 | 
			
		||||
  public function testServerWithNoInstall(): void {
 | 
			
		||||
    $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->run();
 | 
			
		||||
    $this->assertStringContainsString('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 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): bool {
 | 
			
		||||
    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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\BuildTests\QuickStart;
 | 
			
		||||
 | 
			
		||||
use Drupal\BuildTests\Framework\BuildTestBase;
 | 
			
		||||
use Symfony\Component\Process\PhpExecutableFinder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper methods for using the quickstart feature of Drupal.
 | 
			
		||||
 */
 | 
			
		||||
abstract class QuickStartTestBase extends BuildTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * User name of the admin account generated during install.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $adminUsername;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Password of the admin account generated during install.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $adminPassword;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Install a Drupal site using the quick start feature.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $profile
 | 
			
		||||
   *   Drupal profile to install.
 | 
			
		||||
   * @param string $working_dir
 | 
			
		||||
   *   (optional) A working directory relative to the workspace, within which to
 | 
			
		||||
   *   execute the command. Defaults to the workspace directory.
 | 
			
		||||
   */
 | 
			
		||||
  public function installQuickStart($profile, $working_dir = NULL) {
 | 
			
		||||
    $php_finder = new PhpExecutableFinder();
 | 
			
		||||
    $install_process = $this->executeCommand($php_finder->find() . ' ./core/scripts/drupal install ' . $profile, $working_dir);
 | 
			
		||||
    $this->assertCommandOutputContains('Username:');
 | 
			
		||||
    preg_match('/Username: (.+)\vPassword: (.+)/', $install_process->getOutput(), $matches);
 | 
			
		||||
    $this->assertNotEmpty($this->adminUsername = $matches[1]);
 | 
			
		||||
    $this->assertNotEmpty($this->adminPassword = $matches[2]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Helper that uses Drupal's user/login form to log in.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $username
 | 
			
		||||
   *   Username.
 | 
			
		||||
   * @param string $password
 | 
			
		||||
   *   Password.
 | 
			
		||||
   * @param string $working_dir
 | 
			
		||||
   *   (optional) A working directory within which to login. Defaults to the
 | 
			
		||||
   *   workspace directory.
 | 
			
		||||
   */
 | 
			
		||||
  public function formLogin($username, $password, $working_dir = NULL) {
 | 
			
		||||
    $this->visit('/user/login', $working_dir);
 | 
			
		||||
    $assert = $this->getMink()->assertSession();
 | 
			
		||||
    $assert->statusCodeEquals(200);
 | 
			
		||||
    $assert->fieldExists('edit-name')->setValue($username);
 | 
			
		||||
    $assert->fieldExists('edit-pass')->setValue($password);
 | 
			
		||||
    $session = $this->getMink()->getSession();
 | 
			
		||||
    $session->getPage()->findButton('Log in')->submit();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,186 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\BuildTests\QuickStart;
 | 
			
		||||
 | 
			
		||||
use Drupal\sqlite\Driver\Database\sqlite\Install\Tasks;
 | 
			
		||||
use Drupal\BuildTests\Framework\BuildTestBase;
 | 
			
		||||
use Drupal\Core\Test\TestDatabase;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use GuzzleHttp\Client;
 | 
			
		||||
use GuzzleHttp\Cookie\CookieJar;
 | 
			
		||||
use PHPUnit\Framework\Attributes\Group;
 | 
			
		||||
use PHPUnit\Framework\Attributes\PreserveGlobalState;
 | 
			
		||||
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
 | 
			
		||||
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 | 
			
		||||
use Symfony\Component\Process\PhpExecutableFinder;
 | 
			
		||||
use Symfony\Component\Process\Process;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the quick-start command with recipes.
 | 
			
		||||
 *
 | 
			
		||||
 * These tests are run in a separate process because they load Drupal code via
 | 
			
		||||
 * an include.
 | 
			
		||||
 */
 | 
			
		||||
#[Group('Command')]
 | 
			
		||||
#[Group('Recipe')]
 | 
			
		||||
#[PreserveGlobalState(FALSE)]
 | 
			
		||||
#[RequiresPhpExtension('pdo_sqlite')]
 | 
			
		||||
#[RunTestsInSeparateProcesses]
 | 
			
		||||
class RecipeQuickStartTest extends BuildTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The PHP executable path.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected string $php;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * A test database object.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\Test\TestDatabase
 | 
			
		||||
   */
 | 
			
		||||
  protected TestDatabase $testDb;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The Drupal root directory.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected string $root;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    $php_executable_finder = new PhpExecutableFinder();
 | 
			
		||||
    $this->php = (string) $php_executable_finder->find();
 | 
			
		||||
    $this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
 | 
			
		||||
    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}
 | 
			
		||||
   */
 | 
			
		||||
  protected function tearDown(): void {
 | 
			
		||||
    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::filePreDeleteCallback(...));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    parent::tearDown();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the quick-start command with a recipe.
 | 
			
		||||
   */
 | 
			
		||||
  public function testQuickStartRecipeCommand(): void {
 | 
			
		||||
    $sqlite = (string) (new \PDO('sqlite::memory:'))->query('select sqlite_version()')->fetch()[0];
 | 
			
		||||
    if (version_compare($sqlite, Tasks::SQLITE_MINIMUM_VERSION) < 0) {
 | 
			
		||||
      $this->markTestSkipped();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Install a site using the standard recipe to ensure the one time login
 | 
			
		||||
    // link generation works.
 | 
			
		||||
 | 
			
		||||
    $script = $this->root . '/core/scripts/drupal';
 | 
			
		||||
    $install_command = [
 | 
			
		||||
      $this->php,
 | 
			
		||||
      $script,
 | 
			
		||||
      'quick-start',
 | 
			
		||||
      'core/recipes/standard',
 | 
			
		||||
      "--site-name='Test site {$this->testDb->getDatabasePrefix()}'",
 | 
			
		||||
      '--suppress-login',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->assertFileExists($script, "Install script is found in $script");
 | 
			
		||||
 | 
			
		||||
    $process = new Process($install_command, NULL, ['DRUPAL_DEV_SITE_PATH' => $this->testDb->getTestSitePath()]);
 | 
			
		||||
    $process->setTimeout(500);
 | 
			
		||||
    $process->start();
 | 
			
		||||
    $guzzle = new Client();
 | 
			
		||||
    $port = FALSE;
 | 
			
		||||
    $process->waitUntil(function ($type, $output) use (&$port) {
 | 
			
		||||
      if (preg_match('/127.0.0.1:(\d+)/', $output, $match)) {
 | 
			
		||||
        $port = $match[1];
 | 
			
		||||
        return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    // The progress bar uses STDERR to write messages.
 | 
			
		||||
    $this->assertStringContainsString('Congratulations, you installed Drupal!', $process->getErrorOutput());
 | 
			
		||||
    // Ensure the command does not trigger any PHP deprecations.
 | 
			
		||||
    $this->assertStringNotContainsStringIgnoringCase('deprecated', $process->getErrorOutput());
 | 
			
		||||
    $this->assertNotFalse($port, "Web server running on port $port");
 | 
			
		||||
 | 
			
		||||
    // Give the server a couple of seconds to be ready.
 | 
			
		||||
    sleep(2);
 | 
			
		||||
    $this->assertStringContainsString("127.0.0.1:$port/user/reset/1/", $process->getOutput());
 | 
			
		||||
 | 
			
		||||
    // Generate a cookie so we can make a request against the installed site.
 | 
			
		||||
    define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
 | 
			
		||||
    chmod($this->root . '/' . $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->assertStringContainsString('Test site ' . $this->testDb->getDatabasePrefix(), $content);
 | 
			
		||||
    // Test content from Standard front page.
 | 
			
		||||
    $this->assertStringContainsString('Congratulations and welcome to the Drupal community.', $content);
 | 
			
		||||
 | 
			
		||||
    // Stop the web server.
 | 
			
		||||
    $process->stop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 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): bool {
 | 
			
		||||
    if (isset($callback)) {
 | 
			
		||||
      call_user_func($callback, $path);
 | 
			
		||||
    }
 | 
			
		||||
    if (is_dir($path)) {
 | 
			
		||||
      $dir = dir($path);
 | 
			
		||||
      assert($dir instanceof \Directory);
 | 
			
		||||
      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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user