|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +namespace Drupal\FunctionalTests\Installer; |
| 6 | + |
| 7 | +use Drupal\Component\Serialization\Yaml; |
| 8 | +use Drupal\Core\Database\Database; |
| 9 | +use Drupal\Core\Installer\Form\SelectProfileForm; |
| 10 | + |
| 11 | +/** |
| 12 | + * Provides a base class for testing installing from existing configuration. |
| 13 | + */ |
| 14 | +abstract class InstallerConfigDirectoryTestBase extends InstallerTestBase { |
| 15 | + |
| 16 | + /** |
| 17 | + * This is set by the profile in the core.extension extracted. |
| 18 | + * |
| 19 | + * If set to FALSE, then the install will proceed without an install profile. |
| 20 | + */ |
| 21 | + protected $profile = NULL; |
| 22 | + |
| 23 | + /** |
| 24 | + * @todo Fill out docblock. |
| 25 | + */ |
| 26 | + protected $existingSyncDirectory = FALSE; |
| 27 | + |
| 28 | + /** |
| 29 | + * This copies a source directory to a destination directory recursively. |
| 30 | + * |
| 31 | + * @param string $source |
| 32 | + * Source directory. |
| 33 | + * @param string $destination |
| 34 | + * Destination directory. |
| 35 | + */ |
| 36 | + protected function copyDirectory(string $source, string $destination): void { |
| 37 | + if (!is_dir($destination)) { |
| 38 | + mkdir($destination, 0755, TRUE); |
| 39 | + } |
| 40 | + $files = scandir($source); |
| 41 | + foreach ($files as $file) { |
| 42 | + if ($file !== '.' && $file !== '..') { |
| 43 | + $sourceFile = $source . '/' . $file; |
| 44 | + $destinationFile = $destination . '/' . $file; |
| 45 | + if (is_dir($sourceFile)) { |
| 46 | + $this->copyDirectory($sourceFile, $destinationFile); |
| 47 | + } |
| 48 | + else { |
| 49 | + copy($sourceFile, $destinationFile); |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + /** |
| 56 | + * {@inheritdoc} |
| 57 | + */ |
| 58 | + protected function prepareEnvironment() { |
| 59 | + parent::prepareEnvironment(); |
| 60 | + |
| 61 | + if ($this->profile === NULL) { |
| 62 | + $core_extension_location = $this->getConfigLocation() . '/core.extension.yml'; |
| 63 | + $core_extension = Yaml::decode(file_get_contents($core_extension_location)); |
| 64 | + $this->profile = $core_extension['profile']; |
| 65 | + } |
| 66 | + |
| 67 | + if ($this->profile !== FALSE) { |
| 68 | + // Create a profile for testing. We set core_version_requirement to '*' for |
| 69 | + // the test so that it does not need to be updated between major versions. |
| 70 | + $info = [ |
| 71 | + 'type' => 'profile', |
| 72 | + 'core_version_requirement' => '*', |
| 73 | + 'name' => 'Configuration installation test profile (' . $this->profile . ')', |
| 74 | + ]; |
| 75 | + |
| 76 | + // File API functions are not available yet. |
| 77 | + $path = $this->siteDirectory . '/profiles/' . $this->profile; |
| 78 | + |
| 79 | + // Put the sync directory inside the profile. |
| 80 | + $config_sync_directory = $path . '/config/sync'; |
| 81 | + |
| 82 | + mkdir($path, 0777, TRUE); |
| 83 | + file_put_contents("$path/{$this->profile}.info.yml", Yaml::encode($info)); |
| 84 | + } |
| 85 | + else { |
| 86 | + // If we have no profile we must use an existing sync directory. |
| 87 | + $this->existingSyncDirectory = TRUE; |
| 88 | + $config_sync_directory = $this->siteDirectory . '/config/sync'; |
| 89 | + } |
| 90 | + |
| 91 | + if ($this->existingSyncDirectory) { |
| 92 | + $config_sync_directory = $this->siteDirectory . '/config/sync'; |
| 93 | + $this->settings['settings']['config_sync_directory'] = (object) [ |
| 94 | + 'value' => $config_sync_directory, |
| 95 | + 'required' => TRUE, |
| 96 | + ]; |
| 97 | + } |
| 98 | + |
| 99 | + // Create config/sync directory and extract tarball contents to it. |
| 100 | + mkdir($config_sync_directory, 0777, TRUE); |
| 101 | + $this->copyDirectory($this->getConfigLocation(), $config_sync_directory); |
| 102 | + |
| 103 | + // Add the module that is providing the database driver to the list of |
| 104 | + // modules that can not be uninstalled in the core.extension configuration. |
| 105 | + if (file_exists($config_sync_directory . '/core.extension.yml')) { |
| 106 | + $core_extension = Yaml::decode(file_get_contents($config_sync_directory . '/core.extension.yml')); |
| 107 | + $module = Database::getConnection()->getProvider(); |
| 108 | + if ($module !== 'core') { |
| 109 | + $core_extension['module'][$module] = 0; |
| 110 | + $core_extension['module'] = module_config_sort($core_extension['module']); |
| 111 | + } |
| 112 | + if ($this->profile === FALSE && array_key_exists('profile', $core_extension)) { |
| 113 | + // Remove the profile. |
| 114 | + unset($core_extension['module'][$core_extension['profile']]); |
| 115 | + unset($core_extension['profile']); |
| 116 | + |
| 117 | + // Set a default theme to the first theme that will be installed as this |
| 118 | + // can not be retrieved from the profile. |
| 119 | + $this->defaultTheme = array_key_first($core_extension['theme']); |
| 120 | + } |
| 121 | + file_put_contents($config_sync_directory . '/core.extension.yml', Yaml::encode($core_extension)); |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + /** |
| 126 | + * Gets the path to the configuration directory. |
| 127 | + * |
| 128 | + * The directory will be copied to the install profile's config/sync |
| 129 | + * directory for testing. |
| 130 | + * |
| 131 | + * @return string |
| 132 | + * The path to the configuration directory. |
| 133 | + */ |
| 134 | + abstract protected function getConfigLocation(); |
| 135 | + |
| 136 | + /** |
| 137 | + * {@inheritdoc} |
| 138 | + */ |
| 139 | + protected function installParameters() { |
| 140 | + $parameters = parent::installParameters(); |
| 141 | + |
| 142 | + // The options that change configuration are disabled when installing from |
| 143 | + // existing configuration. |
| 144 | + unset($parameters['forms']['install_configure_form']['site_name']); |
| 145 | + unset($parameters['forms']['install_configure_form']['site_mail']); |
| 146 | + unset($parameters['forms']['install_configure_form']['enable_update_status_module']); |
| 147 | + unset($parameters['forms']['install_configure_form']['enable_update_status_emails']); |
| 148 | + |
| 149 | + return $parameters; |
| 150 | + } |
| 151 | + |
| 152 | + /** |
| 153 | + * Confirms that the installation installed the configuration correctly. |
| 154 | + */ |
| 155 | + public function testConfigSync(): void { |
| 156 | + // After installation there is no snapshot and nothing to import. |
| 157 | + $change_list = $this->configImporter()->getStorageComparer()->getChangelist(); |
| 158 | + $expected = [ |
| 159 | + 'create' => [], |
| 160 | + // The system.mail is changed configuration because the test system |
| 161 | + // changes it to ensure that mails are not sent. |
| 162 | + 'update' => ['system.mail'], |
| 163 | + 'delete' => [], |
| 164 | + 'rename' => [], |
| 165 | + ]; |
| 166 | + $this->assertEquals($expected, $change_list); |
| 167 | + } |
| 168 | + |
| 169 | + /** |
| 170 | + * Installer step: Select installation profile. |
| 171 | + */ |
| 172 | + protected function setUpProfile() { |
| 173 | + if ($this->existingSyncDirectory) { |
| 174 | + $edit = [ |
| 175 | + 'profile' => SelectProfileForm::CONFIG_INSTALL_PROFILE_KEY, |
| 176 | + ]; |
| 177 | + $this->submitForm($edit, $this->translations['Save and continue']); |
| 178 | + } |
| 179 | + else { |
| 180 | + parent::setUpProfile(); |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | +} |
0 commit comments