Issue #1215104 by sun, lucascaro, effulgentsia: Use the non-interactive installer in WebTestBase::setUp().
parent
ff4df099d4
commit
1377aaef98
|
@ -439,18 +439,17 @@ function _batch_finished() {
|
|||
$queue->deleteQueue();
|
||||
}
|
||||
}
|
||||
// Clean-up the session. Not needed for CLI updates.
|
||||
if (isset($_SESSION)) {
|
||||
unset($_SESSION['batches'][$batch['id']]);
|
||||
if (empty($_SESSION['batches'])) {
|
||||
unset($_SESSION['batches']);
|
||||
}
|
||||
}
|
||||
}
|
||||
$_batch = $batch;
|
||||
$batch = NULL;
|
||||
|
||||
// Clean-up the session. Not needed for CLI updates.
|
||||
if (isset($_SESSION)) {
|
||||
unset($_SESSION['batches'][$batch['id']]);
|
||||
if (empty($_SESSION['batches'])) {
|
||||
unset($_SESSION['batches']);
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect if needed.
|
||||
if ($_batch['progressive']) {
|
||||
// Revert the 'destination' that was saved in batch_process().
|
||||
|
|
|
@ -2576,7 +2576,12 @@ function drupal_fast_404() {
|
|||
* Returns TRUE if a Drupal installation is currently being attempted.
|
||||
*/
|
||||
function drupal_installation_attempted() {
|
||||
return defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'install';
|
||||
// This cannot rely on the MAINTENANCE_MODE constant, since that would prevent
|
||||
// tests from using the non-interactive installer, in which case Drupal
|
||||
// only happens to be installed within the same request, but subsequently
|
||||
// executed code does not involve the installer at all.
|
||||
// @see install_drupal()
|
||||
return isset($GLOBALS['install_state']) && empty($GLOBALS['install_state']['installation_finished']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,13 +26,17 @@ use Drupal\Core\Cache\CacheFactory;
|
|||
* @see Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
function cache($bin = 'cache') {
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['cache'] = &drupal_static(__FUNCTION__, array());
|
||||
}
|
||||
$cache_objects = &$drupal_static_fast['cache'];
|
||||
|
||||
// Temporary backwards compatibiltiy layer, allow old style prefixed cache
|
||||
// bin names to be passed as arguments.
|
||||
$bin = str_replace('cache_', '', $bin);
|
||||
|
||||
// We do not use drupal_static() here because we do not want to change the
|
||||
// storage of a cache bin mid-request.
|
||||
static $cache_objects;
|
||||
if (!isset($cache_objects[$bin])) {
|
||||
$cache_objects[$bin] = CacheFactory::get($bin);
|
||||
}
|
||||
|
|
|
@ -94,19 +94,29 @@ function install_drupal($settings = array()) {
|
|||
throw $e;
|
||||
}
|
||||
}
|
||||
// After execution, all tasks might be complete, in which case
|
||||
// $install_state['installation_finished'] is TRUE. In case the last task
|
||||
// has been processed, remove the global $install_state, so other code can
|
||||
// reliably check whether it is running during the installer.
|
||||
// @see drupal_installation_attempted()
|
||||
$state = $install_state;
|
||||
if (!empty($install_state['installation_finished'])) {
|
||||
unset($install_state);
|
||||
}
|
||||
|
||||
// All available tasks for this page request are now complete. Interactive
|
||||
// installations can send output to the browser or redirect the user to the
|
||||
// next page.
|
||||
if ($install_state['interactive']) {
|
||||
if ($install_state['parameters_changed']) {
|
||||
if ($state['interactive']) {
|
||||
if ($state['parameters_changed']) {
|
||||
// Redirect to the correct page if the URL parameters have changed.
|
||||
install_goto(install_redirect_url($install_state));
|
||||
install_goto(install_redirect_url($state));
|
||||
}
|
||||
elseif (isset($output)) {
|
||||
// Display a page only if some output is available. Otherwise it is
|
||||
// possible that we are printing a JSON page and theme output should
|
||||
// not be shown.
|
||||
install_display_output($output, $install_state);
|
||||
install_display_output($output, $state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +234,9 @@ function install_state_defaults() {
|
|||
*/
|
||||
function install_begin_request(&$install_state) {
|
||||
// Add any installation parameters passed in via the URL.
|
||||
$install_state['parameters'] += $_GET;
|
||||
if ($install_state['interactive']) {
|
||||
$install_state['parameters'] += $_GET;
|
||||
}
|
||||
|
||||
// Validate certain core settings that are used throughout the installation.
|
||||
if (!empty($install_state['parameters']['profile'])) {
|
||||
|
@ -240,11 +252,10 @@ function install_begin_request(&$install_state) {
|
|||
if (!$install_state['interactive']) {
|
||||
drupal_override_server_variables($install_state['server']);
|
||||
}
|
||||
|
||||
// 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 (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) {
|
||||
elseif (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
|
|
|
@ -10,26 +10,30 @@ use Drupal\Component\Graph\Graph;
|
|||
/**
|
||||
* Loads all the modules that have been enabled in the system table.
|
||||
*
|
||||
* @param $bootstrap
|
||||
* @param bool $bootstrap
|
||||
* Whether to load only the reduced set of modules loaded in "bootstrap mode"
|
||||
* for cached pages. See bootstrap.inc.
|
||||
* for cached pages. See bootstrap.inc. Pass NULL to only check the current
|
||||
* status without loading of modules.
|
||||
* @param bool $reset
|
||||
* (optional) Internal use only. Whether to reset the internal statically
|
||||
* cached flag of whether modules have been loaded. If TRUE, all modules are
|
||||
* (re)loaded in the same call. Used by the testing framework to override and
|
||||
* persist a limited module list for the duration of a unit test (in which no
|
||||
* module system exists).
|
||||
*
|
||||
* @return
|
||||
* If $bootstrap is NULL, return a boolean indicating whether all modules
|
||||
* have been loaded.
|
||||
* @return bool
|
||||
* A Boolean indicating whether all modules have been loaded. This means all
|
||||
* modules; the load status of bootstrap modules cannot be checked.
|
||||
*/
|
||||
function module_load_all($bootstrap = FALSE) {
|
||||
// Already loaded code cannot be unloaded, but new modules may be added within
|
||||
// a request, which should be loaded as well.
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
// @see theme()
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['has_run'] = &drupal_static(__FUNCTION__, FALSE);
|
||||
}
|
||||
$has_run = &$drupal_static_fast['has_run'];
|
||||
function module_load_all($bootstrap = FALSE, $reset = FALSE) {
|
||||
static $has_run = FALSE;
|
||||
|
||||
if (isset($bootstrap)) {
|
||||
if ($reset) {
|
||||
$has_run = FALSE;
|
||||
}
|
||||
|
||||
// Unless $boostrap is NULL, load the requested set of modules.
|
||||
if (isset($bootstrap) && !$has_run) {
|
||||
$type = $bootstrap ? 'bootstrap' : 'module_enabled';
|
||||
foreach (module_list($type) as $module) {
|
||||
drupal_load('module', $module);
|
||||
|
@ -60,14 +64,29 @@ function module_load_all($bootstrap = FALSE) {
|
|||
* list will persist until the next call with a new $fixed_list passed in.
|
||||
* Primarily intended for internal use (e.g., in install.php and update.php).
|
||||
* Use module_list_reset() to undo the $fixed_list override.
|
||||
* @param bool $reset
|
||||
* (optional) Whether to reset/remove the $fixed_list.
|
||||
*
|
||||
* @return array
|
||||
* An associative array whose keys and values are the names of the modules in
|
||||
* the list.
|
||||
*
|
||||
* @see module_list_reset()
|
||||
*/
|
||||
function module_list($type = 'module_enabled', array $fixed_list = NULL) {
|
||||
// This static is only used for $fixed_list.
|
||||
$module_list = &drupal_static(__FUNCTION__);
|
||||
function module_list($type = 'module_enabled', array $fixed_list = NULL, $reset = FALSE) {
|
||||
// This static is only used for $fixed_list. It must not be a drupal_static(),
|
||||
// since any call to drupal_static_reset() in unit tests would cause an
|
||||
// attempt to retrieve the list of modules from the database (which does not
|
||||
// exist).
|
||||
static $module_list;
|
||||
|
||||
if ($reset) {
|
||||
$module_list = NULL;
|
||||
// Do nothing if no $type and no $fixed_list have been passed.
|
||||
if (!isset($type) && !isset($fixed_list)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The list that will be be returned. Separate from $module_list in order
|
||||
// to not duplicate the static cache of system_list().
|
||||
|
@ -93,7 +112,7 @@ function module_list($type = 'module_enabled', array $fixed_list = NULL) {
|
|||
* Subsequent calls to module_list() will no longer use a fixed list.
|
||||
*/
|
||||
function module_list_reset() {
|
||||
drupal_static_reset('module_list');
|
||||
module_list(NULL, NULL, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -254,10 +254,22 @@ function locale($string = NULL, $context = NULL, $langcode = NULL) {
|
|||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['locale'] = &drupal_static(__FUNCTION__);
|
||||
$drupal_static_fast['locale'] = &drupal_static(__FUNCTION__, array('cache' => array(), 'exists' => NULL));
|
||||
}
|
||||
$locale_t = &$drupal_static_fast['locale'];
|
||||
$locale_t = &$drupal_static_fast['locale']['cache'];
|
||||
$locale_exists = &$drupal_static_fast['locale']['exists'];
|
||||
|
||||
// Check whether Locale module is actually installed and operational.
|
||||
// The mere existence of locale() does not imply that Locale module is
|
||||
// actually enabled and its database tables are installed. Since PHP code
|
||||
// cannot be unloaded, this is typically the case in the environment that
|
||||
// is executing a test.
|
||||
if (!isset($locale_exists)) {
|
||||
$locale_exists = function_exists('module_exists') && module_exists('locale');
|
||||
}
|
||||
if (!$locale_exists) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
if (!isset($string)) {
|
||||
// Return all cached strings if no string was specified
|
||||
|
|
|
@ -665,6 +665,14 @@ abstract class TestBase {
|
|||
}
|
||||
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'];
|
||||
|
||||
// Indicate the database prefix was set up correctly.
|
||||
$this->setupDatabasePrefix = TRUE;
|
||||
}
|
||||
|
@ -698,7 +706,10 @@ abstract class TestBase {
|
|||
// Save further contextual information.
|
||||
$this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
|
||||
$this->originalProfile = drupal_get_profile();
|
||||
$this->originalUser = $user;
|
||||
$this->originalUser = clone $user;
|
||||
|
||||
// Ensure that the current session is not changed by the new environment.
|
||||
drupal_save_session(FALSE);
|
||||
|
||||
// Save and clean the shutdown callbacks array because it is static cached
|
||||
// and will be changed by the test run. Otherwise it will contain callbacks
|
||||
|
@ -793,6 +804,10 @@ abstract class TestBase {
|
|||
// Restore original database connection.
|
||||
Database::removeConnection('default');
|
||||
Database::renameConnection('simpletest_original_default', 'default');
|
||||
// @see TestBase::changeDatabasePrefix()
|
||||
global $databases;
|
||||
$connection_info = Database::getConnectionInfo('default');
|
||||
$databases['default']['default'] = $connection_info['default'];
|
||||
|
||||
// Restore original globals.
|
||||
$GLOBALS['theme_key'] = $this->originalThemeKey;
|
||||
|
@ -801,9 +816,9 @@ abstract class TestBase {
|
|||
// Reset all static variables.
|
||||
drupal_static_reset();
|
||||
|
||||
// Restore has_run state.
|
||||
$has_run = &drupal_static('module_load_all');
|
||||
$has_run = TRUE;
|
||||
// Reset module list and module load status.
|
||||
module_list_reset();
|
||||
module_load_all(FALSE, TRUE);
|
||||
|
||||
// Restore original in-memory configuration.
|
||||
$conf = $this->originalConf;
|
||||
|
|
|
@ -595,6 +595,13 @@ abstract class WebTestBase extends TestBase {
|
|||
global $user, $conf;
|
||||
$language_interface = language(LANGUAGE_TYPE_INTERFACE);
|
||||
|
||||
// When running tests through the Simpletest UI (vs. on the command line),
|
||||
// Simpletest's batch conflicts with the installer's batch. Batch API does
|
||||
// not support the concept of nested batches (in which the nested is not
|
||||
// progressive), so we need to temporarily pretend there was no batch.
|
||||
// Backup the currently running Simpletest batch.
|
||||
$this->originalBatch = batch_get();
|
||||
|
||||
// Create the database prefix for this test.
|
||||
$this->prepareDatabasePrefix();
|
||||
|
||||
|
@ -617,16 +624,75 @@ abstract class WebTestBase extends TestBase {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
// Preset the 'install_profile' system variable, so the first call into
|
||||
// system_rebuild_module_data() (in drupal_install_system()) will register
|
||||
// the test's profile as a module. Without this, the installation profile of
|
||||
// the parent site (executing the test) is registered, and the test
|
||||
// profile's hook_install() and other hook implementations are never invoked.
|
||||
$conf['install_profile'] = $this->profile;
|
||||
// Set the 'simpletest_parent_profile' variable to add the parent profile's
|
||||
// search path to the child site's search paths.
|
||||
// @see drupal_system_listing()
|
||||
$conf['simpletest_parent_profile'] = $this->originalProfile;
|
||||
|
||||
// Perform the actual Drupal installation.
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
drupal_install_system();
|
||||
// Set installer parameters.
|
||||
// @see install.php, install.core.inc
|
||||
$connection_info = Database::getConnectionInfo('default');
|
||||
$this->root_user = (object) array(
|
||||
'name' => 'admin',
|
||||
'mail' => 'admin@example.com',
|
||||
'pass_raw' => $this->randomName(),
|
||||
);
|
||||
$settings = array(
|
||||
'interactive' => FALSE,
|
||||
'parameters' => array(
|
||||
'profile' => $this->profile,
|
||||
'langcode' => 'en',
|
||||
),
|
||||
'forms' => array(
|
||||
'install_settings_form' => array(
|
||||
'driver' => $connection_info['default']['driver'],
|
||||
'username' => $connection_info['default']['username'],
|
||||
'host' => $connection_info['default']['host'],
|
||||
'port' => $connection_info['default']['port'],
|
||||
'password' => $connection_info['default']['password'],
|
||||
'database' => $connection_info['default']['database'],
|
||||
'prefix' => $connection_info['default']['prefix'],
|
||||
),
|
||||
'install_configure_form' => array(
|
||||
'site_name' => 'Drupal',
|
||||
'site_mail' => 'simpletest@example.com',
|
||||
'account' => array(
|
||||
'name' => $this->root_user->name,
|
||||
'mail' => $this->root_user->mail,
|
||||
'pass' => array(
|
||||
'pass1' => $this->root_user->pass_raw,
|
||||
'pass2' => $this->root_user->pass_raw,
|
||||
),
|
||||
),
|
||||
// form_type_checkboxes_value() requires NULL instead of FALSE values
|
||||
// for programmatic form submissions to disable a checkbox.
|
||||
'update_status_module' => array(
|
||||
1 => NULL,
|
||||
2 => NULL,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Replace the global $user session with an anonymous user to resemble a
|
||||
// regular installation.
|
||||
$user = drupal_anonymous_user();
|
||||
|
||||
// Reset the static batch to remove Simpletest's batch operations.
|
||||
$batch = &batch_get();
|
||||
$batch = array();
|
||||
|
||||
// Execute the non-interactive installer.
|
||||
require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
|
||||
install_drupal($settings);
|
||||
|
||||
// Restore the original Simpletest batch.
|
||||
$batch = &batch_get();
|
||||
$batch = $this->originalBatch;
|
||||
|
||||
// Revert install_begin_request() cache and lock service overrides.
|
||||
unset($conf['cache_classes']);
|
||||
unset($conf['lock_backend']);
|
||||
|
||||
// Set path variables.
|
||||
variable_set('file_public_path', $this->public_files_directory);
|
||||
|
@ -636,16 +702,8 @@ abstract class WebTestBase extends TestBase {
|
|||
// Set 'parent_profile' of simpletest to add the parent profile's
|
||||
// search path to the child site's search paths.
|
||||
// @see drupal_system_listing()
|
||||
// @todo This may need to be primed like 'install_profile' above.
|
||||
config('simpletest.settings')->set('parent_profile', $this->originalProfile)->save();
|
||||
|
||||
// Include the testing profile.
|
||||
variable_set('install_profile', $this->profile);
|
||||
$profile_details = install_profile_info($this->profile, 'en');
|
||||
|
||||
// Install the modules specified by the testing profile.
|
||||
module_enable($profile_details['dependencies'], FALSE);
|
||||
|
||||
// Collect modules to install.
|
||||
$class = get_class($this);
|
||||
$modules = array();
|
||||
|
@ -660,14 +718,6 @@ abstract class WebTestBase extends TestBase {
|
|||
$this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
|
||||
}
|
||||
|
||||
// Run the profile tasks.
|
||||
$install_profile_module_exists = db_query("SELECT 1 FROM {system} WHERE type = 'module' AND name = :name", array(
|
||||
':name' => $this->profile,
|
||||
))->fetchField();
|
||||
if ($install_profile_module_exists) {
|
||||
module_enable(array($this->profile), FALSE);
|
||||
}
|
||||
|
||||
// Create a new DrupalKernel for testing purposes, now that all required
|
||||
// modules have been enabled. This also stores a new dependency injection
|
||||
// container in drupal_container(). Drupal\simpletest\TestBase::tearDown()
|
||||
|
@ -687,25 +737,6 @@ abstract class WebTestBase extends TestBase {
|
|||
// Reset/rebuild all data structures after enabling the modules.
|
||||
$this->resetAll();
|
||||
|
||||
// Run cron once in that environment, as install.php does at the end of
|
||||
// the installation process.
|
||||
drupal_cron_run();
|
||||
|
||||
// Ensure that the session is not written to the new environment and replace
|
||||
// the global $user session with uid 1 from the new test site.
|
||||
drupal_save_session(FALSE);
|
||||
// Login as uid 1.
|
||||
$user = user_load(1);
|
||||
|
||||
// Restore necessary variables.
|
||||
variable_set('install_task', 'done');
|
||||
config('system.site')->set('mail', 'simpletest@example.com')->save();
|
||||
variable_set('date_default_timezone', date_default_timezone_get());
|
||||
|
||||
// Set up English language.
|
||||
unset($conf['language_default']);
|
||||
$language_interface = language_default();
|
||||
|
||||
// Use the test mail class instead of the default mail handler class.
|
||||
variable_set('mail_system', array('default-system' => 'Drupal\Core\Mail\VariableLog'));
|
||||
|
||||
|
|
|
@ -191,13 +191,13 @@ abstract class UpgradePathTestBase extends WebTestBase {
|
|||
$update_url = $GLOBALS['base_url'] . '/core/update.php';
|
||||
$this->drupalGet($update_url, array('external' => TRUE));
|
||||
if (!$this->assertResponse(200)) {
|
||||
return FALSE;
|
||||
throw new Exception('Initial GET to update.php did not return HTTP 200 status.');
|
||||
}
|
||||
|
||||
// Continue.
|
||||
$this->drupalPost(NULL, array(), t('Continue'));
|
||||
if (!$this->assertResponse(200)) {
|
||||
return FALSE;
|
||||
throw new Exception('POST to continue update.php did not return HTTP 200 status.');
|
||||
}
|
||||
|
||||
// The test should pass if there are no pending updates.
|
||||
|
@ -211,7 +211,7 @@ abstract class UpgradePathTestBase extends WebTestBase {
|
|||
// Go!
|
||||
$this->drupalPost(NULL, array(), t('Apply pending updates'));
|
||||
if (!$this->assertResponse(200)) {
|
||||
return FALSE;
|
||||
throw new Exception('POST to update.php to apply pending updates did not return HTTP 200 status.');
|
||||
}
|
||||
|
||||
// Check for errors during the update process.
|
||||
|
@ -222,36 +222,30 @@ abstract class UpgradePathTestBase extends WebTestBase {
|
|||
$this->fail($message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->upgradeErrors)) {
|
||||
// Upgrade failed, the installation might be in an inconsistent state,
|
||||
// don't process.
|
||||
return FALSE;
|
||||
throw new Exception('Errors during update process.');
|
||||
}
|
||||
|
||||
// Check if there still are pending updates.
|
||||
$this->drupalGet($update_url, array('external' => TRUE));
|
||||
$this->drupalPost(NULL, array(), t('Continue'));
|
||||
if (!$this->assertText(t('No pending updates.'), t('No pending updates at the end of the update process.'))) {
|
||||
return FALSE;
|
||||
throw new Exception('update.php still shows pending updates after execution.');
|
||||
}
|
||||
|
||||
// Upgrade succeed, rebuild the environment so that we can call the API
|
||||
// of the child site directly from this request.
|
||||
$this->upgradedSite = TRUE;
|
||||
|
||||
// Reload module list. For modules that are enabled in the test database,
|
||||
// but not on the test client, we need to load the code here.
|
||||
// Reload module list for modules that are enabled in the test database
|
||||
// but not on the test client.
|
||||
system_list_reset();
|
||||
foreach (module_list() as $module) {
|
||||
drupal_load('module', $module);
|
||||
}
|
||||
|
||||
// Reload hook implementations
|
||||
module_implements_reset();
|
||||
module_load_all(FALSE, TRUE);
|
||||
|
||||
// Rebuild caches.
|
||||
drupal_static_reset();
|
||||
drupal_flush_all_caches();
|
||||
|
||||
// Reload global $conf array and permissions.
|
||||
|
|
Loading…
Reference in New Issue