Verified Commit 04261575 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3455820 by nicxvan, alexpott, smustgrave: Decompress files for config_install

parent 89278799
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
      "modules/system/tests/logo.svgz",
      "node_modules/*",
      "profiles/demo_umami/modules/demo_umami_content/default_content/languages/es/**/*",
      "tests/fixtures/config_install/*",
      "tests/fixtures/files/*",
      "tests/Drupal/Tests/Component/Annotation/Doctrine/**",
      "tests/PHPStan/vendor/**",
+16 −1
Original line number Diff line number Diff line
@@ -398,7 +398,7 @@
	'path' => __DIR__ . '/lib/Drupal/Core/Extension/ExtensionVersion.php',
];
$ignoreErrors[] = [
	'message' => '#^The "module_installer\\.uninstall_validators" service is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0\\. Inject "\\!tagged_iterator module_install\\.uninstall_validator" instead\\. See https\\://www\\.drupal\\.org/node/3432595$#',
	'message' => '#^The "module_installer\\.uninstall_validators" service is deprecated in drupal\\:11\\.1\\.0 and is removed from drupal\\:12\\.0\\.0\\. Inject "\\!tagged_iterator module_install\\.uninstall_validator" instead\\. See https\\://www\\.drupal\\.org/node/3432595$#',
	'count' => 1,
	'path' => __DIR__ . '/lib/Drupal/Core/Extension/ModuleInstaller.php',
];
@@ -2379,6 +2379,21 @@
	'count' => 2,
	'path' => __DIR__ . '/tests/Drupal/BuildTests/Framework/Tests/BuildTestTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Drupal\\\\Tests\\\\BrowserTestBase\\:\\:\\$defaultTheme is required\\. See https\\://www\\.drupal\\.org/node/3083055, which includes recommendations on which theme to use\\.$#',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigExistingSettingsTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Drupal\\\\Tests\\\\BrowserTestBase\\:\\:\\$defaultTheme is required\\. See https\\://www\\.drupal\\.org/node/3083055, which includes recommendations on which theme to use\\.$#',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigNoSystemSiteTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Drupal\\\\Tests\\\\BrowserTestBase\\:\\:\\$defaultTheme is required\\. See https\\://www\\.drupal\\.org/node/3083055, which includes recommendations on which theme to use\\.$#',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigTest.php',
];
$ignoreErrors[] = [
	// identifier: variable.undefined
	'message' => '#^Variable \\$found might not be defined\\.$#',
+184 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\FunctionalTests\Installer;

use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
use Drupal\Core\Installer\Form\SelectProfileForm;

/**
 * Provides a base class for testing installing from existing configuration.
 */
abstract class InstallerConfigDirectoryTestBase extends InstallerTestBase {

  /**
   * This is set by the profile in the core.extension extracted.
   *
   * If set to FALSE, then the install will proceed without an install profile.
   */
  protected $profile = NULL;

  /**
   * @todo Fill out docblock.
   */
  protected $existingSyncDirectory = FALSE;

  /**
   * This copies a source directory to a destination directory recursively.
   *
   * @param string $source
   *   Source directory.
   * @param string $destination
   *   Destination directory.
   */
  protected function copyDirectory(string $source, string $destination): void {
    if (!is_dir($destination)) {
      mkdir($destination, 0755, TRUE);
    }
    $files = scandir($source);
    foreach ($files as $file) {
      if ($file !== '.' && $file !== '..') {
        $sourceFile = $source . '/' . $file;
        $destinationFile = $destination . '/' . $file;
        if (is_dir($sourceFile)) {
          $this->copyDirectory($sourceFile, $destinationFile);
        }
        else {
          copy($sourceFile, $destinationFile);
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function prepareEnvironment() {
    parent::prepareEnvironment();

    if ($this->profile === NULL) {
      $core_extension_location = $this->getConfigLocation() . '/core.extension.yml';
      $core_extension = Yaml::decode(file_get_contents($core_extension_location));
      $this->profile = $core_extension['profile'];
    }

    if ($this->profile !== FALSE) {
      // Create a profile for testing. We set core_version_requirement to '*' for
      // the test so that it does not need to be updated between major versions.
      $info = [
        'type' => 'profile',
        'core_version_requirement' => '*',
        'name' => 'Configuration installation test profile (' . $this->profile . ')',
      ];

      // File API functions are not available yet.
      $path = $this->siteDirectory . '/profiles/' . $this->profile;

      // Put the sync directory inside the profile.
      $config_sync_directory = $path . '/config/sync';

      mkdir($path, 0777, TRUE);
      file_put_contents("$path/{$this->profile}.info.yml", Yaml::encode($info));
    }
    else {
      // If we have no profile we must use an existing sync directory.
      $this->existingSyncDirectory = TRUE;
      $config_sync_directory = $this->siteDirectory . '/config/sync';
    }

    if ($this->existingSyncDirectory) {
      $config_sync_directory = $this->siteDirectory . '/config/sync';
      $this->settings['settings']['config_sync_directory'] = (object) [
        'value' => $config_sync_directory,
        'required' => TRUE,
      ];
    }

    // Create config/sync directory and extract tarball contents to it.
    mkdir($config_sync_directory, 0777, TRUE);
    $this->copyDirectory($this->getConfigLocation(), $config_sync_directory);

    // Add the module that is providing the database driver to the list of
    // modules that can not be uninstalled in the core.extension configuration.
    if (file_exists($config_sync_directory . '/core.extension.yml')) {
      $core_extension = Yaml::decode(file_get_contents($config_sync_directory . '/core.extension.yml'));
      $module = Database::getConnection()->getProvider();
      if ($module !== 'core') {
        $core_extension['module'][$module] = 0;
        $core_extension['module'] = module_config_sort($core_extension['module']);
      }
      if ($this->profile === FALSE && array_key_exists('profile', $core_extension)) {
        // Remove the profile.
        unset($core_extension['module'][$core_extension['profile']]);
        unset($core_extension['profile']);

        // Set a default theme to the first theme that will be installed as this
        // can not be retrieved from the profile.
        $this->defaultTheme = array_key_first($core_extension['theme']);
      }
      file_put_contents($config_sync_directory . '/core.extension.yml', Yaml::encode($core_extension));
    }
  }

  /**
   * Gets the path to the configuration directory.
   *
   * The directory will be copied to the install profile's config/sync
   * directory for testing.
   *
   * @return string
   *   The path to the configuration directory.
   */
  abstract protected function getConfigLocation();

  /**
   * {@inheritdoc}
   */
  protected function installParameters() {
    $parameters = parent::installParameters();

    // The options that change configuration are disabled when installing from
    // existing configuration.
    unset($parameters['forms']['install_configure_form']['site_name']);
    unset($parameters['forms']['install_configure_form']['site_mail']);
    unset($parameters['forms']['install_configure_form']['enable_update_status_module']);
    unset($parameters['forms']['install_configure_form']['enable_update_status_emails']);

    return $parameters;
  }

  /**
   * Confirms that the installation installed the configuration correctly.
   */
  public function testConfigSync(): void {
    // After installation there is no snapshot and nothing to import.
    $change_list = $this->configImporter()->getStorageComparer()->getChangelist();
    $expected = [
      'create' => [],
      // The system.mail is changed configuration because the test system
      // changes it to ensure that mails are not sent.
      'update' => ['system.mail'],
      'delete' => [],
      'rename' => [],
    ];
    $this->assertEquals($expected, $change_list);
  }

  /**
   * Installer step: Select installation profile.
   */
  protected function setUpProfile() {
    if ($this->existingSyncDirectory) {
      $edit = [
        'profile' => SelectProfileForm::CONFIG_INSTALL_PROFILE_KEY,
      ];
      $this->submitForm($edit, $this->translations['Save and continue']);
    }
    else {
      parent::setUpProfile();
    }
  }

}
+3 −3
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@
 *
 * @group Installer
 */
class InstallerExistingConfigMultilingualTest extends InstallerExistingConfigTestBase {
class InstallerExistingConfigMultilingualTest extends InstallerConfigDirectoryTestBase {

  /**
   * {@inheritdoc}
@@ -21,8 +21,8 @@ class InstallerExistingConfigMultilingualTest extends InstallerExistingConfigTes
  /**
   * {@inheritdoc}
   */
  protected function getConfigTarball() {
    return __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz';
  protected function getConfigLocation() {
    return __DIR__ . '/../../../fixtures/config_install/multilingual';
  }

  /**
+3 −3
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
 *
 * @group Installer
 */
class InstallerExistingConfigNoConfigTest extends InstallerExistingConfigTestBase {
class InstallerExistingConfigNoConfigTest extends InstallerConfigDirectoryTestBase {

  /**
   * {@inheritdoc}
@@ -28,8 +28,8 @@ protected function setUpSite() {
  /**
   * {@inheritdoc}
   */
  protected function getConfigTarball() {
    return __DIR__ . '/../../../fixtures/config_install/testing_config_install_no_config.tar.gz';
  protected function getConfigLocation() {
    return __DIR__ . '/../../../fixtures/config_install/testing_config_install_no_config';
  }

  /**
Loading