Revert "Issue #2171683 by sun, tstoeckler, larowlan: Remove all Simpletest overrides and rely on native multi-site functionality instead."
This reverts commit 91db25eba4. Broke web
tests.
8.0.x
parent
cd661a19a7
commit
ec06f877a4
|
|
@ -240,15 +240,15 @@ define('DRUPAL_ROOT', dirname(dirname(__DIR__)));
|
|||
* @see default.settings.php
|
||||
*/
|
||||
function conf_path($require_settings = TRUE, $reset = FALSE) {
|
||||
static $conf_path;
|
||||
$conf_path = &drupal_static(__FUNCTION__, '');
|
||||
|
||||
if (isset($conf_path) && !$reset) {
|
||||
if ($conf_path && !$reset) {
|
||||
return $conf_path;
|
||||
}
|
||||
|
||||
// Check for a simpletest override.
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
$conf_path = 'sites/simpletest/' . substr($test_prefix, 10);
|
||||
if ($simpletest_conf_path = _drupal_simpletest_conf_path()) {
|
||||
$conf_path = $simpletest_conf_path;
|
||||
return $conf_path;
|
||||
}
|
||||
|
||||
|
|
@ -262,6 +262,50 @@ function conf_path($require_settings = TRUE, $reset = FALSE) {
|
|||
return $conf_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to use an overridden value for conf_path().
|
||||
*
|
||||
* Simpletest may provide a secondary, test-specific settings.php file to load
|
||||
* after the primary one used by the parent site and override its variables.
|
||||
* - If the child settings.php does not override $conf_path, then this function
|
||||
* returns FALSE and conf_path() returns the directory of the primary
|
||||
* settings.php.
|
||||
* - If the child settings.php does override $conf_path, then
|
||||
* _drupal_load_test_overrides() sets the 'simpletest_conf_path' setting, and
|
||||
* this function returns that to conf_path(), causing installations and
|
||||
* upgrades to act on that one.
|
||||
*
|
||||
* @return string|false
|
||||
* The overridden $conf_path, or FALSE if the $conf_path should not currently
|
||||
* be overridden.
|
||||
*
|
||||
* @see conf_path()
|
||||
* @see _drupal_load_test_overrides()
|
||||
*/
|
||||
function _drupal_simpletest_conf_path() {
|
||||
// Ensure that the settings object is available. conf_path() is called once
|
||||
// before the Settings class is included, and at that point it should still
|
||||
// load the primary $conf_path. See drupal_settings_initialize().
|
||||
if (!class_exists('Drupal\Component\Utility\Settings', FALSE)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If no $simpletest_conf_path is set, use the normal $conf_path.
|
||||
if (!($simpletest_conf_path = settings()->get('simpletest_conf_path'))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Ensure that this is actually a simpletest request. We can't check this
|
||||
// before settings.php is loaded.
|
||||
if (!drupal_valid_test_ua()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// When the $simpletest_conf_path is set in a valid test request,
|
||||
// return that path.
|
||||
return $simpletest_conf_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the appropriate configuration directory for a given host and path.
|
||||
*
|
||||
|
|
@ -490,32 +534,20 @@ function drupal_valid_http_host($host) {
|
|||
* Sets the base URL, cookie domain, and session name from configuration.
|
||||
*/
|
||||
function drupal_settings_initialize() {
|
||||
global $base_url, $base_path, $base_root, $script_path;
|
||||
|
||||
// Export these settings.php variables to the global namespace.
|
||||
global $base_url, $databases, $cookie_domain, $drupal_hash_salt, $config_directories, $config;
|
||||
global $databases, $cookie_domain, $db_prefix, $drupal_hash_salt, $base_secure_url, $base_insecure_url, $config_directories, $config;
|
||||
$settings = array();
|
||||
$config = array();
|
||||
|
||||
// Make conf_path() available as local variable in settings.php.
|
||||
$conf_path = conf_path();
|
||||
if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
|
||||
require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
|
||||
include_once DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
|
||||
}
|
||||
// Initialize Settings.
|
||||
new Settings($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes global request variables.
|
||||
*
|
||||
* @todo D8: Eliminate this entirely in favor of Request object.
|
||||
*/
|
||||
function _drupal_request_initialize() {
|
||||
// Provided by settings.php.
|
||||
// @see drupal_settings_initialize()
|
||||
global $base_url, $cookie_domain;
|
||||
// Set and derived from $base_url by this function.
|
||||
global $base_path, $base_root, $script_path;
|
||||
global $base_secure_url, $base_insecure_url;
|
||||
|
||||
$is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
|
||||
|
||||
|
|
@ -1721,27 +1753,11 @@ function _drupal_exception_handler($exception) {
|
|||
*/
|
||||
function _drupal_bootstrap_configuration() {
|
||||
drupal_environment_initialize();
|
||||
|
||||
// Indicate that code is operating in a test child site.
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
// Only code that interfaces directly with tests should rely on this
|
||||
// constant; e.g., the error/exception handler conditionally adds further
|
||||
// error information into HTTP response headers that are consumed by
|
||||
// Simpletest's internal browser.
|
||||
define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
|
||||
|
||||
// Log fatal errors to the test site directory.
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
|
||||
}
|
||||
else {
|
||||
// Ensure that no other code defines this.
|
||||
define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
|
||||
}
|
||||
|
||||
// Initialize the configuration, including variables from settings.php.
|
||||
drupal_settings_initialize();
|
||||
_drupal_request_initialize();
|
||||
|
||||
// Make sure we are using the test database prefix in child Drupal sites.
|
||||
_drupal_initialize_db_test_prefix();
|
||||
|
||||
// Activate the class loader.
|
||||
drupal_classloader();
|
||||
|
|
@ -1829,6 +1845,39 @@ function _drupal_bootstrap_page_cache() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In a test environment, get the test db prefix and set it in $databases.
|
||||
*/
|
||||
function _drupal_initialize_db_test_prefix() {
|
||||
// The user agent header is used to pass a database prefix in the request when
|
||||
// running tests. However, for security reasons, it is imperative that we
|
||||
// validate we ourselves made the request.
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
// Set the test run id for use in other parts of Drupal.
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
$test_info['test_run_id'] = $test_prefix;
|
||||
$test_info['in_child_site'] = TRUE;
|
||||
|
||||
foreach ($GLOBALS['databases']['default'] as &$value) {
|
||||
// Extract the current default database prefix.
|
||||
if (!isset($value['prefix'])) {
|
||||
$current_prefix = '';
|
||||
}
|
||||
elseif (is_array($value['prefix'])) {
|
||||
$current_prefix = $value['prefix']['default'];
|
||||
}
|
||||
else {
|
||||
$current_prefix = $value['prefix'];
|
||||
}
|
||||
|
||||
// Remove the current database prefix and replace it by our own.
|
||||
$value['prefix'] = array(
|
||||
'default' => $current_prefix . $test_prefix,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current bootstrap phase for this Drupal process.
|
||||
*
|
||||
|
|
@ -1943,9 +1992,10 @@ function module_hook($module, $hook) {
|
|||
* Returns the test prefix if this is an internal request from SimpleTest.
|
||||
*
|
||||
* @param string $new_prefix
|
||||
* Internal use only. A new prefix to be stored.
|
||||
* Internal use only. A new prefix to be stored. Passed in by tests that use
|
||||
* the test runner from within a test.
|
||||
*
|
||||
* @return string|FALSE
|
||||
* @return
|
||||
* Either the simpletest prefix (the string "simpletest" followed by any
|
||||
* number of digits) or FALSE if the user agent does not contain a valid
|
||||
* HMAC and timestamp.
|
||||
|
|
@ -1959,68 +2009,82 @@ function drupal_valid_test_ua($new_prefix = NULL) {
|
|||
if (isset($test_prefix)) {
|
||||
return $test_prefix;
|
||||
}
|
||||
// Unless the below User-Agent and HMAC validation succeeds, we are not in
|
||||
// a test environment.
|
||||
$test_prefix = FALSE;
|
||||
|
||||
// Perform a basic check on the User-Agent HTTP request header first. Any
|
||||
// inbound request that uses the simpletest UA header needs to be validated.
|
||||
if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);(.+);(.+);(.+)$/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
|
||||
list(, $prefix, $time, $salt, $hmac) = $matches;
|
||||
$check_string = $prefix . ';' . $time . ';' . $salt;
|
||||
// Read the hash salt prepared by drupal_generate_test_ua().
|
||||
// This function is called before settings.php is read and Drupal's error
|
||||
// handlers are set up. While Drupal's error handling may be properly
|
||||
// configured on production sites, the server's PHP error_reporting may not.
|
||||
// Ensure that no information leaks on production sites.
|
||||
$key_file = DRUPAL_ROOT . '/sites/simpletest/' . substr($prefix, 10) . '/.htkey';
|
||||
if (!is_readable($key_file)) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
$private_key = file_get_contents($key_file);
|
||||
// The file properties add more entropy not easily accessible to others.
|
||||
$key = $private_key . filectime(__FILE__) . fileinode(__FILE__);
|
||||
// We use the salt from settings.php to make the HMAC key, since
|
||||
// the database is not yet initialized and we can't access the configuration
|
||||
// system. The file properties add more entropy not easily accessible to
|
||||
// others.
|
||||
$key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
|
||||
$time_diff = REQUEST_TIME - $time;
|
||||
$test_hmac = Crypt::hmacBase64($check_string, $key);
|
||||
// We can't use Crypt::hmacBase64() yet because this can be called in very
|
||||
// early bootstrap when autoloader has not been initialized yet.
|
||||
$test_hmac = base64_encode(hash_hmac('sha256', $check_string, $key, TRUE));
|
||||
$test_hmac = strtr($test_hmac, array('+' => '-', '/' => '_', '=' => ''));
|
||||
// Since we are making a local request a 5 second time window is allowed,
|
||||
// and the HMAC must match.
|
||||
if ($time_diff >= 0 && $time_diff <= 5 && $hmac === $test_hmac) {
|
||||
if ($time_diff >= 0 && $time_diff <= 5 && $hmac == $test_hmac) {
|
||||
$test_prefix = $prefix;
|
||||
_drupal_load_test_overrides($test_prefix);
|
||||
return $test_prefix;
|
||||
}
|
||||
}
|
||||
|
||||
$test_prefix = FALSE;
|
||||
return $test_prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides low-level and environment-specific configuration.
|
||||
*
|
||||
* Very strictly for internal use only.
|
||||
*
|
||||
* Loads settings.php from the simpletest public files directory. These files
|
||||
* can change the global $config_directories, the return value of conf_path(),
|
||||
* settings(), and $config overrides.
|
||||
*
|
||||
* @param string $test_prefix
|
||||
* The simpletest prefix.
|
||||
*/
|
||||
function _drupal_load_test_overrides($test_prefix) {
|
||||
global $config_directories, $config;
|
||||
|
||||
// Do not use the parent site's config directories. Use only the child site's.
|
||||
// @see \Drupal\simpletest\TestBase::prepareConfigDirectories()
|
||||
$path_prefix = 'simpletest/' . substr($test_prefix, 10);
|
||||
$config_directories = array();
|
||||
foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) {
|
||||
$config_directories[$type] = conf_path() . '/files/' . $path_prefix . '/config_' . $type;
|
||||
}
|
||||
|
||||
// Check for and load a settings.php file in the simpletest files directory.
|
||||
$filename = conf_path() . '/files/' . $path_prefix . '/settings.php';
|
||||
if (file_exists($filename)) {
|
||||
$settings = settings()->getAll();
|
||||
$conf_path = &drupal_static('conf_path');
|
||||
// This can override $config, $conf_path, $settings, and $config_directories.
|
||||
include $filename;
|
||||
// Keep the overriden $conf_path alive across drupal_static_reset() calls.
|
||||
// @see conf_path()
|
||||
$settings['simpletest_conf_path'] = $conf_path;
|
||||
new Settings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user agent string with a HMAC and timestamp for simpletest.
|
||||
*/
|
||||
function drupal_generate_test_ua($prefix) {
|
||||
static $key, $last_prefix;
|
||||
static $key;
|
||||
|
||||
if (!isset($key) || $last_prefix != $prefix) {
|
||||
$last_prefix = $prefix;
|
||||
$key_file = DRUPAL_ROOT . '/sites/simpletest/' . substr($prefix, 10) . '/.htkey';
|
||||
// When issuing an outbound HTTP client request from within an inbound test
|
||||
// request, then the outbound request has to use the same User-Agent header
|
||||
// as the inbound request. A newly generated private key for the same test
|
||||
// prefix would invalidate all subsequent inbound requests.
|
||||
// @see \Drupal\Core\Http\Plugin\SimpletestHttpRequestSubscriber
|
||||
if (DRUPAL_TEST_IN_CHILD_SITE && $parent_prefix = drupal_valid_test_ua()) {
|
||||
if ($parent_prefix != $prefix) {
|
||||
throw new \RuntimeException("Malformed User-Agent: Expected '$parent_prefix' but got '$prefix'.");
|
||||
}
|
||||
// If the file is not readable, a PHP warning is expected in this case.
|
||||
$private_key = file_get_contents($key_file);
|
||||
}
|
||||
else {
|
||||
// Generate and save a new hash salt for a test run.
|
||||
// Consumed by drupal_valid_test_ua() before settings.php is loaded.
|
||||
$private_key = Crypt::randomStringHashed(55);
|
||||
file_put_contents($key_file, $private_key);
|
||||
}
|
||||
// The file properties add more entropy not easily accessible to others.
|
||||
$key = $private_key . filectime(__FILE__) . fileinode(__FILE__);
|
||||
if (!isset($key)) {
|
||||
// We use the salt from settings.php to make the HMAC key, since
|
||||
// the database is not yet initialized and we can't access the configuration
|
||||
// system. The file properties add more entropy not easily accessible to
|
||||
// others.
|
||||
$key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
|
||||
}
|
||||
// Generate a moderately secure HMAC based on the database credentials.
|
||||
$salt = uniqid('', TRUE);
|
||||
|
|
|
|||
|
|
@ -3071,6 +3071,14 @@ function _drupal_bootstrap_code() {
|
|||
// Make sure all stream wrappers are registered.
|
||||
file_get_stream_wrappers();
|
||||
|
||||
// Now that stream wrappers are registered, log fatal errors from a simpletest
|
||||
// child site to a test specific file directory.
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
if (!empty($test_info['in_child_site'])) {
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'public://error.log');
|
||||
}
|
||||
|
||||
// Set the allowed protocols once we have the config available.
|
||||
$allowed_protocols = \Drupal::config('system.filter')->get('protocols');
|
||||
if (!isset($allowed_protocols)) {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,8 @@ function _drupal_log_error($error, $fatal = FALSE) {
|
|||
|
||||
// When running inside the testing framework, we relay the errors
|
||||
// to the tested site by the way of HTTP headers.
|
||||
if (DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
if (!empty($test_info['in_child_site']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
|
||||
// $number does not use drupal_static as it should not be reset
|
||||
// as it uniquely identifies each PHP error.
|
||||
static $number = 0;
|
||||
|
|
|
|||
|
|
@ -276,18 +276,19 @@ function install_begin_request(&$install_state) {
|
|||
// which will be used for installing Drupal.
|
||||
conf_path(FALSE);
|
||||
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
|
||||
|
||||
// If the hash salt leaks, it becomes possible to forge a valid testing user
|
||||
// agent, install a new copy of Drupal, and take over the original site.
|
||||
// The user agent header is used to pass a database prefix in the request when
|
||||
// running tests. However, for security reasons, it is imperative that no
|
||||
// installation be permitted using such a prefix.
|
||||
if ($install_state['interactive'] && strpos($request->server->get('HTTP_USER_AGENT'), 'simpletest') !== FALSE && !drupal_valid_test_ua()) {
|
||||
// agent, install a new copy of Drupal, and take over the original site. To
|
||||
// avoid this yet allow for automated testing of the installer, make sure
|
||||
// there is also a special test-specific settings.php overriding conf_path().
|
||||
// _drupal_load_test_overrides() sets the simpletest_conf_path in-memory
|
||||
// setting in this case.
|
||||
if ($install_state['interactive'] && drupal_valid_test_ua() && !settings()->get('simpletest_conf_path')) {
|
||||
header($request->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
|
||||
|
||||
// Ensure that procedural dependencies are loaded as early as possible,
|
||||
// since the error/exception handlers depend on them.
|
||||
require_once __DIR__ . '/../modules/system/system.install';
|
||||
|
|
@ -1079,6 +1080,7 @@ function install_verify_database_settings() {
|
|||
global $databases;
|
||||
if (!empty($databases)) {
|
||||
$database = $databases['default']['default'];
|
||||
drupal_static_reset('conf_path');
|
||||
$settings_file = './' . conf_path(FALSE) . '/settings.php';
|
||||
$errors = install_database_errors($database, $settings_file);
|
||||
if (empty($errors)) {
|
||||
|
|
@ -1101,6 +1103,7 @@ function install_verify_database_settings() {
|
|||
function install_settings_form($form, &$form_state, &$install_state) {
|
||||
global $databases;
|
||||
|
||||
drupal_static_reset('conf_path');
|
||||
$conf_path = './' . conf_path(FALSE);
|
||||
$settings_file = $conf_path . '/settings.php';
|
||||
$database = isset($databases['default']['default']) ? $databases['default']['default'] : array();
|
||||
|
|
@ -1162,6 +1165,12 @@ function install_settings_form($form, &$form_state, &$install_state) {
|
|||
function install_settings_form_validate($form, &$form_state) {
|
||||
$driver = $form_state['values']['driver'];
|
||||
$database = $form_state['values'][$driver];
|
||||
// When testing the interactive installer, copy the database password and
|
||||
// the test prefix.
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
$database['prefix'] = $test_prefix;
|
||||
$database['password'] = $GLOBALS['databases']['default']['default']['password'];
|
||||
}
|
||||
$drivers = drupal_get_database_types();
|
||||
$reflection = new \ReflectionClass($drivers[$driver]);
|
||||
$install_namespace = $reflection->getNamespaceName();
|
||||
|
|
@ -1228,14 +1237,33 @@ function install_settings_form_submit($form, &$form_state) {
|
|||
// Update global settings array and save.
|
||||
$settings = array();
|
||||
$database = $form_state['storage']['database'];
|
||||
$settings['databases']['default']['default'] = (object) array(
|
||||
'value' => $database,
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['drupal_hash_salt'] = (object) array(
|
||||
'value' => Crypt::randomStringHashed(55),
|
||||
'required' => TRUE,
|
||||
);
|
||||
// Ideally, there is no difference between the code executed by the
|
||||
// automated test browser and an ordinary browser. However, the database
|
||||
// settings need a different format and also need to skip the password
|
||||
// when testing. The hash salt also needs to be skipped because the original
|
||||
// salt is used to verify the validity of the automated test browser.
|
||||
// Because of these, there's a little difference in the code following but
|
||||
// it is small and self-contained.
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
foreach ($form_state['storage']['database'] as $k => $v) {
|
||||
if ($k != 'password') {
|
||||
$settings['databases']['default']['default'][$k] = (object) array(
|
||||
'value' => $v,
|
||||
'required' => TRUE,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$settings['databases']['default']['default'] = (object) array(
|
||||
'value' => $database,
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['drupal_hash_salt'] = (object) array(
|
||||
'value' => Crypt::randomStringHashed(55),
|
||||
'required' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
// Remember the profile which was used.
|
||||
$settings['settings'] = array(
|
||||
|
|
@ -2353,7 +2381,7 @@ function install_check_requirements($install_state) {
|
|||
if (!$install_state['settings_verified']) {
|
||||
$readable = FALSE;
|
||||
$writable = FALSE;
|
||||
$conf_path = './' . conf_path(FALSE);
|
||||
$conf_path = './' . conf_path(FALSE, TRUE);
|
||||
$settings_file = $conf_path . '/settings.php';
|
||||
$default_settings_file = './sites/default/default.settings.php';
|
||||
$file = $conf_path;
|
||||
|
|
|
|||
|
|
@ -292,7 +292,8 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn
|
|||
|
||||
// When running inside the testing framework, we relay the errors
|
||||
// to the tested site by the way of HTTP headers.
|
||||
if (DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
if (!empty($test_info['in_child_site']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
|
||||
// $number does not use drupal_static as it should not be reset
|
||||
// as it uniquely identifies each PHP error.
|
||||
static $number = 0;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class Tasks extends InstallTasks {
|
|||
// Make the text more accurate for SQLite.
|
||||
$form['database']['#title'] = t('Database file');
|
||||
$form['database']['#description'] = t('The absolute path to the file where @drupal data will be stored. This must be writable by the web server and should exist outside of the web root.', array('@drupal' => drupal_install_profile_distribution_name()));
|
||||
$default_database = conf_path(FALSE) . '/files/.ht.sqlite';
|
||||
$default_database = conf_path(FALSE, TRUE) . '/files/.ht.sqlite';
|
||||
$form['database']['#default_value'] = empty($database['database']) ? $default_database : $database['database'];
|
||||
return $form;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,13 +335,20 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the classname based on environment.
|
||||
* Returns the classname based on environment and testing prefix.
|
||||
*
|
||||
* @return string
|
||||
* The class name.
|
||||
*/
|
||||
protected function getClassName() {
|
||||
$parts = array('service_container', $this->environment);
|
||||
// Make sure to use a testing-specific container even in the parent site.
|
||||
if (!empty($GLOBALS['drupal_test_info']['test_run_id'])) {
|
||||
$parts[] = $GLOBALS['drupal_test_info']['test_run_id'];
|
||||
}
|
||||
elseif ($prefix = drupal_valid_test_ua()) {
|
||||
$parts[] = $prefix;
|
||||
}
|
||||
return implode('_', $parts);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ class SimpletestHttpRequestSubscriber implements EventSubscriberInterface {
|
|||
// user-agent is used to ensure that multiple testing sessions running at the
|
||||
// same time won't interfere with each other as they would if the database
|
||||
// prefix were stored statically in a file or database variable.
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
$event['request']->setHeader('User-Agent', drupal_generate_test_ua($test_prefix));
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
if (!empty($test_info['test_run_id'])) {
|
||||
$event['request']->setHeader('User-Agent', drupal_generate_test_ua($test_info['test_run_id']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,13 @@ class PublicStream extends LocalStream {
|
|||
*/
|
||||
public static function basePath() {
|
||||
$base_path = settings()->get('file_public_path', conf_path() . '/files');
|
||||
if ($test_prefix = drupal_valid_test_ua()) {
|
||||
// Append the testing suffix unless already given.
|
||||
// @see \Drupal\simpletest\WebTestBase::setUp()
|
||||
if (strpos($base_path, '/simpletest/' . substr($test_prefix, 10)) === FALSE) {
|
||||
return $base_path . '/simpletest/' . substr($test_prefix, 10);
|
||||
}
|
||||
}
|
||||
return $base_path;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,12 +95,11 @@ class FieldImportCreateTest extends FieldUnitTestBase {
|
|||
|
||||
// Add the new files to the staging directory.
|
||||
$src_dir = drupal_get_path('module', 'field_test_config') . '/staging';
|
||||
$target_dir = $this->configDirectories[CONFIG_STAGING_DIRECTORY];
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "$target_dir/$field_config_name.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name.yml", "$target_dir/$instance_config_name.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2.yml", "$target_dir/$field_config_name_2.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name_2a.yml", "$target_dir/$instance_config_name_2a.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name_2b.yml", "$target_dir/$instance_config_name_2b.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "public://config_staging/$field_config_name.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name.yml", "public://config_staging/$instance_config_name.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2.yml", "public://config_staging/$field_config_name_2.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name_2a.yml", "public://config_staging/$instance_config_name_2a.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$instance_config_name_2b.yml", "public://config_staging/$instance_config_name_2b.yml"));
|
||||
|
||||
// Import the content of the staging directory.
|
||||
$this->configImporter()->import();
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use Drupal\Core\StreamWrapper\LocalReadOnlyStream;
|
|||
*/
|
||||
class DummyReadOnlyStreamWrapper extends LocalReadOnlyStream {
|
||||
function getDirectoryPath() {
|
||||
return conf_path() . '/files';
|
||||
return 'sites/default/files';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use Drupal\Core\StreamWrapper\LocalStream;
|
|||
*/
|
||||
class DummyStreamWrapper extends LocalStream {
|
||||
function getDirectoryPath() {
|
||||
return conf_path() . '/files';
|
||||
return 'sites/default/files';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ class LanguageNegotiationInfoTest extends WebTestBase {
|
|||
*/
|
||||
public static $modules = array('language');
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\language\ConfigurableLanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -39,60 +46,31 @@ class LanguageNegotiationInfoTest extends WebTestBase {
|
|||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->languageManager = $this->container->get('language_manager');
|
||||
$admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme'));
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalPostForm('admin/config/regional/language/add', array('predefined_langcode' => 'it'), t('Add language'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurable language manager.
|
||||
*
|
||||
* @return \Drupal\language\ConfigurableLanguageManager
|
||||
*/
|
||||
protected function languageManager() {
|
||||
return $this->container->get('language_manager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets state flags for language_test module.
|
||||
*
|
||||
* Ensures to correctly update data both in the child site and the test runner
|
||||
* environment.
|
||||
*
|
||||
* @param array $values
|
||||
* The key/value pairs to set in state.
|
||||
*/
|
||||
protected function stateSet(array $values) {
|
||||
// Set the new state values.
|
||||
$this->container->get('state')->setMultiple($values);
|
||||
// Refresh in-memory static state/config caches and static variables.
|
||||
$this->refreshVariables();
|
||||
// Refresh/rewrite language negotiation configuration, in order to pick up
|
||||
// the manipulations performed by language_test module's info alter hooks.
|
||||
$this->container->get('language_negotiator')->purgeConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alterations to language types/negotiation info.
|
||||
*/
|
||||
function testInfoAlterations() {
|
||||
$this->stateSet(array(
|
||||
// Enable language_test type info.
|
||||
'language_test.language_types' => TRUE,
|
||||
// Enable language_test negotiation info (not altered yet).
|
||||
'language_test.language_negotiation_info' => TRUE,
|
||||
// Alter Language::TYPE_CONTENT to be configurable.
|
||||
'language_test.content_language_type' => TRUE,
|
||||
));
|
||||
$this->container->get('module_handler')->install(array('language_test'));
|
||||
$this->rebuildContainer();
|
||||
// Enable language type/negotiation info alterations.
|
||||
\Drupal::state()->set('language_test.language_types', TRUE);
|
||||
\Drupal::state()->set('language_test.language_negotiation_info', TRUE);
|
||||
$this->languageNegotiationUpdate();
|
||||
|
||||
// Check that fixed language types are properly configured without the need
|
||||
// of saving the language negotiation settings.
|
||||
$this->checkFixedLanguageTypes();
|
||||
|
||||
// Make the content language type configurable by updating the language
|
||||
// negotiation settings with the proper flag enabled.
|
||||
\Drupal::state()->set('language_test.content_language_type', TRUE);
|
||||
$this->languageNegotiationUpdate();
|
||||
$type = Language::TYPE_CONTENT;
|
||||
$language_types = $this->languageManager()->getLanguageTypes();
|
||||
$language_types = $this->languageManager->getLanguageTypes();
|
||||
$this->assertTrue(in_array($type, $language_types), 'Content language type is configurable.');
|
||||
|
||||
// Enable some core and custom language negotiation methods. The test
|
||||
|
|
@ -109,34 +87,30 @@ class LanguageNegotiationInfoTest extends WebTestBase {
|
|||
);
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
|
||||
// Alter language negotiation info to remove interface language negotiation
|
||||
// method.
|
||||
$this->stateSet(array(
|
||||
'language_test.language_negotiation_info_alter' => TRUE,
|
||||
));
|
||||
|
||||
$negotiation = $this->container->get('config.factory')->get('language.types')->get('negotiation.' . $type . '.enabled');
|
||||
// Remove the interface language negotiation method by updating the language
|
||||
// negotiation settings with the proper flag enabled.
|
||||
\Drupal::state()->set('language_test.language_negotiation_info_alter', TRUE);
|
||||
$this->languageNegotiationUpdate();
|
||||
$negotiation = \Drupal::config('language.types')->get('negotiation.' . $type . '.enabled') ?: array();
|
||||
$this->assertFalse(isset($negotiation[$interface_method_id]), 'Interface language negotiation method removed from the stored settings.');
|
||||
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->assertNoFieldByName($form_field, NULL, 'Interface language negotiation method unavailable.');
|
||||
$this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, 'Interface language negotiation method unavailable.');
|
||||
|
||||
// Check that type-specific language negotiation methods can be assigned
|
||||
// only to the corresponding language types.
|
||||
foreach ($this->languageManager()->getLanguageTypes() as $type) {
|
||||
foreach ($this->languageManager->getLanguageTypes() as $type) {
|
||||
$form_field = $type . '[enabled][test_language_negotiation_method_ts]';
|
||||
if ($type == $test_type) {
|
||||
$this->assertFieldByName($form_field, NULL, format_string('Type-specific test language negotiation method available for %type.', array('%type' => $type)));
|
||||
$this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, format_string('Type-specific test language negotiation method available for %type.', array('%type' => $type)));
|
||||
}
|
||||
else {
|
||||
$this->assertNoFieldByName($form_field, NULL, format_string('Type-specific test language negotiation method unavailable for %type.', array('%type' => $type)));
|
||||
$this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, format_string('Type-specific test language negotiation method unavailable for %type.', array('%type' => $type)));
|
||||
}
|
||||
}
|
||||
|
||||
// Check language negotiation results.
|
||||
$this->drupalGet('');
|
||||
$last = $this->container->get('state')->get('language_test.language_negotiation_last');
|
||||
foreach ($this->languageManager()->getDefinedLanguageTypes() as $type) {
|
||||
$last = \Drupal::state()->get('language_test.language_negotiation_last');
|
||||
foreach ($this->languageManager->getDefinedLanguageTypes() as $type) {
|
||||
$langcode = $last[$type];
|
||||
$value = $type == Language::TYPE_CONTENT || strpos($type, 'test') !== FALSE ? 'it' : 'en';
|
||||
$this->assertEqual($langcode, $value, format_string('The negotiated language for %type is %language', array('%type' => $type, '%language' => $value)));
|
||||
|
|
@ -144,11 +118,10 @@ class LanguageNegotiationInfoTest extends WebTestBase {
|
|||
|
||||
// Uninstall language_test and check that everything is set back to the
|
||||
// original status.
|
||||
$this->container->get('module_handler')->uninstall(array('language_test'));
|
||||
$this->rebuildContainer();
|
||||
$this->languageNegotiationUpdate('uninstall');
|
||||
|
||||
// Check that only the core language types are available.
|
||||
foreach ($this->languageManager()->getDefinedLanguageTypes() as $type) {
|
||||
foreach ($this->languageManager->getDefinedLanguageTypes() as $type) {
|
||||
$this->assertTrue(strpos($type, 'test') === FALSE, format_string('The %type language is still available', array('%type' => $type)));
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +131,7 @@ class LanguageNegotiationInfoTest extends WebTestBase {
|
|||
|
||||
// Check that unavailable language negotiation methods are not present in
|
||||
// the negotiation settings.
|
||||
$negotiation = $this->container->get('config.factory')->get('language.types')->get('negotiation.' . $type . '.enabled');
|
||||
$negotiation = \Drupal::config('language.types')->get('negotiation.' . $type . '.enabled') ?: array();
|
||||
$this->assertFalse(isset($negotiation[$test_method_id]), 'The disabled test language negotiation method is not part of the content language negotiation settings.');
|
||||
|
||||
// Check that configuration page presents the correct options and settings.
|
||||
|
|
@ -166,14 +139,41 @@ class LanguageNegotiationInfoTest extends WebTestBase {
|
|||
$this->assertNoRaw(t('This is a test language negotiation method'), 'No test language negotiation method available.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update language types/negotiation information.
|
||||
*
|
||||
* Manually invoke language_modules_installed()/language_modules_uninstalled()
|
||||
* since they would not be invoked after installing/uninstalling language_test
|
||||
* the first time.
|
||||
*/
|
||||
protected function languageNegotiationUpdate($op = 'install') {
|
||||
static $last_op = NULL;
|
||||
$modules = array('language_test');
|
||||
|
||||
// Install/uninstall language_test only if we did not already before.
|
||||
if ($last_op != $op) {
|
||||
call_user_func(array($this->container->get('module_handler'), $op), $modules);
|
||||
$last_op = $op;
|
||||
}
|
||||
else {
|
||||
$function = "language_modules_{$op}ed";
|
||||
if (function_exists($function)) {
|
||||
$function($modules);
|
||||
}
|
||||
}
|
||||
|
||||
$this->languageManager->reset();
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that language negotiation for fixed types matches the stored one.
|
||||
*/
|
||||
protected function checkFixedLanguageTypes() {
|
||||
$configurable = $this->languageManager()->getLanguageTypes();
|
||||
foreach ($this->languageManager()->getDefinedLanguageTypesInfo() as $type => $info) {
|
||||
$configurable = $this->languageManager->getLanguageTypes();
|
||||
foreach ($this->languageManager->getDefinedLanguageTypesInfo() as $type => $info) {
|
||||
if (!in_array($type, $configurable) && isset($info['fixed'])) {
|
||||
$negotiation = $this->container->get('config.factory')->get('language.types')->get('negotiation.' . $type . '.enabled');
|
||||
$negotiation = \Drupal::config('language.types')->get('negotiation.' . $type . '.enabled') ?: array();
|
||||
$equal = count($info['fixed']) == count($negotiation);
|
||||
while ($equal && list($id) = each($negotiation)) {
|
||||
list(, $info_id) = each($info['fixed']);
|
||||
|
|
|
|||
|
|
@ -71,8 +71,7 @@ class NodeImportCreateTest extends DrupalUnitTestBase {
|
|||
$this->copyConfig($active, $staging);
|
||||
// Manually add new node type.
|
||||
$src_dir = drupal_get_path('module', 'node_test_config') . '/staging';
|
||||
$target_dir = $this->configDirectories[CONFIG_STAGING_DIRECTORY];
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$node_type_config_name.yml", "$target_dir/$node_type_config_name.yml"));
|
||||
$this->assertTrue(file_unmanaged_copy("$src_dir/$node_type_config_name.yml", "public://config_staging/$node_type_config_name.yml"));
|
||||
|
||||
// Import the content of the staging directory.
|
||||
$this->configImporter()->import();
|
||||
|
|
|
|||
|
|
@ -57,13 +57,6 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
|
|||
private $themeFiles;
|
||||
private $themeData;
|
||||
|
||||
/**
|
||||
* The configuration directories for this test run.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $configDirectories = array();
|
||||
|
||||
/**
|
||||
* A KeyValueMemoryFactory instance to use when building the container.
|
||||
*
|
||||
|
|
@ -100,27 +93,6 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and set new configuration directories.
|
||||
*
|
||||
* @see config_get_config_directory()
|
||||
*/
|
||||
protected function prepareConfigDirectories() {
|
||||
$this->configDirectories = array();
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) {
|
||||
// Assign the relative path to the global variable.
|
||||
$path = $this->siteDirectory . '/config_' . $type;
|
||||
$GLOBALS['config_directories'][$type] = $path;
|
||||
// Ensure the directory can be created and is writeable.
|
||||
if (!install_ensure_config_directory($type)) {
|
||||
throw new \RuntimeException("Failed to create '$type' config directory $path");
|
||||
}
|
||||
// Provide the already resolved path for tests.
|
||||
$this->configDirectories[$type] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up Drupal unit test environment.
|
||||
*/
|
||||
|
|
@ -129,9 +101,6 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
|
|||
|
||||
parent::setUp();
|
||||
|
||||
// Create and set new configuration directories.
|
||||
$this->prepareConfigDirectories();
|
||||
|
||||
// Build a minimal, partially mocked environment for unit tests.
|
||||
$this->containerBuild(\Drupal::getContainer());
|
||||
// Make sure it survives kernel rebuilds.
|
||||
|
|
@ -188,9 +157,7 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
|
|||
}
|
||||
|
||||
protected function tearDown() {
|
||||
if ($this->kernel instanceof DrupalKernel) {
|
||||
$this->kernel->shutdown();
|
||||
}
|
||||
$this->kernel->shutdown();
|
||||
// Before tearing down the test environment, ensure that no stream wrapper
|
||||
// of this test leaks into the parent environment. Unlike all other global
|
||||
// state variables in Drupal, stream wrappers are a global state construct
|
||||
|
|
|
|||
|
|
@ -36,13 +36,6 @@ abstract class TestBase {
|
|||
*/
|
||||
protected $testId;
|
||||
|
||||
/**
|
||||
* The site directory of this test run.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $siteDirectory = NULL;
|
||||
|
||||
/**
|
||||
* The database prefix of this test run.
|
||||
*
|
||||
|
|
@ -158,13 +151,6 @@ abstract class TestBase {
|
|||
*/
|
||||
public $dieOnFail = FALSE;
|
||||
|
||||
/**
|
||||
* The DrupalKernel instance used in the test.
|
||||
*
|
||||
* @var \Drupal\Core\DrupalKernel
|
||||
*/
|
||||
protected $kernel;
|
||||
|
||||
/**
|
||||
* The dependency injection container used in the test.
|
||||
*
|
||||
|
|
@ -622,20 +608,7 @@ abstract class TestBase {
|
|||
return $this->assertTrue($identical, $message, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that no errors have been logged to the PHP error.log thus far.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*
|
||||
* @see TestBase::prepareEnvironment()
|
||||
* @see _drupal_bootstrap_configuration()
|
||||
*/
|
||||
protected function assertNoErrorsLogged() {
|
||||
// Since PHP only creates the error.log file when an actual error is
|
||||
// triggered, it is sufficient to check whether the file exists.
|
||||
return $this->assertFalse(file_exists(DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log'), 'PHP error.log is empty.');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fire an assertion that is always positive.
|
||||
|
|
@ -884,9 +857,7 @@ abstract class TestBase {
|
|||
* @see drupal_valid_test_ua()
|
||||
*/
|
||||
private function prepareDatabasePrefix() {
|
||||
$suffix = mt_rand(1000, 1000000);
|
||||
$this->siteDirectory = 'sites/simpletest/' . $suffix;
|
||||
$this->databasePrefix = 'simpletest' . $suffix;
|
||||
$this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
|
||||
|
||||
// As soon as the database prefix is set, the test might start to execute.
|
||||
// All assertions as well as the SimpleTest batch operations are associated
|
||||
|
|
@ -914,9 +885,19 @@ abstract class TestBase {
|
|||
$connection_info = Database::getConnectionInfo('default');
|
||||
Database::renameConnection('default', 'simpletest_original_default');
|
||||
foreach ($connection_info as $target => $value) {
|
||||
$connection_info[$target]['prefix'] = $value['prefix']['default'] . $this->databasePrefix;
|
||||
$connection_info[$target]['prefix'] = array(
|
||||
'default' => $value['prefix']['default'] . $this->databasePrefix,
|
||||
);
|
||||
}
|
||||
Database::addConnectionInfo('default', 'default', $connection_info['default']);
|
||||
|
||||
// Additionally override global $databases, since the installer does not use
|
||||
// the Database connection info.
|
||||
// @see install_verify_database_settings()
|
||||
// @see install_database_errors()
|
||||
// @todo Fix installer to use Database connection info.
|
||||
global $databases;
|
||||
$databases['default']['default'] = $connection_info['default'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -957,9 +938,10 @@ abstract class TestBase {
|
|||
$language_interface = language(Language::TYPE_INTERFACE);
|
||||
|
||||
// When running the test runner within a test, back up the original database
|
||||
// prefix.
|
||||
if (DRUPAL_TEST_IN_CHILD_SITE) {
|
||||
// prefix and re-set the new/nested prefix in drupal_valid_test_ua().
|
||||
if (drupal_valid_test_ua()) {
|
||||
$this->originalPrefix = drupal_valid_test_ua();
|
||||
drupal_valid_test_ua($this->databasePrefix);
|
||||
}
|
||||
|
||||
// Backup current in-memory configuration.
|
||||
|
|
@ -999,16 +981,22 @@ abstract class TestBase {
|
|||
|
||||
// Create test directory ahead of installation so fatal errors and debug
|
||||
// information can be logged during installation process.
|
||||
file_prepare_directory($this->siteDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
|
||||
|
||||
// Prepare filesystem directory paths.
|
||||
$this->public_files_directory = $this->siteDirectory . '/files';
|
||||
$this->private_files_directory = $this->siteDirectory . '/private';
|
||||
$this->temp_files_directory = $this->siteDirectory . '/temp';
|
||||
$this->translation_files_directory = $this->siteDirectory . '/translations';
|
||||
// Use temporary files directory with the same prefix as the database.
|
||||
$this->public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
|
||||
$this->private_files_directory = $this->public_files_directory . '/private';
|
||||
$this->temp_files_directory = $this->private_files_directory . '/temp';
|
||||
$this->translation_files_directory = $this->public_files_directory . '/translations';
|
||||
|
||||
// Create the directories
|
||||
file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
|
||||
file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
|
||||
file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
|
||||
file_prepare_directory($this->translation_files_directory, FILE_CREATE_DIRECTORY);
|
||||
$this->generatedTestFiles = FALSE;
|
||||
|
||||
// Create and set new configuration directories.
|
||||
$this->prepareConfigDirectories();
|
||||
|
||||
// Unregister all custom stream wrappers of the parent site.
|
||||
// Availability of Drupal stream wrappers varies by test base class:
|
||||
// - UnitTestBase operates in a completely empty environment.
|
||||
|
|
@ -1052,31 +1040,53 @@ abstract class TestBase {
|
|||
\Drupal::setContainer($this->container);
|
||||
|
||||
// Unset globals.
|
||||
unset($GLOBALS['config_directories']);
|
||||
unset($GLOBALS['theme_key']);
|
||||
unset($GLOBALS['theme']);
|
||||
|
||||
// Log fatal errors.
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
|
||||
ini_set('error_log', $this->public_files_directory . '/error.log');
|
||||
|
||||
// Set the test information for use in other parts of Drupal.
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
$test_info['test_run_id'] = $this->databasePrefix;
|
||||
$test_info['in_child_site'] = FALSE;
|
||||
|
||||
// Change the database prefix.
|
||||
// All static variables need to be reset before the database prefix is
|
||||
// changed, since \Drupal\Core\Utility\CacheArray implementations attempt to
|
||||
// write back to persistent caches when they are destructed.
|
||||
$this->changeDatabasePrefix();
|
||||
|
||||
// Remove all configuration overrides.
|
||||
$GLOBALS['config'] = array();
|
||||
|
||||
// After preparing the environment and changing the database prefix, we are
|
||||
// in a valid test environment.
|
||||
drupal_valid_test_ua($this->databasePrefix);
|
||||
conf_path(FALSE, TRUE);
|
||||
|
||||
drupal_set_time_limit($this->timeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and set new configuration directories.
|
||||
*
|
||||
* The child site uses drupal_valid_test_ua() to adjust the config directory
|
||||
* paths to a test-prefix-specific directory within the public files
|
||||
* directory.
|
||||
*
|
||||
* @see config_get_config_directory()
|
||||
*/
|
||||
protected function prepareConfigDirectories() {
|
||||
$GLOBALS['config_directories'] = array();
|
||||
$this->configDirectories = array();
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) {
|
||||
// Assign the relative path to the global variable.
|
||||
$path = conf_path() . '/files/simpletest/' . substr($this->databasePrefix, 10) . '/config_' . $type;
|
||||
$GLOBALS['config_directories'][$type] = $path;
|
||||
// Ensure the directory can be created and is writeable.
|
||||
if (!install_ensure_config_directory($type)) {
|
||||
return FALSE;
|
||||
}
|
||||
// Provide the already resolved path for tests.
|
||||
$this->configDirectories[$type] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild \Drupal::getContainer().
|
||||
*
|
||||
|
|
@ -1093,11 +1103,11 @@ abstract class TestBase {
|
|||
* tests can invoke this workaround when requiring services from newly
|
||||
* enabled modules to be immediately available in the same request.
|
||||
*/
|
||||
protected function rebuildContainer($environment = 'testing') {
|
||||
protected function rebuildContainer() {
|
||||
// Preserve the request object after the container rebuild.
|
||||
$request = \Drupal::request();
|
||||
|
||||
$this->kernel = new DrupalKernel($environment, drupal_classloader(), FALSE);
|
||||
$this->kernel = new DrupalKernel('testing', drupal_classloader(), FALSE);
|
||||
$this->kernel->boot();
|
||||
// DrupalKernel replaces the container in \Drupal::getContainer() with a
|
||||
// different object, so we need to replace the instance on this test class.
|
||||
|
|
@ -1159,12 +1169,8 @@ abstract class TestBase {
|
|||
}
|
||||
}
|
||||
|
||||
// In case a fatal error occurred that was not in the test process read the
|
||||
// log to pick up any fatal errors.
|
||||
simpletest_log_read($this->testId, $this->databasePrefix, get_class($this));
|
||||
|
||||
// Delete test site directory.
|
||||
file_unmanaged_delete_recursive($this->siteDirectory, array($this, 'filePreDeleteCallback'));
|
||||
// Delete temporary files directory.
|
||||
file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10), array($this, 'filePreDeleteCallback'));
|
||||
|
||||
// Restore original database connection.
|
||||
Database::removeConnection('default');
|
||||
|
|
@ -1193,13 +1199,19 @@ abstract class TestBase {
|
|||
\Drupal::setContainer($this->originalContainer);
|
||||
$GLOBALS['config_directories'] = $this->originalConfigDirectories;
|
||||
|
||||
// Re-initialize original stream wrappers of the parent site.
|
||||
// This must happen after static variables have been reset and the original
|
||||
// container and $config_directories are restored, as simpletest_log_read()
|
||||
// uses the public stream wrapper to locate the error.log.
|
||||
file_get_stream_wrappers();
|
||||
|
||||
// In case a fatal error occurred that was not in the test process read the
|
||||
// log to pick up any fatal errors.
|
||||
simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE);
|
||||
|
||||
if (isset($this->originalPrefix)) {
|
||||
drupal_valid_test_ua($this->originalPrefix);
|
||||
}
|
||||
else {
|
||||
drupal_valid_test_ua(FALSE);
|
||||
}
|
||||
conf_path(TRUE, TRUE);
|
||||
|
||||
// Restore original shutdown callbacks.
|
||||
$callbacks = &drupal_register_shutdown_function();
|
||||
|
|
|
|||
|
|
@ -28,13 +28,6 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
*/
|
||||
public static $modules = array('simpletest');
|
||||
|
||||
/**
|
||||
* The path to the shared trigger file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $sharedTriggerFile;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Broken SimpleTest method',
|
||||
|
|
@ -45,20 +38,15 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
|
||||
function setUp() {
|
||||
// If the test is being run from the main site, set up normally.
|
||||
if (!$this->isInChildSite()) {
|
||||
if (!drupal_valid_test_ua()) {
|
||||
parent::setUp();
|
||||
|
||||
$this->sharedTriggerFile = $this->public_files_directory . '/trigger';
|
||||
|
||||
// Create and log in user.
|
||||
$admin_user = $this->drupalCreateUser(array('administer unit tests'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
// If the test is being run from within simpletest, set up the broken test.
|
||||
else {
|
||||
$this->sharedTriggerFile = $this->originalFileDirectory . '/trigger';
|
||||
|
||||
if (file_get_contents($this->sharedTriggerFile) === 'setup') {
|
||||
if (file_get_contents($this->originalFileDirectory . '/simpletest/trigger') === 'setup') {
|
||||
throw new \Exception('Broken setup');
|
||||
}
|
||||
$this->pass('The setUp() method has run.');
|
||||
|
|
@ -67,13 +55,13 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
|
||||
function tearDown() {
|
||||
// If the test is being run from the main site, tear down normally.
|
||||
if (!$this->isInChildSite()) {
|
||||
unlink($this->sharedTriggerFile);
|
||||
if (!drupal_valid_test_ua()) {
|
||||
unlink($this->originalFileDirectory . '/simpletest/trigger');
|
||||
parent::tearDown();
|
||||
}
|
||||
// If the test is being run from within simpletest, output a message.
|
||||
else {
|
||||
if (file_get_contents($this->sharedTriggerFile) === 'teardown') {
|
||||
if (file_get_contents($this->originalFileDirectory . '/simpletest/trigger') === 'teardown') {
|
||||
throw new \Exception('Broken teardown');
|
||||
}
|
||||
$this->pass('The tearDown() method has run.');
|
||||
|
|
@ -86,9 +74,9 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
function testMethod() {
|
||||
// If the test is being run from the main site, run it again from the web
|
||||
// interface within the simpletest child site.
|
||||
if (!$this->isInChildSite()) {
|
||||
if (!drupal_valid_test_ua()) {
|
||||
// Verify that a broken setUp() method is caught.
|
||||
file_put_contents($this->sharedTriggerFile, 'setup');
|
||||
file_put_contents($this->originalFileDirectory . '/simpletest/trigger', 'setup');
|
||||
$edit['Drupal\simpletest\Tests\BrokenSetUpTest'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests'));
|
||||
$this->assertRaw('Broken setup');
|
||||
|
|
@ -99,7 +87,7 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
$this->assertNoRaw('The tearDown() method has run.');
|
||||
|
||||
// Verify that a broken tearDown() method is caught.
|
||||
file_put_contents($this->sharedTriggerFile, 'teardown');
|
||||
file_put_contents($this->originalFileDirectory . '/simpletest/trigger', 'teardown');
|
||||
$edit['Drupal\simpletest\Tests\BrokenSetUpTest'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests'));
|
||||
$this->assertNoRaw('Broken setup');
|
||||
|
|
@ -110,7 +98,7 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
$this->assertNoRaw('The tearDown() method has run.');
|
||||
|
||||
// Verify that a broken test method is caught.
|
||||
file_put_contents($this->sharedTriggerFile, 'test');
|
||||
file_put_contents($this->originalFileDirectory . '/simpletest/trigger', 'test');
|
||||
$edit['Drupal\simpletest\Tests\BrokenSetUpTest'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests'));
|
||||
$this->assertNoRaw('Broken setup');
|
||||
|
|
@ -122,7 +110,7 @@ class BrokenSetUpTest extends WebTestBase {
|
|||
}
|
||||
// If the test is being run from within simpletest, output a message.
|
||||
else {
|
||||
if (file_get_contents($this->sharedTriggerFile) === 'test') {
|
||||
if (file_get_contents($this->originalFileDirectory . '/simpletest/trigger') === 'test') {
|
||||
throw new \Exception('Broken test');
|
||||
}
|
||||
$this->pass('The test method has run.');
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class MissingCheckedRequirementsTest extends WebTestBase {
|
|||
* Overrides checkRequirements().
|
||||
*/
|
||||
protected function checkRequirements() {
|
||||
if ($this->isInChildSite()) {
|
||||
if (drupal_valid_test_ua()) {
|
||||
return array(
|
||||
'Test is not allowed to run.'
|
||||
);
|
||||
|
|
@ -53,7 +53,7 @@ class MissingCheckedRequirementsTest extends WebTestBase {
|
|||
protected function testCheckRequirements() {
|
||||
// If this is the main request, run the web test script and then assert
|
||||
// that the child tests did not run.
|
||||
if (!$this->isInChildSite()) {
|
||||
if (!drupal_valid_test_ua()) {
|
||||
// Run this test from web interface.
|
||||
$edit['Drupal\simpletest\Tests\MissingCheckedRequirementsTest'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests'));
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class SimpleTestTest extends WebTestBase {
|
|||
}
|
||||
|
||||
function setUp() {
|
||||
if (!$this->isInChildSite()) {
|
||||
if (!$this->inCURL()) {
|
||||
parent::setUp();
|
||||
// Create and log in an admin user.
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer unit tests')));
|
||||
|
|
@ -54,7 +54,7 @@ class SimpleTestTest extends WebTestBase {
|
|||
* Test the internal browsers functionality.
|
||||
*/
|
||||
function testInternalBrowser() {
|
||||
if (!$this->isInChildSite()) {
|
||||
if (!$this->inCURL()) {
|
||||
// Retrieve the test page and check its title and headers.
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertTrue($this->drupalGetHeader('Date'), 'An HTTP header was received.');
|
||||
|
|
@ -91,12 +91,10 @@ class SimpleTestTest extends WebTestBase {
|
|||
$headers = $this->drupalGetHeaders(TRUE);
|
||||
$this->assertEqual(count($headers), 2, 'Simpletest stopped following redirects after the first one.');
|
||||
|
||||
// Remove the Simpletest private key file so we can test the protection
|
||||
// Remove the Simpletest settings.php so we can test the protection
|
||||
// against requests that forge a valid testing user agent to gain access
|
||||
// to the installer.
|
||||
// @see drupal_valid_test_ua()
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink($this->siteDirectory . '/.htkey');
|
||||
drupal_unlink($this->public_files_directory . '/settings.php');
|
||||
global $base_url;
|
||||
$this->drupalGet(url($base_url . '/core/install.php', array('external' => TRUE, 'absolute' => TRUE)));
|
||||
$this->assertResponse(403, 'Cannot access install.php.');
|
||||
|
|
@ -107,7 +105,7 @@ class SimpleTestTest extends WebTestBase {
|
|||
* Test validation of the User-Agent header we use to perform test requests.
|
||||
*/
|
||||
function testUserAgentValidation() {
|
||||
if (!$this->isInChildSite()) {
|
||||
if (!$this->inCURL()) {
|
||||
global $base_url;
|
||||
$system_path = $base_url . '/' . drupal_get_path('module', 'system');
|
||||
$HTTP_path = $system_path .'/tests/http.php?q=node';
|
||||
|
|
@ -149,7 +147,7 @@ class SimpleTestTest extends WebTestBase {
|
|||
$this->valid_permission = 'access content';
|
||||
$this->invalid_permission = 'invalid permission';
|
||||
|
||||
if ($this->isInChildSite()) {
|
||||
if ($this->inCURL()) {
|
||||
// Only run following code if this test is running itself through a CURL
|
||||
// request.
|
||||
$this->stubTest();
|
||||
|
|
@ -337,4 +335,10 @@ class SimpleTestTest extends WebTestBase {
|
|||
return trim(html_entity_decode(strip_tags($element->asXML())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the test is being run from inside a CURL request.
|
||||
*/
|
||||
function inCURL() {
|
||||
return (bool) drupal_valid_test_ua();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ use Drupal\Core\Database\ConnectionNotDefinedException;
|
|||
*/
|
||||
abstract class UnitTestBase extends TestBase {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $configDirectories;
|
||||
|
||||
/**
|
||||
* Constructor for UnitTestBase.
|
||||
*/
|
||||
|
|
@ -36,7 +41,6 @@ abstract class UnitTestBase extends TestBase {
|
|||
* setUp() method.
|
||||
*/
|
||||
protected function setUp() {
|
||||
file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
|
||||
$this->settingsSet('file_public_path', $this->public_files_directory);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -767,78 +767,46 @@ abstract class WebTestBase extends TestBase {
|
|||
$batch = &batch_get();
|
||||
$batch = array();
|
||||
|
||||
// Get parameters for install_drupal() before removing global variables.
|
||||
$parameters = $this->installParameters();
|
||||
|
||||
// Prepare installer settings that are not install_drupal() parameters.
|
||||
// Copy and prepare an actual settings.php, so as to resemble a regular
|
||||
// installation.
|
||||
// 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');
|
||||
|
||||
// All file system paths are created by System module during installation.
|
||||
// @see system_requirements()
|
||||
// @see TestBase::prepareEnvironment()
|
||||
$settings['settings']['file_public_path'] = (object) array(
|
||||
'value' => $this->public_files_directory,
|
||||
'required' => TRUE,
|
||||
);
|
||||
// Add the parent profile's search path to the child site's search paths.
|
||||
// @see drupal_system_listing()
|
||||
$settings['conf']['simpletest.settings']['parent_profile'] = (object) array(
|
||||
'value' => $this->originalProfile,
|
||||
'required' => TRUE,
|
||||
);
|
||||
$this->writeSettings($settings);
|
||||
|
||||
// Since Drupal is bootstrapped already, install_begin_request() will not
|
||||
// bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to
|
||||
// reload the newly written custom settings.php manually.
|
||||
drupal_settings_initialize();
|
||||
$this->settingsSet('file_public_path', $this->public_files_directory);
|
||||
$GLOBALS['config']['system.file']['path']['private'] = $this->private_files_directory;
|
||||
$GLOBALS['config']['system.file']['path']['temporary'] = $this->temp_files_directory;
|
||||
$GLOBALS['config']['locale.settings']['translation']['path'] = $this->translation_files_directory;
|
||||
|
||||
// Execute the non-interactive installer.
|
||||
require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
|
||||
$this->settingsSet('cache', array('default' => 'cache.backend.memory'));
|
||||
$parameters = $this->installParameters();
|
||||
install_drupal($parameters);
|
||||
|
||||
// Import new settings.php written by the installer.
|
||||
drupal_settings_initialize();
|
||||
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.
|
||||
// TestBase::restoreEnvironment() will delete the entire site directory.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777);
|
||||
// Set the install_profile so that web requests to the requests to the child
|
||||
// site have the correct profile.
|
||||
$settings = array(
|
||||
'settings' => array(
|
||||
'install_profile' => (object) array(
|
||||
'value' => $this->profile,
|
||||
'required' => TRUE,
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->writeSettings($settings);
|
||||
// Override install profile in Settings to so the correct profile is used by
|
||||
// tests.
|
||||
$this->settingsSet('install_profile', $this->profile);
|
||||
|
||||
$this->settingsSet('cache', array());
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Manually create and configure private and temporary files directories.
|
||||
// While these could be preset/enforced in settings.php like the public
|
||||
// files directory above, some tests expect them to be configurable in the
|
||||
// UI. If declared in settings.php, they would no longer be configurable.
|
||||
file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
|
||||
file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
|
||||
\Drupal::config('system.file')
|
||||
->set('path.private', $this->private_files_directory)
|
||||
->set('path.temporary', $this->temp_files_directory)
|
||||
->save();
|
||||
|
||||
// Manually configure the test mail collector implementation to prevent
|
||||
// tests from sending out e-mails and collect them in state instead.
|
||||
// While this should be enforced via settings.php prior to installation,
|
||||
// some tests expect to be able to test mail system implementations.
|
||||
\Drupal::config('system.mail')
|
||||
->set('interface.default', 'Drupal\Core\Mail\TestMailCollector')
|
||||
->save();
|
||||
|
||||
// Restore the original Simpletest batch.
|
||||
$batch = &batch_get();
|
||||
$batch = $this->originalBatch;
|
||||
|
||||
// Set path variables.
|
||||
|
||||
// Set 'parent_profile' of simpletest to add the parent profile's
|
||||
// search path to the child site's search paths.
|
||||
// @see drupal_system_listing()
|
||||
\Drupal::config('simpletest.settings')->set('parent_profile', $this->originalProfile)->save();
|
||||
|
||||
// Collect modules to install.
|
||||
$class = get_class($this);
|
||||
$modules = array();
|
||||
|
|
@ -855,18 +823,22 @@ abstract class WebTestBase extends TestBase {
|
|||
$this->rebuildContainer();
|
||||
}
|
||||
|
||||
// Like DRUPAL_BOOTSTRAP_CONFIGURATION above, any further bootstrap phases
|
||||
// are not re-executed by the installer, as Drupal is bootstrapped already.
|
||||
// Reset/rebuild all data structures after enabling the modules, primarily
|
||||
// to synchronize all data structures and caches between the test runner and
|
||||
// the child site.
|
||||
// Affects e.g. file_get_stream_wrappers().
|
||||
// @see _drupal_bootstrap_code()
|
||||
// @see _drupal_bootstrap_full()
|
||||
// @todo Test-specific setUp() methods may set up further fixtures; find a
|
||||
// way to execute this after setUp() is done, or to eliminate it entirely.
|
||||
// Reset/rebuild all data structures after enabling the modules.
|
||||
$this->resetAll();
|
||||
|
||||
// Now make sure that the file path configurations are saved. This is done
|
||||
// after we install the modules to override default values.
|
||||
\Drupal::config('system.file')
|
||||
->set('path.private', $this->private_files_directory)
|
||||
->set('path.temporary', $this->temp_files_directory)
|
||||
->save();
|
||||
\Drupal::config('locale.settings')
|
||||
->set('translation.path', $this->translation_files_directory)
|
||||
->save();
|
||||
|
||||
// Use the test mail class instead of the default mail handler class.
|
||||
\Drupal::config('system.mail')->set('interface.default', 'Drupal\Core\Mail\TestMailCollector')->save();
|
||||
|
||||
// Temporary fix so that when running from run-tests.sh we don't get an
|
||||
// empty current path which would indicate we're on the home page.
|
||||
$path = current_path();
|
||||
|
|
@ -923,29 +895,40 @@ abstract class WebTestBase extends TestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Rewrites the settings.php file of the test site.
|
||||
* Writes a test-specific settings.php file for the child site.
|
||||
*
|
||||
* @param array $settings
|
||||
* An array of settings to write out, in the format expected by
|
||||
* drupal_rewrite_settings().
|
||||
* The child site loads this after the parent site's settings.php, so settings
|
||||
* here override those.
|
||||
*
|
||||
* @param $settings An array of settings to write out, in the format expected
|
||||
* by drupal_rewrite_settings().
|
||||
*
|
||||
* @see _drupal_load_test_overrides()
|
||||
* @see drupal_rewrite_settings()
|
||||
*/
|
||||
protected function writeSettings(array $settings) {
|
||||
protected function writeSettings($settings) {
|
||||
// drupal_rewrite_settings() sets the in-memory global variables in addition
|
||||
// to writing the file. We'll want to restore the original globals.
|
||||
foreach (array_keys($settings) as $variable_name) {
|
||||
$original_globals[$variable_name] = isset($GLOBALS[$variable_name]) ? $GLOBALS[$variable_name] : NULL;
|
||||
}
|
||||
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
$filename = $this->siteDirectory . '/settings.php';
|
||||
// system_requirements() removes write permissions from settings.php
|
||||
// whenever it is invoked.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod($filename, 0666);
|
||||
$filename = $this->public_files_directory . '/settings.php';
|
||||
file_put_contents($filename, "<?php\n");
|
||||
drupal_rewrite_settings($settings, $filename);
|
||||
|
||||
// Restore the original globals.
|
||||
foreach ($original_globals as $variable_name => $value) {
|
||||
$GLOBALS[$variable_name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues custom translations to be written to settings.php.
|
||||
* Sets custom translations to the settings object and queues them to writing.
|
||||
*
|
||||
* Use WebTestBase::writeCustomTranslations() to apply and write the queued
|
||||
* translations.
|
||||
* In order for those custom translations to persist (being written in test
|
||||
* site's settings.php) make sure to also call self::writeCustomTranslations()
|
||||
*
|
||||
* @param string $langcode
|
||||
* The langcode to add translations for.
|
||||
|
|
@ -958,56 +941,32 @@ abstract class WebTestBase extends TestBase {
|
|||
* 'Long month name' => array('March' => 'marzo'),
|
||||
* );
|
||||
* @endcode
|
||||
* Pass an empty array to remove all existing custom translations for the
|
||||
* given $langcode.
|
||||
*/
|
||||
protected function addCustomTranslations($langcode, array $values) {
|
||||
// If $values is empty, then the test expects all custom translations to be
|
||||
// cleared.
|
||||
if (empty($values)) {
|
||||
$this->customTranslations[$langcode] = array();
|
||||
}
|
||||
// Otherwise, $values are expected to be merged into previously passed
|
||||
// values, while retaining keys that are not explicitly set.
|
||||
else {
|
||||
foreach ($values as $context => $translations) {
|
||||
foreach ($translations as $original => $translation) {
|
||||
$this->customTranslations[$langcode][$context][$original] = $translation;
|
||||
}
|
||||
$this->settingsSet('locale_custom_strings_' . $langcode, $values);
|
||||
foreach ($values as $key => $translations) {
|
||||
foreach ($translations as $label => $value) {
|
||||
$this->customTranslations['locale_custom_strings_' . $langcode][$key][$label] = (object) array(
|
||||
'value' => $value,
|
||||
'required' => TRUE,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes custom translations to the test site's settings.php.
|
||||
*
|
||||
* Use TestBase::addCustomTranslations() to queue custom translations before
|
||||
* calling this method.
|
||||
* Writes custom translations to test site's settings.php.
|
||||
*/
|
||||
protected function writeCustomTranslations() {
|
||||
$settings = array();
|
||||
foreach ($this->customTranslations as $langcode => $values) {
|
||||
$settings_key = 'locale_custom_strings_' . $langcode;
|
||||
|
||||
// Update in-memory settings directly.
|
||||
$this->settingsSet($settings_key, $values);
|
||||
|
||||
$settings['settings'][$settings_key] = (object) array(
|
||||
'value' => $values,
|
||||
'required' => TRUE,
|
||||
);
|
||||
}
|
||||
// Only rewrite settings if there are any translation changes to write.
|
||||
if (!empty($settings)) {
|
||||
$this->writeSettings($settings);
|
||||
}
|
||||
$this->writeSettings(array('settings' => $this->customTranslations));
|
||||
$this->customTranslations = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\TestBase::rebuildContainer().
|
||||
*/
|
||||
protected function rebuildContainer($environment = 'prod') {
|
||||
parent::rebuildContainer($environment);
|
||||
protected function rebuildContainer() {
|
||||
parent::rebuildContainer();
|
||||
// Make sure the url generator has a request object, otherwise calls to
|
||||
// $this->drupalGet() will fail.
|
||||
$this->prepareRequestForGenerator();
|
||||
|
|
@ -1047,8 +1006,8 @@ abstract class WebTestBase extends TestBase {
|
|||
// Clear the tag cache.
|
||||
drupal_static_reset('Drupal\Core\Cache\CacheBackendInterface::tagCache');
|
||||
|
||||
$this->container->get('config.factory')->reset();
|
||||
$this->container->get('state')->resetCache();
|
||||
\Drupal::service('config.factory')->reset();
|
||||
\Drupal::state()->resetCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1311,21 +1270,6 @@ abstract class WebTestBase extends TestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the test is being executed from within a test site.
|
||||
*
|
||||
* Mainly used by recursive tests (i.e. to test the testing framework).
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if this test was instantiated in a request within the test site,
|
||||
* FALSE otherwise.
|
||||
*
|
||||
* @see _drupal_bootstrap_configuration()
|
||||
*/
|
||||
protected function isInChildSite() {
|
||||
return DRUPAL_TEST_IN_CHILD_SITE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse content returned from curlExec using DOM and SimpleXML.
|
||||
*
|
||||
|
|
@ -1369,18 +1313,10 @@ abstract class WebTestBase extends TestBase {
|
|||
protected function drupalGet($path, array $options = array(), array $headers = array()) {
|
||||
$options['absolute'] = TRUE;
|
||||
|
||||
// The URL generator service is not necessarily available yet; e.g., in
|
||||
// interactive installer tests.
|
||||
if ($this->container->has('url_generator')) {
|
||||
$url = $this->container->get('url_generator')->generateFromPath($path, $options);
|
||||
}
|
||||
else {
|
||||
$url = $this->getAbsoluteUrl($path);
|
||||
}
|
||||
|
||||
// We re-using a CURL connection here. If that connection still has certain
|
||||
// options set, it might change the GET into a POST. Make sure we clear out
|
||||
// previous options.
|
||||
$url = $this->container->get('url_generator')->generateFromPath($path, $options);
|
||||
$out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $url, CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers));
|
||||
// Ensure that any changes to variables in the other thread are picked up.
|
||||
$this->refreshVariables();
|
||||
|
|
@ -1900,28 +1836,6 @@ abstract class WebTestBase extends TestBase {
|
|||
return implode('&', $post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a nested array into a flat array suitable for WebTestBase::drupalPostForm().
|
||||
*
|
||||
* @param array $values
|
||||
* A multi-dimensional form values array to convert.
|
||||
*
|
||||
* @return array
|
||||
* The flattened $edit array suitable for WebTestBase::drupalPostForm().
|
||||
*/
|
||||
protected function translatePostValues(array $values) {
|
||||
$edit = array();
|
||||
// The easiest and most straightforward way to translate values suitable for
|
||||
// WebTestBase::drupalPostForm() is to actually build the POST data string
|
||||
// and convert the resulting key/value pairs back into a flat array.
|
||||
$query = http_build_query($values);
|
||||
foreach (explode('&', $query) as $item) {
|
||||
list($key, $value) = explode('=', $item);
|
||||
$edit[urldecode($key)] = urldecode($value);
|
||||
}
|
||||
return $edit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs cron in the Drupal installed by Simpletest.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,6 +5,18 @@
|
|||
* Hooks provided by the SimpleTest module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Global variable that holds information about the tests being run.
|
||||
*
|
||||
* An array, with the following keys:
|
||||
* - 'test_run_id': the ID of the test being run, in the form 'simpletest_%"
|
||||
* - 'in_child_site': TRUE if the current request is a cURL request from
|
||||
* the parent site.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
global $drupal_test_info;
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
|
|
|
|||
|
|
@ -58,28 +58,6 @@ function simpletest_requirements($phase) {
|
|||
$requirements['php_memory_limit']['description'] = t('The testing framework requires the PHP memory limit to be at least %memory_minimum_limit. The current value is %memory_limit. <a href="@url">Follow these steps to continue</a>.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT, '@url' => 'http://drupal.org/node/207036'));
|
||||
}
|
||||
|
||||
$site_directory = 'sites/simpletest';
|
||||
if (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $site_directory, FILE_EXIST|FILE_READABLE|FILE_WRITABLE|FILE_EXECUTABLE, 'dir')) {
|
||||
$requirements['simpletest_site_directory'] = array(
|
||||
'title' => t('Simpletest site directory'),
|
||||
'value' => is_dir(DRUPAL_ROOT . '/' . $site_directory) ? t('Not writable') : t('Missing'),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
'description' => t('The testing framework requires the !sites-simpletest directory to exist and be writable in order to run tests.', array(
|
||||
'!sites-simpletest' => '<code>./' . check_plain($site_directory) . '</code>',
|
||||
)),
|
||||
);
|
||||
}
|
||||
elseif (!file_save_htaccess(DRUPAL_ROOT . '/' . $site_directory, FALSE)) {
|
||||
$requirements['simpletest_site_directory'] = array(
|
||||
'title' => t('Simpletest site directory'),
|
||||
'value' => t('Not protected'),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
'description' => t('The file !file does not exist and could not be created automatically, which poses a security risk. Ensure that the directory is writable.', array(
|
||||
'!file' => '<code>./' . check_plain($site_directory) . '/.htaccess</code>',
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
|
|
@ -179,12 +157,8 @@ function simpletest_schema() {
|
|||
* Implements hook_uninstall().
|
||||
*/
|
||||
function simpletest_uninstall() {
|
||||
// Do not clean the environment in case the Simpletest module is uninstalled
|
||||
// in a (recursive) test for itself, since simpletest_clean_environment()
|
||||
// would also delete the test site of the parent test process.
|
||||
if (!DRUPAL_TEST_IN_CHILD_SITE) {
|
||||
simpletest_clean_environment();
|
||||
}
|
||||
// Delete verbose test output and any other testing framework files.
|
||||
simpletest_clean_database();
|
||||
|
||||
// Remove generated files.
|
||||
file_unmanaged_delete_recursive('public://simpletest');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -383,16 +383,18 @@ function simpletest_last_test_get($test_id) {
|
|||
*
|
||||
* @param $test_id
|
||||
* The test ID to which the log relates.
|
||||
* @param $database_prefix
|
||||
* @param $prefix
|
||||
* The database prefix to which the log relates.
|
||||
* @param $test_class
|
||||
* The test class to which the log relates.
|
||||
*
|
||||
* @param $during_test
|
||||
* Indicates that the current file directory path is a temporary file
|
||||
* file directory used during testing.
|
||||
* @return
|
||||
* Found any entries in log.
|
||||
*/
|
||||
function simpletest_log_read($test_id, $database_prefix, $test_class) {
|
||||
$log = DRUPAL_ROOT . '/sites/simpletest/' . substr($database_prefix, 10) . '/error.log';
|
||||
function simpletest_log_read($test_id, $prefix, $test_class, $during_test = FALSE) {
|
||||
$log = 'public://' . ($during_test ? '' : '/simpletest/' . substr($prefix, 10)) . '/error.log';
|
||||
$found = FALSE;
|
||||
if (file_exists($log)) {
|
||||
foreach (file($log) as $line) {
|
||||
|
|
@ -646,11 +648,11 @@ function simpletest_clean_database() {
|
|||
*/
|
||||
function simpletest_clean_temporary_directories() {
|
||||
$count = 0;
|
||||
if (is_dir(DRUPAL_ROOT . '/sites/simpletest')) {
|
||||
$files = scandir(DRUPAL_ROOT . '/sites/simpletest');
|
||||
if (is_dir('public://simpletest')) {
|
||||
$files = scandir('public://simpletest');
|
||||
foreach ($files as $file) {
|
||||
if ($file[0] != '.') {
|
||||
$path = DRUPAL_ROOT . '/sites/simpletest/' . $file;
|
||||
$path = 'public://simpletest/' . $file;
|
||||
if (is_dir($path) && (is_numeric($file) || strpos($file, 'config_simpletest') !== FALSE)) {
|
||||
file_unmanaged_delete_recursive($path, array('Drupal\simpletest\TestBase', 'filePreDeleteCallback'));
|
||||
$count++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ class FormValuesTest extends AjaxTestBase {
|
|||
}
|
||||
|
||||
// Verify that AJAX elements with invalid callbacks return error code 500.
|
||||
// Ensure the test error log is empty before these tests.
|
||||
$this->assertNoErrorsLogged();
|
||||
foreach (array('null', 'empty', 'nonexistent') as $key) {
|
||||
$element_name = 'select_' . $key . '_callback';
|
||||
$edit = array(
|
||||
|
|
@ -63,8 +61,5 @@ class FormValuesTest extends AjaxTestBase {
|
|||
$commands = $this->drupalPostAjaxForm('ajax_forms_test_get_form', $edit, $element_name);
|
||||
$this->assertResponse(500);
|
||||
}
|
||||
// The exceptions are expected. Do not interpret them as a test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ namespace Drupal\system\Tests\DrupalKernel;
|
|||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage;
|
||||
use Drupal\Component\PhpStorage\FileReadOnlyStorage;
|
||||
use Drupal\simpletest\DrupalUnitTestBase;
|
||||
use Drupal\simpletest\UnitTestBase;
|
||||
|
||||
/**
|
||||
* Tests compilation of the DIC.
|
||||
*/
|
||||
class DrupalKernelTest extends DrupalUnitTestBase {
|
||||
class DrupalKernelTest extends UnitTestBase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
|
|
@ -26,13 +26,7 @@ class DrupalKernelTest extends DrupalUnitTestBase {
|
|||
}
|
||||
|
||||
function setUp() {
|
||||
// DrupalKernel relies on global $config_directories and requires those
|
||||
// directories to exist. Therefore, create the directories, but do not
|
||||
// invoke DrupalUnitTestBase::setUp(), since that would set up further
|
||||
// environment aspects, which would distort this test, because it tests
|
||||
// the DrupalKernel (re-)building itself.
|
||||
$this->prepareConfigDirectories();
|
||||
|
||||
parent::setUp();
|
||||
$this->settingsSet('php_storage', array('service_container' => array(
|
||||
'bin' => 'service_container',
|
||||
'class' => 'Drupal\Component\PhpStorage\MTimeProtectedFileStorage',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\system\Tests\InstallerTest;
|
||||
|
||||
/**
|
||||
|
|
@ -15,11 +16,11 @@ use Drupal\system\Tests\InstallerTest;
|
|||
class InstallerTranslationTest extends InstallerTest {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
* Whether the installer has completed.
|
||||
*
|
||||
* @var string
|
||||
* @var bool
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
protected $isInstalled = FALSE;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
|
|
@ -29,34 +30,104 @@ class InstallerTranslationTest extends InstallerTest {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides InstallerTest::setUpLanguage().
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
parent::setUpLanguage();
|
||||
// After selecting a different language than English, all following screens
|
||||
// should be translated already.
|
||||
// @todo Instead of actually downloading random translations that cannot be
|
||||
// asserted, write and supply a German translation file. Until then, take
|
||||
// over whichever string happens to be there, but ensure that the English
|
||||
// string no longer appears.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$string = (string) current($elements);
|
||||
$this->assertNotEqual($string, 'Save and continue');
|
||||
$this->translations['Save and continue'] = $string;
|
||||
}
|
||||
protected function setUp() {
|
||||
$this->isInstalled = FALSE;
|
||||
|
||||
/**
|
||||
* Overrides InstallerTest::setUpConfirm().
|
||||
*/
|
||||
protected function setUpConfirm() {
|
||||
// We don't know the translated link text of "Visit your new site", but
|
||||
// luckily, there is only one link.
|
||||
$elements = $this->xpath('//a');
|
||||
$string = (string) current($elements);
|
||||
$this->assertNotEqual($string, 'Visit your new site');
|
||||
$this->translations['Visit your new site'] = $string;
|
||||
parent::setUpConfirm();
|
||||
|
||||
$settings['conf_path'] = (object) array(
|
||||
'value' => $this->public_files_directory,
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['config_directories'] = (object) array(
|
||||
'value' => array(),
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['config']['system.file'] = (object) array(
|
||||
'value' => array(
|
||||
'path' => array(
|
||||
'private' => $this->private_files_directory,
|
||||
'temporary' => $this->temp_files_directory,
|
||||
),
|
||||
),
|
||||
'required' => TRUE,
|
||||
);
|
||||
// Add the translations directory so we can retrieve German translations.
|
||||
$settings['config']['locale.settings'] = (object) array(
|
||||
'value' => array(
|
||||
'translation' => array(
|
||||
'path' => drupal_get_path('module', 'simpletest') . '/files/translations',
|
||||
),
|
||||
),
|
||||
'required' => TRUE,
|
||||
);
|
||||
$this->writeSettings($settings);
|
||||
|
||||
// Submit the installer with German language.
|
||||
$edit = array(
|
||||
'langcode' => 'de',
|
||||
);
|
||||
$this->drupalPostForm($GLOBALS['base_url'] . '/core/install.php', $edit, 'Save and continue');
|
||||
|
||||
// On the following page where installation profile is being selected the
|
||||
// interface should be already translated, so there is no "Set up database"
|
||||
// text anymore.
|
||||
$this->assertNoText('Set up database', '"Set up database" string was not found.');
|
||||
|
||||
// After this assertion all we needed to test is tested, but the test
|
||||
// expects the installation to succeed. If the test would finish here, an
|
||||
// exception would occur. That is why the full installation has to be
|
||||
// finished in the further steps.
|
||||
|
||||
// Get the "Save and continue" submit button translated value from the
|
||||
// translated interface.
|
||||
$submit_value = (string) current($this->xpath('//input[@type="submit"]/@value'));
|
||||
$this->assertNotEqual($submit_value, 'Save and continue');
|
||||
|
||||
// Submit the Standard profile installation.
|
||||
$edit = array(
|
||||
'profile' => 'standard',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, $submit_value);
|
||||
|
||||
// Submit the next step.
|
||||
$this->drupalPostForm(NULL, array(), $submit_value);
|
||||
|
||||
// Reload config directories.
|
||||
include $this->public_files_directory . '/settings.php';
|
||||
foreach ($config_directories as $type => $path) {
|
||||
$GLOBALS['config_directories'][$type] = $path;
|
||||
}
|
||||
$this->rebuildContainer();
|
||||
|
||||
\Drupal::config('system.file')
|
||||
->set('path.private', $this->private_files_directory)
|
||||
->set('path.temporary', $this->temp_files_directory)
|
||||
->save();
|
||||
\Drupal::config('locale.settings')
|
||||
->set('translation.path', $this->translation_files_directory)
|
||||
->save();
|
||||
|
||||
// Submit site configuration form.
|
||||
$this->drupalPostForm(NULL, array(
|
||||
'site_mail' => 'admin@test.de',
|
||||
'account[name]' => 'admin',
|
||||
'account[mail]' => 'admin@test.de',
|
||||
'account[pass][pass1]' => '123',
|
||||
'account[pass][pass2]' => '123',
|
||||
'site_default_country' => 'DE',
|
||||
), $submit_value);
|
||||
|
||||
// Use the test mail class instead of the default mail handler class.
|
||||
\Drupal::config('system.mail')->set('interface.default', 'Drupal\Core\Mail\TestMailCollector')->save();
|
||||
|
||||
// When running from run-tests.sh we don't get an empty current path which
|
||||
// would indicate we're on the home page.
|
||||
$path = current_path();
|
||||
if (empty($path)) {
|
||||
_current_path('run-tests');
|
||||
}
|
||||
|
||||
$this->isInstalled = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,60 +8,13 @@
|
|||
namespace Drupal\system\Tests;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Session\UserSession;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Allows testing of the interactive installer.
|
||||
*
|
||||
* @todo Move majority of code into new Drupal\simpletest\InstallerTestBase.
|
||||
*/
|
||||
class InstallerTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* 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 = array();
|
||||
|
||||
/**
|
||||
* The language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'en';
|
||||
|
||||
/**
|
||||
* The installation profile to install.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'minimal';
|
||||
|
||||
/**
|
||||
* Additional parameters to use for installer screens.
|
||||
*
|
||||
* @see WebTestBase::installParameters()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters = array();
|
||||
|
||||
/**
|
||||
* A string translation map used for translated installer screens.
|
||||
*
|
||||
* Keys are English strings, values are translated strings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $translations = array(
|
||||
'Save and continue' => 'Save and continue',
|
||||
'Visit your new site' => 'Visit your new site',
|
||||
);
|
||||
|
||||
/**
|
||||
* Whether the installer has completed.
|
||||
*
|
||||
|
|
@ -77,74 +30,57 @@ class InstallerTest extends WebTestBase {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides WebTestBase::setUp().
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->isInstalled = FALSE;
|
||||
|
||||
// Define information about the user 1 account.
|
||||
$this->root_user = new UserSession(array(
|
||||
'uid' => 1,
|
||||
'name' => 'admin',
|
||||
'mail' => 'admin@example.com',
|
||||
'pass_raw' => $this->randomName(),
|
||||
));
|
||||
|
||||
// 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($settings);
|
||||
|
||||
$settings['conf_path'] = (object) array(
|
||||
'value' => $this->public_files_directory,
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['config_directories'] = (object) array(
|
||||
'value' => array(),
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['config']['system.file'] = (object) array(
|
||||
'value' => array(
|
||||
'path' => array(
|
||||
'private' => $this->private_files_directory,
|
||||
'temporary' => $this->temp_files_directory,
|
||||
),
|
||||
),
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['config']['locale.settings'] = (object) array(
|
||||
'value' => array(
|
||||
'translation' => array(
|
||||
'path' => $this->translation_files_directory,
|
||||
),
|
||||
),
|
||||
'required' => TRUE,
|
||||
);
|
||||
$this->writeSettings($settings);
|
||||
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=minimal');
|
||||
$this->drupalPostForm(NULL, array(), 'Save and continue');
|
||||
// Reload config directories.
|
||||
include $this->public_files_directory . '/settings.php';
|
||||
foreach ($config_directories as $type => $path) {
|
||||
$GLOBALS['config_directories'][$type] = $path;
|
||||
}
|
||||
|
||||
// Note that WebTestBase::installParameters() returns form input values
|
||||
// suitable for a programmed drupal_form_submit().
|
||||
// @see WebTestBase::translatePostValues()
|
||||
$this->parameters = $this->installParameters();
|
||||
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php');
|
||||
|
||||
// Select language.
|
||||
$this->setUpLanguage();
|
||||
|
||||
// Select profile.
|
||||
$this->setUpProfile();
|
||||
|
||||
// Configure settings.
|
||||
$this->setUpSettings();
|
||||
|
||||
// @todo Allow test classes based on this class to act on further installer
|
||||
// screens.
|
||||
|
||||
// Configure site.
|
||||
$this->setUpSite();
|
||||
|
||||
// Confirm installation.
|
||||
$this->setUpConfirm();
|
||||
|
||||
// Import new settings.php written by the installer.
|
||||
drupal_settings_initialize();
|
||||
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.
|
||||
// WebTestBase::tearDown() will delete the entire test site directory.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777);
|
||||
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Manually configure the test mail collector implementation to prevent
|
||||
// tests from sending out e-mails and collect them in state instead.
|
||||
\Drupal::config('system.mail')
|
||||
->set('interface.default', 'Drupal\Core\Mail\TestMailCollector')
|
||||
\Drupal::config('system.file')
|
||||
->set('path.private', $this->private_files_directory)
|
||||
->set('path.temporary', $this->temp_files_directory)
|
||||
->save();
|
||||
\Drupal::config('locale.settings')
|
||||
->set('translation.path', $this->translation_files_directory)
|
||||
->save();
|
||||
|
||||
// Use the test mail class instead of the default mail handler class.
|
||||
\Drupal::config('system.mail')->set('interface.default', 'Drupal\Core\Mail\TestMailCollector')->save();
|
||||
|
||||
// When running from run-tests.sh we don't get an empty current path which
|
||||
// would indicate we're on the home page.
|
||||
|
|
@ -156,49 +92,6 @@ class InstallerTest extends WebTestBase {
|
|||
$this->isInstalled = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select language.
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
$edit = array(
|
||||
'langcode' => $this->langcode,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select installation profile.
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
$edit = array(
|
||||
'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: Configure site.
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
$edit = $this->translatePostValues($this->parameters['forms']['install_configure_form']);
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Confirm installation.
|
||||
*/
|
||||
protected function setUpConfirm() {
|
||||
$this->clickLink($this->translations['Visit your new site']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
|
@ -211,14 +104,35 @@ class InstallerTest extends WebTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* This override is necessary because the parent drupalGet() calls t(), which
|
||||
* is not available early during installation.
|
||||
*/
|
||||
protected function drupalGet($path, array $options = array(), array $headers = array()) {
|
||||
// We are re-using a CURL connection here. If that connection still has
|
||||
// certain options set, it might change the GET into a POST. Make sure we
|
||||
// clear out previous options.
|
||||
$out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $this->getAbsoluteUrl($path), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers));
|
||||
$this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
|
||||
|
||||
// Replace original page output with new output from redirected page(s).
|
||||
if ($new = $this->checkForMetaRefresh()) {
|
||||
$out = $new;
|
||||
}
|
||||
$this->verbose('GET request to: ' . $path .
|
||||
'<hr />Ending URL: ' . $this->getUrl() .
|
||||
'<hr />' . $out);
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the user page is available after every test installation.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->drupalGet('user');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->root_user->getUsername());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,9 +94,6 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
* Test the exception handler.
|
||||
*/
|
||||
function testExceptionHandler() {
|
||||
// Ensure the test error log is empty before these tests.
|
||||
$this->assertNoErrorsLogged();
|
||||
|
||||
$error_exception = array(
|
||||
'%type' => 'Exception',
|
||||
'!message' => 'Drupal is awesome',
|
||||
|
|
@ -124,10 +121,6 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
$this->assertText($error_pdo_exception['!message'], format_string('Found !message in error page.', $error_pdo_exception));
|
||||
$error_details = format_string('in %function (line ', $error_pdo_exception);
|
||||
$this->assertRaw($error_details, format_string("Found '!message' in error page.", array('!message' => $error_details)));
|
||||
|
||||
// The exceptions are expected. Do not interpret them as a test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,14 +29,6 @@ class ShutdownFunctionsTest extends WebTestBase {
|
|||
);
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
// This test intentionally throws an exception in a PHP shutdown function.
|
||||
// Prevent it from being interpreted as an actual test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test shutdown functions.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -326,8 +326,9 @@ function system_requirements($phase) {
|
|||
}
|
||||
else {
|
||||
// If we are installing Drupal, the settings.php file might not exist yet
|
||||
// in the intended site directory, so don't require it.
|
||||
$directories[] = conf_path(FALSE) . '/files';
|
||||
// in the intended conf_path() directory, so don't require it. The
|
||||
// conf_path() cache must also be reset in this case.
|
||||
$directories[] = conf_path(FALSE, TRUE) . '/files';
|
||||
}
|
||||
if (!empty($GLOBALS['config']['system.file']['path']['private'])) {
|
||||
$directories[] = $GLOBALS['config']['system.file']['path']['private'];
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Drupal\Component\Utility\Timer;
|
||||
use Drupal\Core\StreamWrapper\PublicStream;
|
||||
|
||||
const SIMPLETEST_SCRIPT_COLOR_PASS = 32; // Green.
|
||||
const SIMPLETEST_SCRIPT_COLOR_FAIL = 31; // Red.
|
||||
|
|
@ -415,7 +416,8 @@ function simpletest_script_execute_batch($test_classes) {
|
|||
echo 'FATAL ' . $child['class'] . ': test runner returned a non-zero error code (' . $status['exitcode'] . ').' . "\n";
|
||||
if ($args['die-on-fail']) {
|
||||
list($db_prefix, ) = simpletest_last_test_get($child['test_id']);
|
||||
$test_directory = 'sites/simpletest/' . substr($db_prefix, 10);
|
||||
$public_files = PublicStream::basePath();
|
||||
$test_directory = $public_files . '/simpletest/' . substr($db_prefix, 10);
|
||||
echo 'Simpletest database and files kept and test exited immediately on fail so should be reproducible if you change settings.php to use the database prefix '. $db_prefix . ' and config directories in '. $test_directory . "\n";
|
||||
$args['keep-results'] = TRUE;
|
||||
// Exit repeat loop immediately.
|
||||
|
|
@ -581,9 +583,10 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
|
|||
// Read the log file in case any fatal errors caused the test to crash.
|
||||
simpletest_log_read($test_id, $db_prefix, $test_class);
|
||||
|
||||
// Check whether a test site directory was setup already.
|
||||
// @see \Drupal\simpletest\TestBase::prepareEnvironment()
|
||||
$test_directory = DRUPAL_ROOT . '/sites/simpletest/' . substr($db_prefix, 10);
|
||||
// Check whether a test file directory was setup already.
|
||||
// @see prepareEnvironment()
|
||||
$public_files = PublicStream::basePath();
|
||||
$test_directory = $public_files . '/simpletest/' . substr($db_prefix, 10);
|
||||
if (is_dir($test_directory)) {
|
||||
// Output the error_log.
|
||||
if (is_file($test_directory . '/error.log')) {
|
||||
|
|
@ -592,7 +595,8 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
|
|||
$messages[] = $errors;
|
||||
}
|
||||
}
|
||||
// Delete the test site directory.
|
||||
|
||||
// Delete the test files directory.
|
||||
// simpletest_clean_temporary_directories() cannot be used here, since it
|
||||
// would also delete file directories of other tests that are potentially
|
||||
// running concurrently.
|
||||
|
|
|
|||
Loading…
Reference in New Issue