Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

View file

@ -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());
}
}
}
}

View file

@ -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');
}
}

View file

@ -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.');
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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'));
}
}

View file

@ -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());
}
}
}

View file

@ -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.");
}
}

View file

@ -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.");
}
}

View file

@ -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');
}
}

View file

@ -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);
}
}

View file

@ -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.');
}
}

View file

@ -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';
}
}

View file

@ -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');
}
}

View file

@ -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';
}
}

View file

@ -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.');
}
}

View file

@ -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');
}
}

View file

@ -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');
}
}

View file

@ -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');
}
}

View file

@ -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';
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}

View file

@ -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');
}
}

View file

@ -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');
}
}

View file

@ -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());
}
}

View file

@ -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.");
}
}

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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.');
}
}

View file

@ -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);
}
}

View file

@ -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');
}
}

View file

@ -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();
}
}

View file

@ -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';
}
}

View file

@ -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';
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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([]);
}
}

View file

@ -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');
}
}

View file

@ -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');
}
}

View file

@ -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.');
}
}

View file

@ -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);
}
}