curlInitialize(); $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)); curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode(session_name()) . '=' . rawurlencode($sid)); // Force our way into the session of the child site. drupal_save_session(TRUE); _drupal_session_write($sid, ''); drupal_save_session(FALSE); } /** * Checks that zlib is enabled in order to run the upgrade tests. */ protected function checkRequirements() { if (!function_exists('gzopen')) { return array( 'Missing zlib requirement for upgrade tests.', ); } return parent::checkRequirements(); } /** * Overrides Drupal\simpletest\WebTestBase::setUp() for upgrade testing. * * @see Drupal\simpletest\WebTestBase::prepareDatabasePrefix() * @see Drupal\simpletest\WebTestBase::changeDatabasePrefix() * @see Drupal\simpletest\WebTestBase::prepareEnvironment() */ protected function setUp() { global $user, $conf; // Load the Update API. require_once DRUPAL_ROOT . '/core/includes/update.inc'; // Reset flags. $this->upgradedSite = FALSE; $this->upgradeErrors = array(); // Create the database prefix for this test. $this->prepareDatabasePrefix(); // Prepare the environment for running tests. $this->prepareEnvironment(); if (!$this->setupEnvironment) { return FALSE; } // Reset all statics and variables to perform tests in a clean environment. $conf = array(); drupal_static_reset(); // 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(); if (!$this->setupDatabasePrefix) { return FALSE; } // Load the database from the portable PHP dump. // The files may be gzipped. foreach ($this->databaseDumpFiles as $file) { if (substr($file, -3) == '.gz') { $file = "compress.zlib://$file"; } require $file; } // Set path variables. $this->variable_set('file_public_path', $this->public_files_directory); $this->variable_set('file_private_path', $this->private_files_directory); $this->variable_set('file_temporary_path', $this->temp_files_directory); $this->pass('Finished loading the dump.'); // 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 = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject(); // Generate and set a D8-compatible session cookie. $this->prepareD8Session(); // Restore necessary variables. $this->variable_set('site_mail', 'simpletest@example.com'); drupal_set_time_limit($this->timeLimit); $this->setup = TRUE; } /** * Overrides \Drupal\simpletest\TestBase::prepareConfigDirectories(). */ protected function prepareConfigDirectories() { // The configuration directories are prepared as part of the first access to // update.php. } /** * Specialized variable_set() that works even if the child site is not upgraded. * * @param $name * The name of the variable to set. * @param $value * The value to set. This can be any PHP data type; these functions take care * of serialization as necessary. * * @todo Update for D8 configuration system. */ protected function variable_set($name, $value) { db_delete('variable') ->condition('name', $name) ->execute(); db_insert('variable') ->fields(array( 'name' => $name, 'value' => serialize($value), )) ->execute(); try { cache()->delete('variables'); cache('bootstrap')->delete('variables'); } // Since cache_bootstrap won't exist in a Drupal 6 site, ignore the // exception if the above fails. catch (Exception $e) {} } /** * Specialized refreshVariables(). */ protected function refreshVariables() { // Refresh the variables only if the site was already upgraded. if ($this->upgradedSite) { global $conf; cache('bootstrap')->delete('variables'); $conf = variable_initialize(); $container = drupal_container(); if ($container->has('config.factory')) { $container->get('config.factory')->reset(); } } } /** * Perform the upgrade. * * @param $register_errors * Register the errors during the upgrade process as failures. * @return * TRUE if the upgrade succeeded, FALSE otherwise. */ protected function performUpgrade($register_errors = TRUE) { // Load the first update screen. $this->getUpdatePhp(); if (!$this->assertResponse(200)) { throw new Exception('Initial GET to update.php did not return HTTP 200 status.'); } // Ensure that the first update screen appeared correctly. if (!$this->assertFieldByXPath('//input[@type="submit"]')) { throw new Exception('An error was encountered during the first access to update.php.'); } // Initialize config directories and rebuild the service container after // creating them in the first step. parent::prepareConfigDirectories(); $this->rebuildContainer(); // Continue. $this->drupalPost(NULL, array(), t('Continue')); if (!$this->assertResponse(200)) { throw new Exception('POST to continue update.php did not return HTTP 200 status.'); } // The test should pass if there are no pending updates. $content = $this->drupalGetContent(); if (strpos($content, t('No pending updates.')) !== FALSE) { $this->pass('No pending updates and therefore no upgrade process to test.'); $this->pendingUpdates = FALSE; return TRUE; } // Go! $this->drupalPost(NULL, array(), t('Apply pending updates')); if (!$this->assertResponse(200)) { throw new Exception('POST to update.php to apply pending updates did not return HTTP 200 status.'); } // Check for errors during the update process. foreach ($this->xpath('//li[@class=:class]', array(':class' => 'failure')) as $element) { $message = strip_tags($element->asXML()); $this->upgradeErrors[] = $message; if ($register_errors) { $this->fail($message); } } if (!empty($this->upgradeErrors)) { // Upgrade failed, the installation might be in an inconsistent state, // don't process. throw new Exception('Errors during update process.'); } // Check if there still are pending updates. $this->getUpdatePhp(); $this->drupalPost(NULL, array(), t('Continue')); if (!$this->assertText(t('No pending updates.'), 'No pending updates at the end of the update process.')) { 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; // Force a variable refresh as we only just enabled it. $this->refreshVariables(); // Reload module list for modules that are enabled in the test database // but not on the test client. drupal_container()->get('module_handler')->resetImplementations(); drupal_container()->get('module_handler')->reload(); // Rebuild the container and all caches. $this->rebuildContainer(); $this->resetAll(); return TRUE; } /** * Gets update.php without calling url(). * * Required since WebTestBase::drupalGet() calls t(), which calls into * system_list(), from the parent site/test runner, before update.php is even * executed. * * @see WebTestBase::drupalGet() */ protected function getUpdatePhp() { $path = $GLOBALS['base_url'] . '/core/update.php'; $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $path, CURLOPT_NOBODY => FALSE)); // Ensure that any changes to variables in the other thread are picked up. $this->refreshVariables(); // Replace original page output with new output from redirected page(s). if ($new = $this->checkForMetaRefresh()) { $out = $new; } $this->verbose('GET request to: ' . $path . '
Ending URL: ' . $this->getUrl() . '
' . $out); return $out; } }