Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Config\InstallStorage;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\KernelTests\AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* Provides a class for install profiles to check their installed config.
|
||||
*/
|
||||
abstract class ConfigAfterInstallerTestBase extends InstallerTestBase {
|
||||
|
||||
use AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* Ensures that all the installed config looks like the exported one.
|
||||
*
|
||||
* @param array $skipped_config
|
||||
* An array of skipped config.
|
||||
*/
|
||||
protected function assertInstalledConfig(array $skipped_config) {
|
||||
$this->addToAssertionCount(1);
|
||||
/** @var \Drupal\Core\Config\StorageInterface $active_config_storage */
|
||||
$active_config_storage = $this->container->get('config.storage');
|
||||
/** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
|
||||
$config_manager = $this->container->get('config.manager');
|
||||
|
||||
$default_install_path = 'core/profiles/' . $this->profile . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
|
||||
$profile_config_storage = new FileStorage($default_install_path, StorageInterface::DEFAULT_COLLECTION);
|
||||
|
||||
foreach ($profile_config_storage->listAll() as $config_name) {
|
||||
$result = $config_manager->diff($profile_config_storage, $active_config_storage, $config_name);
|
||||
try {
|
||||
$this->assertConfigDiff($result, $config_name, $skipped_config);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support with existing settings.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class DistributionProfileExistingSettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Use the kernel to find the site path because the site.path service should
|
||||
// not be available at this point in the install process.
|
||||
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => $site_path . '/files/config_staging',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Make settings file not writable.
|
||||
$filename = $this->siteDirectory . '/settings.php';
|
||||
// Make the settings file read-only.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod($filename, 0444);
|
||||
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Confirm that Drupal recognizes this distribution as the current profile.
|
||||
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
|
||||
$this->assertArrayNotHasKey('install_profile', Settings::getAll(), 'The install profile has not been written to settings.php.');
|
||||
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
|
||||
|
||||
$this->rebuildContainer();
|
||||
$this->pass('Container can be rebuilt even though distribution is not written to settings.php.');
|
||||
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class DistributionProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
'finish_url' => '/myrootuser',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
file_put_contents("$path/mydistro.install", "<?php function mydistro_install() {\Drupal::service('path.alias_storage')->save('/user/1', '/myrootuser');}");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the distribution name is used in the site title.
|
||||
$this->assertTitle('Choose language | ' . $this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('myrootuser');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Confirm that Drupal recognizes this distribution as the current profile.
|
||||
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
|
||||
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support with a 'langcode' query string.
|
||||
*
|
||||
* @group Installer
|
||||
*
|
||||
* @see \Drupal\FunctionalTests\Installer\DistributionProfileTranslationTest
|
||||
*/
|
||||
class DistributionProfileTranslationQueryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'langcode' => $this->langcode,
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->root . DIRECTORY_SEPARATOR . $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir($this->root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.fr.po', $this->getPo('fr'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Pass a different language code than the one set in the distribution
|
||||
// profile. This distribution language should still be used.
|
||||
// The unrouted URL assembler does not exist at this point, so we build the
|
||||
// URL ourselves.
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=fr');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because the distribution profile uses a fixed
|
||||
// language.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// The language should have been automatically detected, all following
|
||||
// screens should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual(current($elements)->getText(), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = $this->getSession()->getPage()->find('xpath', '/@dir')->getText();
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getDisplayName());
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*
|
||||
* @see \Drupal\FunctionalTests\Installer\DistributionProfileTest
|
||||
*/
|
||||
class DistributionProfileTranslationTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'langcode' => $this->langcode,
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->root . DIRECTORY_SEPARATOR . $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir($this->root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because the distribution profile uses a fixed
|
||||
// language.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// The language should have been automatically detected, all following
|
||||
// screens should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual(current($elements)->getText(), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = current($this->xpath('/@dir'))->getText();
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getDisplayName());
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that an install profile with only dependencies works as expected.
|
||||
*
|
||||
* @group Installer
|
||||
* @group legacy
|
||||
*/
|
||||
class InstallProfileDependenciesBcTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_install_profile_dependencies_bc';
|
||||
|
||||
/**
|
||||
* Tests that the install profile BC layer for dependencies key works.
|
||||
*
|
||||
* @expectedDeprecation The install profile core/profiles/testing_install_profile_dependencies_bc/testing_install_profile_dependencies_bc.info.yml only implements a 'dependencies' key. As of Drupal 8.6.0 profile's support a new 'install' key for modules that should be installed but not depended on. See https://www.drupal.org/node/2952947.
|
||||
*/
|
||||
public function testUninstallingModules() {
|
||||
$user = $this->drupalCreateUser(['administer modules']);
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet('admin/modules/uninstall');
|
||||
$this->getSession()->getPage()->checkField('uninstall[ban]');
|
||||
$this->getSession()->getPage()->checkField('uninstall[dblog]');
|
||||
$this->click('#edit-submit');
|
||||
// Click the confirm button.
|
||||
$this->click('#edit-submit');
|
||||
$this->assertSession()->responseContains('The selected modules have been uninstalled.');
|
||||
$this->assertSession()->responseContains('No modules are available to uninstall.');
|
||||
// We've uninstalled modules therefore we need to rebuild the container in
|
||||
// the test runner.
|
||||
$this->rebuildContainer();
|
||||
$module_handler = $this->container->get('module_handler');
|
||||
$this->assertFalse($module_handler->moduleExists('ban'));
|
||||
$this->assertFalse($module_handler->moduleExists('dblog'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Extension\ModuleUninstallValidatorException;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that an install profile can require modules.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallProfileDependenciesTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_install_profile_dependencies';
|
||||
|
||||
/**
|
||||
* Tests that an install profile can require modules.
|
||||
*/
|
||||
public function testUninstallingModules() {
|
||||
$user = $this->drupalCreateUser(['administer modules']);
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet('admin/modules/uninstall');
|
||||
$this->assertSession()->fieldDisabled('uninstall[dblog]');
|
||||
$this->getSession()->getPage()->checkField('uninstall[ban]');
|
||||
$this->click('#edit-submit');
|
||||
// Click the confirm button.
|
||||
$this->click('#edit-submit');
|
||||
$this->assertSession()->responseContains('The selected modules have been uninstalled.');
|
||||
// We've uninstalled a module therefore we need to rebuild the container in
|
||||
// the test runner.
|
||||
$this->rebuildContainer();
|
||||
$this->assertFalse($this->container->get('module_handler')->moduleExists('ban'));
|
||||
try {
|
||||
$this->container->get('module_installer')->uninstall(['dblog']);
|
||||
$this->fail('Uninstalled dblog module.');
|
||||
}
|
||||
catch (ModuleUninstallValidatorException $e) {
|
||||
$this->assertContains('The Testing install profile dependencies module is required', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
|
||||
/**
|
||||
* Tests the installer when a config_directory set up but does not exist.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerConfigDirectorySetNoDirectoryErrorTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The directory where the sync directory should be created during install.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $configDirectory;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->configDirectory = $this->publicFilesDirectory . '/config_' . Crypt::randomBytesBase64();
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $this->configDirectory . '/sync',
|
||||
'required' => TRUE,
|
||||
];
|
||||
// Create the files directory early so we can test the error case.
|
||||
mkdir($this->publicFilesDirectory);
|
||||
// Create a file so the directory can not be created.
|
||||
file_put_contents($this->configDirectory, 'Test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Configure settings.
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear as we had a failure prior to the settings
|
||||
// screen.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// This step should not appear as we had a failure prior to the settings
|
||||
// screen.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation failed.
|
||||
*/
|
||||
public function testError() {
|
||||
$this->assertText("An automated attempt to create the directory {$this->configDirectory}/sync failed, possibly due to a permissions problem.");
|
||||
$this->assertFalse(file_exists($this->configDirectory . '/sync') && is_dir($this->configDirectory . '/sync'), "The directory {$this->configDirectory}/sync does not exist.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
|
||||
/**
|
||||
* Tests the installer when a config_directory set up but does not exist.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerConfigDirectorySetNoDirectoryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The sync directory created during the install.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $syncDirectory;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->syncDirectory = $this->publicFilesDirectory . '/config_' . Crypt::randomBytesBase64() . '/sync';
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $this->syncDirectory,
|
||||
'required' => TRUE,
|
||||
];
|
||||
// Other directories will be created too.
|
||||
$this->settings['config_directories']['custom'] = (object) [
|
||||
'value' => $this->publicFilesDirectory . '/config_custom',
|
||||
'required' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertTrue(file_exists($this->syncDirectory) && is_dir($this->syncDirectory), "The directory {$this->syncDirectory} exists.");
|
||||
$this->assertTrue(file_exists($this->publicFilesDirectory . '/config_custom') && is_dir($this->publicFilesDirectory . '/config_custom'), "The directory {$this->publicFilesDirectory}/custom_config exists.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Tests the installer with database errors.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerDatabaseErrorMessagesTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// We are creating a table here to force an error in the installer because
|
||||
// it will try and create the drupal_install_test table as this is part of
|
||||
// the standard database tests performed by the installer in
|
||||
// Drupal\Core\Database\Install\Tasks.
|
||||
Database::getConnection('default')->query('CREATE TABLE {drupal_install_test} (id int NULL)');
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// This step should not appear as we had a failure on the settings screen.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the error message in the settings step is correct.
|
||||
*/
|
||||
public function testSetUpSettingsErrorMessage() {
|
||||
$this->assertRaw('<ul><li>Failed to <strong>CREATE</strong> a test table');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests the installer with empty settings file.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerEmptySettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// Create an empty settings.php file.
|
||||
$path = $this->root . DIRECTORY_SEPARATOR . $this->siteDirectory;
|
||||
file_put_contents($path . '/settings.php', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests the installer when a config_directory has already been set up.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigDirectoryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The expected file perms of the folder.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expectedFilePerms;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
mkdir($this->root . DIRECTORY_SEPARATOR . $this->siteDirectory . '/config_read_only', 0444);
|
||||
$this->expectedFilePerms = fileperms($this->siteDirectory . '/config_read_only');
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $this->siteDirectory . '/config_read_only',
|
||||
'required' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual($this->expectedFilePerms, fileperms($this->siteDirectory . '/config_read_only'));
|
||||
$this->assertEqual([], glob($this->siteDirectory . '/config_read_only/*'), 'The sync directory is empty after install because it is read-only.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that installing from existing configuration works.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigMultilingualTest extends InstallerExistingConfigTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_config_install_multilingual';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that profiles invalid config can not be installed.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigNoConfigTest extends InstallerExistingConfigTestBase {
|
||||
|
||||
protected $profile = 'no_config_profile';
|
||||
|
||||
/**
|
||||
* Final installer step: Configure site.
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// There are errors therefore there is nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/testing_config_install_no_config.tar.gz';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that profiles with an empty config/sync directory do not work.
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
$this->assertTitle('Configuration validation | Drupal');
|
||||
$this->assertText('The configuration synchronization failed validation.');
|
||||
$this->assertText('This import is empty and if applied would delete all of your configuration, so has been rejected.');
|
||||
|
||||
// Ensure there is no continuation button.
|
||||
$this->assertNoText('Save and continue');
|
||||
$this->assertNoFieldById('edit-submit');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Testing installing from config without system.site.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigNoSystemSiteTest extends InstallerExistingConfigTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// File API functions are not available yet.
|
||||
unlink($this->siteDirectory . '/profiles/' . $this->profile . '/config/sync/system.site.yml');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUpSite() {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that profiles with no system.site do not work.
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
$this->htmlOutput(NULL);
|
||||
$this->assertTitle('Configuration validation | Drupal');
|
||||
$this->assertText('The configuration synchronization failed validation.');
|
||||
$this->assertText('This import does not contain system.site configuration, so has been rejected.');
|
||||
|
||||
// Ensure there is no continuation button.
|
||||
$this->assertNoText('Save and continue');
|
||||
$this->assertNoFieldById('edit-submit');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/testing_config_install.tar.gz';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that profiles with hook_install() can't be installed from config.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigProfileHookInstall extends InstallerExistingConfigTestBase {
|
||||
|
||||
protected $profile = 'config_profile_with_hook_install';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Create an .install file with a hook_install() implementation.
|
||||
$path = $this->siteDirectory . '/profiles/' . $this->profile;
|
||||
$contents = <<<EOF
|
||||
<?php
|
||||
|
||||
function config_profile_with_hook_install_install() {
|
||||
}
|
||||
EOF;
|
||||
file_put_contents("$path/{$this->profile}.install", $contents);
|
||||
parent::visitInstaller();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Configure settings.
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// There are errors therefore there is nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final installer step: Configure site.
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// There are errors therefore there is nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
// We're not going to get to the config import stage so this does not
|
||||
// matter.
|
||||
return __DIR__ . '/../../../fixtures/config_install/testing_config_install_no_config.tar.gz';
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms the installation has failed and the expected error is displayed.
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
$this->assertTitle('Requirements problem | Drupal');
|
||||
$this->assertText($this->profile);
|
||||
$this->assertText('The selected profile has a hook_install() implementation and therefore can not be installed from configuration.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that installing from existing configuration works.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigSyncDirectoryMultilingualTest extends InstallerExistingConfigTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_config_install_multilingual';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $existingSyncDirectory = TRUE;
|
||||
|
||||
/**
|
||||
* Installer step: Select installation profile.
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// Ensure the site name 'Multilingual' appears as expected in the 'Use
|
||||
// existing configuration' radio description.
|
||||
$this->assertSession()->pageTextContains('Install Multilingual using existing configuration.');
|
||||
return parent::setUpProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz';
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation installed the configuration correctly.
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
parent::testConfigSync();
|
||||
// Ensure that menu blocks have been created correctly.
|
||||
$this->assertSession()->responseNotContains('This block is broken or missing.');
|
||||
$this->assertSession()->linkExists('Add content');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that profiles with hook_install() can't be installed from config.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigSyncDirectoryProfileHookInstall extends InstallerExistingConfigTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_config_install_multilingual';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $existingSyncDirectory = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Create an .install file with a hook_install() implementation.
|
||||
$path = $this->siteDirectory . '/profiles/' . $this->profile;
|
||||
$contents = <<<EOF
|
||||
<?php
|
||||
|
||||
function testing_config_install_multilingual_install() {
|
||||
}
|
||||
EOF;
|
||||
file_put_contents("$path/{$this->profile}.install", $contents);
|
||||
parent::visitInstaller();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select installation profile.
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This is the form we are testing so wait until the test method to do
|
||||
// assertions.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Requirements problem.
|
||||
*/
|
||||
protected function setUpRequirementsProblem() {
|
||||
// This form will never be reached.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Configure settings.
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This form will never be reached.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final installer step: Configure site.
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// This form will never be reached.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests installing from config is not available due to hook_INSTALL().
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
$this->assertSession()->titleEquals('Select an installation profile | Drupal');
|
||||
$this->assertSession()->responseNotContains('Use existing configuration');
|
||||
|
||||
// Remove the install hook and the option to install from existing
|
||||
// configuration will be available.
|
||||
unlink("{$this->siteDirectory}/profiles/{$this->profile}/{$this->profile}.install");
|
||||
$this->getSession()->reload();
|
||||
$this->assertSession()->titleEquals('Select an installation profile | Drupal');
|
||||
$this->assertSession()->responseContains('Use existing configuration');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that installing from existing configuration works.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigSyncDriectoryProfileMismatchTest extends InstallerExistingConfigTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_config_install_multilingual';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $existingSyncDirectory = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/multilingual.tar.gz';
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Configure settings.
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// Cause a profile mismatch by hacking the URL.
|
||||
$this->drupalGet(str_replace($this->profile, 'minimal', $this->getUrl()));
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
protected function setUpSite() {
|
||||
// This step will not occur because there is an error.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that profile mismatch fails to install.
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
$this->htmlOutput(NULL);
|
||||
$this->assertTitle('Configuration validation | Drupal');
|
||||
$this->assertText('The configuration synchronization failed validation.');
|
||||
$this->assertText('The selected installation profile minimal does not match the profile stored in configuration testing_config_install_multilingual.');
|
||||
|
||||
// Ensure there is no continuation button.
|
||||
$this->assertNoText('Save and continue');
|
||||
$this->assertNoFieldById('edit-submit');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that installing from existing configuration works.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigTest extends InstallerExistingConfigTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUpSite() {
|
||||
// The configuration is from a site installed in French.
|
||||
// So after selecting the profile the installer detects that the site must
|
||||
// be installed in French, thus we change the button translation.
|
||||
$this->translations['Save and continue'] = 'Enregistrer et continuer';
|
||||
parent::setUpSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConfigTarball() {
|
||||
return __DIR__ . '/../../../fixtures/config_install/testing_config_install.tar.gz';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Core\Archiver\ArchiveTar;
|
||||
use Drupal\Core\Installer\Form\SelectProfileForm;
|
||||
|
||||
/**
|
||||
* Provides a base class for testing installing from existing configuration.
|
||||
*/
|
||||
abstract class InstallerExistingConfigTestBase extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* This is set by the profile in the core.extension extracted.
|
||||
*/
|
||||
protected $profile = NULL;
|
||||
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
protected $existingSyncDirectory = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$archiver = new ArchiveTar($this->getConfigTarball(), 'gz');
|
||||
|
||||
if ($this->profile === NULL) {
|
||||
$core_extension = Yaml::decode($archiver->extractInString('core.extension.yml'));
|
||||
$this->profile = $core_extension['profile'];
|
||||
}
|
||||
|
||||
// Create a profile for testing.
|
||||
$info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Configuration installation test profile (' . $this->profile . ')',
|
||||
];
|
||||
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/' . $this->profile;
|
||||
if ($this->existingSyncDirectory) {
|
||||
$config_sync_directory = $this->siteDirectory . '/config/sync';
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $config_sync_directory,
|
||||
'required' => TRUE,
|
||||
];
|
||||
}
|
||||
else {
|
||||
// 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));
|
||||
|
||||
// Create config/sync directory and extract tarball contents to it.
|
||||
mkdir($config_sync_directory, 0777, TRUE);
|
||||
$files = [];
|
||||
$list = $archiver->listContent();
|
||||
if (is_array($list)) {
|
||||
/** @var array $list */
|
||||
foreach ($list as $file) {
|
||||
$files[] = $file['filename'];
|
||||
}
|
||||
$archiver->extractList($files, $config_sync_directory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filepath to the configuration tarball.
|
||||
*
|
||||
* The tarball will be extracted to the install profile's config/sync
|
||||
* directory for testing.
|
||||
*
|
||||
* @return string
|
||||
* The filepath to the configuration tarball.
|
||||
*/
|
||||
abstract protected function getConfigTarball();
|
||||
|
||||
/**
|
||||
* {@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']['update_status_module']);
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation installed the configuration correctly.
|
||||
*/
|
||||
public function testConfigSync() {
|
||||
// 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->assertEqual($expected, $change_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select installation profile.
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
if ($this->existingSyncDirectory) {
|
||||
$edit = [
|
||||
'profile' => SelectProfileForm::CONFIG_INSTALL_PROFILE_KEY,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
else {
|
||||
parent::setUpProfile();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file with database connection
|
||||
* info.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingDatabaseSettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// Pre-configure database credentials in settings.php.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo The database settings form is not supposed to appear if settings.php
|
||||
* contains a valid database connection already (but e.g. no config
|
||||
* directories yet).
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// All database settings should be pre-configured, except password.
|
||||
$values = $this->parameters['forms']['install_settings_form'];
|
||||
$driver = $values['driver'];
|
||||
$edit = [];
|
||||
if (isset($values[$driver]['password']) && $values[$driver]['password'] !== '') {
|
||||
$edit = $this->translatePostValues([
|
||||
$driver => [
|
||||
'password' => $values[$driver]['password'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing Drupal installation.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingInstallationTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Verifies that Drupal can't be reinstalled while an existing installation is
|
||||
* available.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
// Verify that Drupal can't be immediately reinstalled.
|
||||
$this->visitInstaller();
|
||||
$this->assertRaw('Drupal already installed');
|
||||
|
||||
// Delete settings.php and attempt to reinstall again.
|
||||
unlink($this->siteDirectory . '/settings.php');
|
||||
$this->visitInstaller();
|
||||
$this->setUpLanguage();
|
||||
$this->setUpProfile();
|
||||
$this->setUpRequirementsProblem();
|
||||
$this->setUpSettings();
|
||||
$this->assertRaw('Drupal already installed');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests install with existing settings.php and a mismatching install profile.
|
||||
*
|
||||
* @group Installer
|
||||
* @group legacy
|
||||
*/
|
||||
class InstallerExistingSettingsMismatchProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Configures a preexisting settings.php file without an install_profile
|
||||
* setting before invoking the interactive installer.
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// During interactive install we'll change this to a different profile and
|
||||
// this test will ensure that the new value is written to settings.php.
|
||||
$this->settings['settings']['install_profile'] = (object) [
|
||||
'value' => 'minimal',
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => DrupalKernel::findSitePath(Request::createFromGlobals()) . '/files/config_sync',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Provide profile and language in query string to skip these pages.
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because there is a langcode as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a profile as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*
|
||||
* @expectedDeprecation To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual('testing', \Drupal::installProfile());
|
||||
$this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file but no install profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingSettingsNoProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Configures a preexisting settings.php file without an install_profile
|
||||
* setting before invoking the interactive installer.
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => DrupalKernel::findSitePath(Request::createFromGlobals()) . '/files/config_sync',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual('testing', \Drupal::installProfile());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests installer breaks with a profile mismatch and a read-only settings.php.
|
||||
*
|
||||
* @group Installer
|
||||
* @group legacy
|
||||
*/
|
||||
class InstallerExistingSettingsReadOnlyMismatchProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Configures a preexisting settings.php file without an install_profile
|
||||
* setting before invoking the interactive installer.
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// During interactive install we'll change this to a different profile and
|
||||
// this test will ensure that the new value is written to settings.php.
|
||||
$this->settings['settings']['install_profile'] = (object) [
|
||||
'value' => 'minimal',
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure config directories.
|
||||
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => $site_path . '/files/config_staging',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Make settings file not writable. This will break the installer.
|
||||
$filename = $this->siteDirectory . '/settings.php';
|
||||
// Make the settings file read-only.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod($filename, 0444);
|
||||
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because there is a lagcode as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a profile as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*
|
||||
* @expectedDeprecation To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->initBrowserOutputFile();
|
||||
$this->htmlOutput(NULL);
|
||||
$this->assertEquals('testing', \Drupal::installProfile());
|
||||
$this->assertEquals('minimal', Settings::get('install_profile'));
|
||||
$this->drupalGet('admin/reports/status');
|
||||
$this->assertSession()->pageTextContains("Drupal 8 no longer uses the \$settings['install_profile'] value in settings.php and it can be removed.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingSettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Fully configures a preexisting settings.php file before invoking the
|
||||
* interactive installer.
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Use the kernel to find the site path because the site.path service should
|
||||
// not be available at this point in the install process.
|
||||
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => $site_path . '/files/config_sync',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual('testing', \Drupal::installProfile());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that the early installer uses the correct language direction.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerLanguageDirectionTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Overrides the language code the installer should use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'ar';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir($this->root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.ar.po', "msgid \"\"\nmsgstr \"\"\nmsgid \"Save and continue\"\nmsgstr \"Save and continue Arabic\"");
|
||||
|
||||
parent::setUpLanguage();
|
||||
// After selecting a different language than English, all following screens
|
||||
// should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual(current($elements)->getText(), 'Save and continue Arabic');
|
||||
$this->translations['Save and continue'] = 'Save and continue Arabic';
|
||||
|
||||
// Verify that language direction is right-to-left.
|
||||
$direction = current($this->xpath('/@dir'))->getText();
|
||||
$this->assertEqual($direction, 'rtl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Language\LanguageManager;
|
||||
|
||||
/**
|
||||
* Verifies that the installer language list combines local and remote languages.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerLanguagePageTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Installer step: Select language.
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir($this->root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
touch($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.xoxo.po');
|
||||
|
||||
// Check that all predefined languages show up with their native names.
|
||||
$this->visitInstaller();
|
||||
foreach (LanguageManager::getStandardLanguageList() as $langcode => $names) {
|
||||
$this->assertOption('edit-langcode', $langcode);
|
||||
$this->assertRaw('>' . $names[1] . '<');
|
||||
}
|
||||
|
||||
// Check that our custom one shows up with the file name indicated language.
|
||||
$this->assertOption('edit-langcode', 'xoxo');
|
||||
$this->assertRaw('>xoxo<');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests that an install profile can implement hook_requirements().
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerProfileRequirementsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'testing_requirements';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This form will never be reached.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// This form will never be reached.
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the profile failed hook_requirements().
|
||||
*/
|
||||
public function testHookRequirementsFailure() {
|
||||
$this->assertSession()->pageTextContains('Testing requirements failed requirements.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Verifies that the installer skipped permission hardening.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerSkipPermissionHardeningTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$this->settings['settings']['skip_permissions_hardening'] = (object) ['value' => TRUE, 'required' => TRUE];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
$site_directory = $this->container->get('app.root') . '/' . $this->siteDirectory;
|
||||
$this->assertTrue(is_writable($site_directory));
|
||||
$this->assertTrue(is_writable($site_directory . '/settings.php'));
|
||||
|
||||
$this->assertSession()->responseContains('All necessary changes to <em class="placeholder">' . $this->siteDirectory . '</em> and <em class="placeholder">' . $this->siteDirectory . '/settings.php</em> have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href="https://www.drupal.org/server-permissions">online handbook</a>.');
|
||||
|
||||
parent::setUpSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected behaviors of the installation result.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertSession()->addressEquals('user/1');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests the interactive installer.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Ensures that the user page is available after installation.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Verify that the confirmation message appears.
|
||||
require_once $this->root . '/core/includes/install.inc';
|
||||
$this->assertRaw(t('Congratulations, you installed @drupal!', [
|
||||
'@drupal' => drupal_install_profile_distribution_name(),
|
||||
]));
|
||||
|
||||
// Ensure that the timezone is correct for sites under test after installing
|
||||
// interactively.
|
||||
$this->assertEqual($this->config('system.date')->get('timezone.default'), 'Australia/Sydney');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select language.
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Test that \Drupal\Core\Render\BareHtmlPageRenderer adds assets and
|
||||
// metatags as expected to the first page of the installer.
|
||||
$this->assertRaw("core/themes/seven/css/components/buttons.css");
|
||||
$this->assertRaw('<meta charset="utf-8" />');
|
||||
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Choose language', $this->cssSelect('main h2')[0]->getText());
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Select an installation profile', $this->cssSelect('main h2')[0]->getText());
|
||||
$result = $this->xpath('//span[contains(@class, :class) and contains(text(), :text)]', [':class' => 'visually-hidden', ':text' => 'Select an installation profile']);
|
||||
$this->assertEqual(count($result), 1, "Title/Label not displayed when '#title_display' => 'invisible' attribute is set");
|
||||
|
||||
parent::setUpProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Database configuration', $this->cssSelect('main h2')[0]->getText());
|
||||
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Configure site', $this->cssSelect('main h2')[0]->getText());
|
||||
|
||||
// Test that SiteConfigureForm::buildForm() has made the site directory and
|
||||
// the settings file non-writable.
|
||||
$site_directory = $this->container->get('app.root') . '/' . $this->siteDirectory;
|
||||
$this->assertFalse(is_writable($site_directory));
|
||||
$this->assertFalse(is_writable($site_directory . '/settings.php'));
|
||||
|
||||
parent::setUpSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
parent::visitInstaller();
|
||||
|
||||
// Assert the title is correct and has the title suffix.
|
||||
$this->assertTitle('Choose language | Drupal');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Session\UserSession;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Base class for testing the interactive installer.
|
||||
*/
|
||||
abstract class InstallerTestBase extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Custom settings.php values to write for a test run.
|
||||
*
|
||||
* @var array
|
||||
* An array of settings to write out, in the format expected by
|
||||
* drupal_rewrite_settings().
|
||||
*/
|
||||
protected $settings = [];
|
||||
|
||||
/**
|
||||
* The language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'en';
|
||||
|
||||
/**
|
||||
* The installation profile to install.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing';
|
||||
|
||||
/**
|
||||
* Additional parameters to use for installer screens.
|
||||
*
|
||||
* @see FunctionalTestSetupTrait::installParameters()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* A string translation map used for translated installer screens.
|
||||
*
|
||||
* Keys are English strings, values are translated strings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $translations = [
|
||||
'Save and continue' => 'Save and continue',
|
||||
];
|
||||
|
||||
/**
|
||||
* Whether the installer has completed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInstalled = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->isInstalled = FALSE;
|
||||
|
||||
$this->setupBaseUrl();
|
||||
|
||||
$this->prepareDatabasePrefix();
|
||||
|
||||
// Install Drupal test site.
|
||||
$this->prepareEnvironment();
|
||||
|
||||
// Define information about the user 1 account.
|
||||
$this->rootUser = new UserSession([
|
||||
'uid' => 1,
|
||||
'name' => 'admin',
|
||||
'mail' => 'admin@example.com',
|
||||
'pass_raw' => $this->randomMachineName(),
|
||||
]);
|
||||
|
||||
// If any $settings are defined for this test, copy and prepare an actual
|
||||
// settings.php, so as to resemble a regular installation.
|
||||
if (!empty($this->settings)) {
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
copy(DRUPAL_ROOT . '/sites/default/default.settings.php', DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php');
|
||||
$this->writeSettings($this->settings);
|
||||
}
|
||||
|
||||
// Note that FunctionalTestSetupTrait::installParameters() returns form
|
||||
// input values suitable for a programmed
|
||||
// \Drupal::formBuilder()->submitForm().
|
||||
// @see InstallerTestBase::translatePostValues()
|
||||
$this->parameters = $this->installParameters();
|
||||
|
||||
// Set up a minimal container (required by BrowserTestBase). Set cookie and
|
||||
// server information so that XDebug works.
|
||||
// @see install_begin_request()
|
||||
$request = Request::create($GLOBALS['base_url'] . '/core/install.php', 'GET', [], $_COOKIE, [], $_SERVER);
|
||||
$this->container = new ContainerBuilder();
|
||||
$request_stack = new RequestStack();
|
||||
$request_stack->push($request);
|
||||
$this->container
|
||||
->set('request_stack', $request_stack);
|
||||
$this->container
|
||||
->setParameter('language.default_values', Language::$defaultValues);
|
||||
$this->container
|
||||
->register('language.default', 'Drupal\Core\Language\LanguageDefault')
|
||||
->addArgument('%language.default_values%');
|
||||
$this->container
|
||||
->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
|
||||
->addArgument(new Reference('language.default'));
|
||||
$this->container
|
||||
->register('http_client', 'GuzzleHttp\Client')
|
||||
->setFactory('http_client_factory:fromOptions');
|
||||
$this->container
|
||||
->register('http_client_factory', 'Drupal\Core\Http\ClientFactory')
|
||||
->setArguments([new Reference('http_handler_stack')]);
|
||||
$handler_stack = HandlerStack::create();
|
||||
$test_http_client_middleware = new TestHttpClientMiddleware();
|
||||
$handler_stack->push($test_http_client_middleware(), 'test.http_client.middleware');
|
||||
$this->container
|
||||
->set('http_handler_stack', $handler_stack);
|
||||
|
||||
$this->container
|
||||
->set('app.root', DRUPAL_ROOT);
|
||||
\Drupal::setContainer($this->container);
|
||||
|
||||
// Setup Mink.
|
||||
$this->initMink();
|
||||
|
||||
// Set up the browser test output file.
|
||||
$this->initBrowserOutputFile();
|
||||
|
||||
$this->visitInstaller();
|
||||
|
||||
// Select language.
|
||||
$this->setUpLanguage();
|
||||
|
||||
// Select profile.
|
||||
$this->setUpProfile();
|
||||
|
||||
// Address the requirements problem screen, if any.
|
||||
$this->setUpRequirementsProblem();
|
||||
|
||||
// Configure settings.
|
||||
$this->setUpSettings();
|
||||
|
||||
// @todo Allow test classes based on this class to act on further installer
|
||||
// screens.
|
||||
|
||||
// Configure site.
|
||||
$this->setUpSite();
|
||||
|
||||
if ($this->isInstalled) {
|
||||
// Import new settings.php written by the installer.
|
||||
$request = Request::createFromGlobals();
|
||||
$class_loader = require $this->container->get('app.root') . '/autoload.php';
|
||||
Settings::initialize($this->container->get('app.root'), DrupalKernel::findSitePath($request), $class_loader);
|
||||
foreach ($GLOBALS['config_directories'] as $type => $path) {
|
||||
$this->configDirectories[$type] = $path;
|
||||
}
|
||||
|
||||
// After writing settings.php, the installer removes write permissions
|
||||
// from the site directory. To allow drupal_generate_test_ua() to write
|
||||
// a file containing the private key for drupal_valid_test_ua(), the site
|
||||
// directory has to be writable.
|
||||
// BrowserTestBase::tearDown() will delete the entire test site directory.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod($this->container->get('app.root') . '/' . $this->siteDirectory, 0777);
|
||||
$this->kernel = DrupalKernel::createFromRequest($request, $class_loader, 'prod', FALSE);
|
||||
$this->kernel->prepareLegacyRequest($request);
|
||||
$this->container = $this->kernel->getContainer();
|
||||
|
||||
// Manually configure the test mail collector implementation to prevent
|
||||
// tests from sending out emails and collect them in state instead.
|
||||
$this->container->get('config.factory')
|
||||
->getEditable('system.mail')
|
||||
->set('interface.default', 'test_mail_collector')
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initFrontPage() {
|
||||
// We don't want to visit the front page with the installer when
|
||||
// initializing Mink, so we do nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the interactive installer.
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select language.
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
$edit = [
|
||||
'langcode' => $this->langcode,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select installation profile.
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
$edit = [
|
||||
'profile' => $this->profile,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Configure settings.
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
$edit = $this->translatePostValues($this->parameters['forms']['install_settings_form']);
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Requirements problem.
|
||||
*
|
||||
* Override this method to test specific requirements warnings or errors
|
||||
* during the installer.
|
||||
*
|
||||
* @see system_requirements()
|
||||
*/
|
||||
protected function setUpRequirementsProblem() {
|
||||
// By default, skip the "recommended PHP version" warning on older test
|
||||
// environments. This allows the installer to be tested consistently on
|
||||
// both recommended PHP versions and older (but still supported) versions.
|
||||
if (version_compare(phpversion(), '7.0') < 0) {
|
||||
$this->continueOnExpectedWarnings(['PHP']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Final installer step: Configure site.
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
$edit = $this->translatePostValues($this->parameters['forms']['install_configure_form']);
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
// If we've got to this point the site is installed using the regular
|
||||
// installation workflow.
|
||||
$this->isInstalled = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* FunctionalTestSetupTrait::refreshVariables() tries to operate on persistent
|
||||
* storage, which is only available after the installer completed.
|
||||
*/
|
||||
protected function refreshVariables() {
|
||||
if ($this->isInstalled) {
|
||||
parent::refreshVariables();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues installation when an expected warning is found.
|
||||
*
|
||||
* @param string[] $expected_warnings
|
||||
* A list of warning summaries to expect on the requirements screen (e.g.
|
||||
* 'PHP', 'PHP OPcode caching', etc.). If only the expected warnings
|
||||
* are found, the test will click the "continue anyway" link to go to the
|
||||
* next screen of the installer. If an expected warning is not found, or if
|
||||
* a warning not in the list is present, a fail is raised.
|
||||
*/
|
||||
protected function continueOnExpectedWarnings($expected_warnings = []) {
|
||||
// Don't try to continue if there are errors.
|
||||
if (strpos($this->getTextContent(), 'Errors found') !== FALSE) {
|
||||
return;
|
||||
}
|
||||
// Allow only details elements that are directly after the warning header
|
||||
// or each other. There is no guaranteed wrapper we can rely on across
|
||||
// distributions. When there are multiple warnings, the selectors will be:
|
||||
// - h3#warning+details summary
|
||||
// - h3#warning+details+details summary
|
||||
// - etc.
|
||||
// We add one more selector than expected warnings to confirm that there
|
||||
// isn't any other warning before clicking the link.
|
||||
// @todo Make this more reliable in
|
||||
// https://www.drupal.org/project/drupal/issues/2927345.
|
||||
$selectors = [];
|
||||
for ($i = 0; $i <= count($expected_warnings); $i++) {
|
||||
$selectors[] = 'h3#warning' . implode('', array_fill(0, $i + 1, '+details')) . ' summary';
|
||||
}
|
||||
$warning_elements = $this->cssSelect(implode(', ', $selectors));
|
||||
|
||||
// Confirm that there are only the expected warnings.
|
||||
$warnings = [];
|
||||
foreach ($warning_elements as $warning) {
|
||||
$warnings[] = trim($warning->getText());
|
||||
}
|
||||
$this->assertEquals($expected_warnings, $warnings);
|
||||
$this->clickLink('continue anyway');
|
||||
$this->checkForMetaRefresh();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests translation files for multiple languages get imported during install.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationMultipleLanguageForeignTest extends InstallerTranslationMultipleLanguageTest {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
parent::setUpLanguage();
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests that keeping English in a foreign language install works.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationMultipleLanguageKeepEnglishTest extends InstallerTranslationMultipleLanguageForeignTest {
|
||||
|
||||
/**
|
||||
* Switch to the multilingual testing profile with English kept.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing_multilingual_with_english';
|
||||
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests translation files for multiple languages get imported during install.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationMultipleLanguageTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Switch to the multilingual testing profile.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing_multilingual';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place custom local translations in the translations directory.
|
||||
mkdir(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.es.po', $this->getPo('es'));
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
|
||||
msgid "Anonymous"
|
||||
msgstr "Anonymous $langcode"
|
||||
|
||||
msgid "Language"
|
||||
msgstr "Language $langcode"
|
||||
|
||||
#: Testing site name configuration during the installer.
|
||||
msgid "Drupal"
|
||||
msgstr "Drupal"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function installParameters() {
|
||||
$params = parent::installParameters();
|
||||
$params['forms']['install_configure_form']['site_name'] = 'SITE_NAME_' . $this->langcode;
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that translations ended up at the expected places.
|
||||
*/
|
||||
public function testTranslationsLoaded() {
|
||||
// Ensure the title is correct.
|
||||
$this->assertEqual('SITE_NAME_' . $this->langcode, \Drupal::config('system.site')->get('name'));
|
||||
|
||||
// Verify German and Spanish were configured.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertText('Spanish');
|
||||
// If the installer was English or we used a profile that keeps English, we
|
||||
// expect that configured also. Otherwise English should not be configured
|
||||
// on the site.
|
||||
if ($this->langcode == 'en' || $this->profile == 'testing_multilingual_with_english') {
|
||||
$this->assertText('English');
|
||||
}
|
||||
else {
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
// Verify the strings from the translation files were imported.
|
||||
$this->verifyImportedStringsTranslated();
|
||||
|
||||
/** @var \Drupal\language\ConfigurableLanguageManager $language_manager */
|
||||
$language_manager = \Drupal::languageManager();
|
||||
|
||||
// If the site was installed in a foreign language (only tested with German
|
||||
// in subclasses), then the active configuration should be updated and no
|
||||
// override should exist in German. Otherwise the German translation should
|
||||
// end up in overrides the same way as Spanish (which is not used as a site
|
||||
// installation language). English should be available based on profile
|
||||
// information and should be possible to add if not yet added, making
|
||||
// English overrides available.
|
||||
|
||||
$config = \Drupal::config('user.settings');
|
||||
$override_de = $language_manager->getLanguageConfigOverride('de', 'user.settings');
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$override_es = $language_manager->getLanguageConfigOverride('es', 'user.settings');
|
||||
|
||||
if ($this->langcode == 'de') {
|
||||
// Active configuration should be in German and no German override should
|
||||
// exist.
|
||||
$this->assertEqual($config->get('anonymous'), 'Anonymous de');
|
||||
$this->assertEqual($config->get('langcode'), 'de');
|
||||
$this->assertTrue($override_de->isNew());
|
||||
|
||||
if ($this->profile == 'testing_multilingual_with_english') {
|
||||
// English is already added in this profile. Should make the override
|
||||
// available.
|
||||
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
|
||||
}
|
||||
else {
|
||||
// English is not yet available.
|
||||
$this->assertTrue($override_en->isNew());
|
||||
|
||||
// Adding English should make the English override available.
|
||||
$edit = ['predefined_langcode' => 'en'];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
|
||||
}
|
||||
|
||||
// Activate a module, to make sure that config is not overridden by module
|
||||
// installation.
|
||||
$edit = [
|
||||
'modules[views][enable]' => TRUE,
|
||||
'modules[filter][enable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/modules', $edit, t('Install'));
|
||||
|
||||
// Verify the strings from the translation are still as expected.
|
||||
$this->verifyImportedStringsTranslated();
|
||||
}
|
||||
else {
|
||||
// Active configuration should be English.
|
||||
$this->assertEqual($config->get('anonymous'), 'Anonymous');
|
||||
$this->assertEqual($config->get('langcode'), 'en');
|
||||
// There should not be an English override.
|
||||
$this->assertTrue($override_en->isNew());
|
||||
// German should be an override.
|
||||
$this->assertEqual($override_de->get('anonymous'), 'Anonymous de');
|
||||
}
|
||||
|
||||
// Spanish is always an override (never used as installation language).
|
||||
$this->assertEqual($override_es->get('anonymous'), 'Anonymous es');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to verify that the expected strings are translated.
|
||||
*/
|
||||
protected function verifyImportedStringsTranslated() {
|
||||
$test_samples = ['Save and continue', 'Anonymous', 'Language'];
|
||||
$langcodes = ['de', 'es'];
|
||||
|
||||
foreach ($test_samples as $sample) {
|
||||
foreach ($langcodes as $langcode) {
|
||||
$edit = [];
|
||||
$edit['langcode'] = $langcode;
|
||||
$edit['translation'] = 'translated';
|
||||
$edit['string'] = $sample;
|
||||
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Filter'));
|
||||
$this->assertText($sample . ' ' . $langcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Installs Drupal in German and checks resulting site.
|
||||
*
|
||||
* @group Installer
|
||||
*
|
||||
* @see \Drupal\FunctionalTests\Installer\InstallerTranslationTest
|
||||
*/
|
||||
class InstallerTranslationQueryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir($this->root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
|
||||
// The unrouted URL assembler does not exist at this point, so we build the
|
||||
// URL ourselves.
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=' . $this->langcode);
|
||||
|
||||
// The language should have been automatically detected, all following
|
||||
// screens should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual(current($elements)->getText(), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = current($this->xpath('/@dir'))->getText();
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// The language was was preset by passing a query parameter in the URL, so
|
||||
// no explicit language selection is necessary.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected behaviors of the installation result.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Installs Drupal in German and checks resulting site.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir($this->root . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents($this->root . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
|
||||
parent::setUpLanguage();
|
||||
|
||||
// After selecting a different language than English, all following screens
|
||||
// should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual(current($elements)->getText(), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = current($this->xpath('/@dir'))->getText();
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// We are creating a table here to force an error in the installer because
|
||||
// it will try and create the drupal_install_test table as this is part of
|
||||
// the standard database tests performed by the installer in
|
||||
// Drupal\Core\Database\Install\Tasks.
|
||||
Database::getConnection('default')->query('CREATE TABLE {drupal_install_test} (id int NULL)');
|
||||
parent::setUpSettings();
|
||||
|
||||
// Ensure that the error message translation is working.
|
||||
$this->assertRaw('Beheben Sie alle Probleme unten, um die Installation fortzusetzen. Informationen zur Konfiguration der Datenbankserver finden Sie in der <a href="https://www.drupal.org/getting-started/install">Installationshandbuch</a>, oder kontaktieren Sie Ihren Hosting-Anbieter.');
|
||||
$this->assertRaw('<strong>CREATE</strong> ein Test-Tabelle auf Ihrem Datenbankserver mit dem Befehl <em class="placeholder">CREATE TABLE {drupal_install_test} (id int NULL)</em> fehlgeschlagen.');
|
||||
|
||||
// Now do it successfully.
|
||||
Database::getConnection('default')->query('DROP TABLE {drupal_install_test}');
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected behaviors of the installation result.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
|
||||
// The current container still has the english as current language, rebuild.
|
||||
$this->rebuildContainer();
|
||||
/** @var \Drupal\user\Entity\User $account */
|
||||
$account = User::load(0);
|
||||
$this->assertEqual($account->language()->getId(), 'en', 'Anonymous user is English.');
|
||||
$account = User::load(1);
|
||||
$this->assertEqual($account->language()->getId(), 'en', 'Administrator user is English.');
|
||||
$account = $this->drupalCreateUser();
|
||||
$this->assertEqual($account->language()->getId(), 'de', 'New user is German.');
|
||||
|
||||
// Ensure that we can enable basic_auth on a non-english site.
|
||||
$this->drupalPostForm('admin/modules', ['modules[basic_auth][enable]' => TRUE], t('Install'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Assert that the theme CSS was added to the page.
|
||||
$edit = ['preprocess_css' => FALSE];
|
||||
$this->drupalPostForm('admin/config/development/performance', $edit, t('Save configuration'));
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertRaw('classy/css/components/action-links.css');
|
||||
|
||||
// Verify the strings from the translation files were imported.
|
||||
$test_samples = ['Save and continue', 'Anonymous'];
|
||||
foreach ($test_samples as $sample) {
|
||||
$edit = [];
|
||||
$edit['langcode'] = 'de';
|
||||
$edit['translation'] = 'translated';
|
||||
$edit['string'] = $sample;
|
||||
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Filter'));
|
||||
$this->assertText($sample . ' de');
|
||||
}
|
||||
|
||||
/** @var \Drupal\language\ConfigurableLanguageManager $language_manager */
|
||||
$language_manager = \Drupal::languageManager();
|
||||
|
||||
// Installed in German, configuration should be in German. No German or
|
||||
// English overrides should be present.
|
||||
$config = \Drupal::config('user.settings');
|
||||
$override_de = $language_manager->getLanguageConfigOverride('de', 'user.settings');
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$this->assertEqual($config->get('anonymous'), 'Anonymous de');
|
||||
$this->assertEqual($config->get('langcode'), 'de');
|
||||
$this->assertTrue($override_de->isNew());
|
||||
$this->assertTrue($override_en->isNew());
|
||||
|
||||
// Assert that adding English makes the English override available.
|
||||
$edit = ['predefined_langcode' => 'en'];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$this->assertFalse($override_en->isNew());
|
||||
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
|
||||
msgid "Anonymous"
|
||||
msgstr "Anonymous $langcode"
|
||||
|
||||
msgid "Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="https://www.drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider."
|
||||
msgstr "Beheben Sie alle Probleme unten, um die Installation fortzusetzen. Informationen zur Konfiguration der Datenbankserver finden Sie in der <a href="https://www.drupal.org/getting-started/install">Installationshandbuch</a>, oder kontaktieren Sie Ihren Hosting-Anbieter."
|
||||
|
||||
msgid "Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>"
|
||||
msgstr "<strong>CREATE</strong> ein Test-Tabelle auf Ihrem Datenbankserver mit dem Befehl %query fehlgeschlagen."
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\KernelTests\AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* Tests the interactive installer installing the minimal profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class MinimalInstallerTest extends ConfigAfterInstallerTestBase {
|
||||
|
||||
use AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'minimal';
|
||||
|
||||
/**
|
||||
* Ensures that the exported minimal configuration is up to date.
|
||||
*/
|
||||
public function testMinimalConfig() {
|
||||
$this->assertInstalledConfig([]);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
|
||||
/**
|
||||
* Tests multiple distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class MultipleDistributionsProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
// Create two distributions.
|
||||
foreach (['distribution_one', 'distribution_two'] as $name) {
|
||||
$info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => $name . ' profile',
|
||||
'distribution' => [
|
||||
'name' => $name,
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->root . DIRECTORY_SEPARATOR . $this->siteDirectory . '/profiles/' . $name;
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/$name.info.yml", Yaml::encode($info));
|
||||
}
|
||||
// Install the first distribution.
|
||||
$this->profile = 'distribution_one';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw('distribution_one');
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw('bartik');
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Confirm that Drupal recognizes this distribution as the current profile.
|
||||
$this->assertEqual(\Drupal::installProfile(), 'distribution_one');
|
||||
$this->assertEqual($this->config('core.extension')->get('profile'), 'distribution_one', 'The install profile has been written to core.extension configuration.');
|
||||
|
||||
$this->rebuildContainer();
|
||||
$this->pass('Container can be rebuilt as distribution is written to configuration.');
|
||||
$this->assertEqual(\Drupal::installProfile(), 'distribution_one');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class SingleVisibleProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The installation profile to install.
|
||||
*
|
||||
* Not needed when only one is visible.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = NULL;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEnvironment() {
|
||||
parent::prepareEnvironment();
|
||||
$profiles = ['standard', 'demo_umami'];
|
||||
foreach ($profiles as $profile) {
|
||||
$info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Override ' . $profile,
|
||||
'hidden' => TRUE,
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/' . $profile;
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/$profile.info.yml", Yaml::encode($info));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is only one visible profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
// Confirm that the minimal profile was installed.
|
||||
$this->assertEqual(drupal_get_profile(), 'minimal');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that the site name can be set during a non-interactive installation.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class SiteNameTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* The site name to be used when testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $siteName;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function installParameters() {
|
||||
$this->siteName = $this->randomMachineName();
|
||||
$parameters = parent::installParameters();
|
||||
$parameters['forms']['install_configure_form']['site_name'] = $this->siteName;
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the desired site name appears on the page after installation.
|
||||
*/
|
||||
public function testSiteName() {
|
||||
$this->drupalGet('');
|
||||
$this->assertRaw($this->siteName, 'The site name that was set during the installation appears on the front page after installation.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\Installer;
|
||||
|
||||
/**
|
||||
* Tests the interactive installer installing the standard profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class StandardInstallerTest extends ConfigAfterInstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
|
||||
/**
|
||||
* Ensures that the user page is available after installation.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
// Verify that the Standard install profile's default frontpage appears.
|
||||
$this->assertRaw('No front page content has been created yet.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// Test that the correct theme is being used.
|
||||
$this->assertNoRaw('bartik');
|
||||
$this->assertRaw('themes/seven/css/theme/install-page.css');
|
||||
parent::setUpSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function curlExec($curl_options, $redirect = FALSE) {
|
||||
// Ensure that we see the classy progress CSS on the batch page.
|
||||
// Batch processing happens as part of HTTP redirects, so we can access the
|
||||
// HTML of the batch page.
|
||||
if (strpos($curl_options[CURLOPT_URL], '&id=1&op=do_nojs') !== FALSE) {
|
||||
$this->assertRaw('themes/classy/css/components/progress.css');
|
||||
}
|
||||
return parent::curlExec($curl_options, $redirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the exported standard configuration is up to date.
|
||||
*/
|
||||
public function testStandardConfig() {
|
||||
$skipped_config = [];
|
||||
// FunctionalTestSetupTrait::installParameters() uses
|
||||
// simpletest@example.com as mail address.
|
||||
$skipped_config['contact.form.feedback'][] = '- simpletest@example.com';
|
||||
// \Drupal\filter\Entity\FilterFormat::toArray() drops the roles of filter
|
||||
// formats.
|
||||
$skipped_config['filter.format.basic_html'][] = 'roles:';
|
||||
$skipped_config['filter.format.basic_html'][] = '- authenticated';
|
||||
$skipped_config['filter.format.full_html'][] = 'roles:';
|
||||
$skipped_config['filter.format.full_html'][] = '- administrator';
|
||||
$skipped_config['filter.format.restricted_html'][] = 'roles:';
|
||||
$skipped_config['filter.format.restricted_html'][] = '- anonymous';
|
||||
|
||||
$this->assertInstalledConfig($skipped_config);
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue