From ad3bbec18d8aae42c8f583dfb11cfc155521ef3d Mon Sep 17 00:00:00 2001
From: lucascaro <lucascaro@gmail.com>
Date: Thu, 19 Jul 2012 16:29:00 -0300
Subject: [PATCH] Porting D8 patch by sun to D7

---
 .htaccess                                   |    2 +-
 includes/batch.inc                          |   15 +--
 includes/bootstrap.inc                      |    2 +-
 includes/cache.inc                          |    4 +-
 includes/common.inc                         |    3 +-
 includes/install.core.inc                   |   22 +++-
 includes/session.inc                        |   21 ++-
 modules/node/node.module                    |    3 +
 modules/simpletest/drupal_web_test_case.php |  190 ++++++++++++++++-----------
 modules/simpletest/tests/ajax.test          |    2 +-
 10 files changed, 163 insertions(+), 101 deletions(-)

diff --git a/.htaccess b/.htaccess
index 246edc2..30d71a9 100644
--- a/.htaccess
+++ b/.htaccess
@@ -95,7 +95,7 @@ DirectoryIndex index.php index.html index.htm
   #
   # If your site is running in a VirtualDocumentRoot at http://example.com/,
   # uncomment the following line:
-  # RewriteBase /
+  RewriteBase /drupal/
 
   # Pass all requests not referring directly to files in the filesystem to
   # index.php. Clean URLs are handled in drupal_environment_initialize().
diff --git a/includes/batch.inc b/includes/batch.inc
index 061acd4..125b8b4 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -478,18 +478,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().
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index d9f5aa1..3fa3e84 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -2518,7 +2518,7 @@ 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';
+  return isset($GLOBALS['install_state']) && empty($GLOBALS['install_state']['installation_finished']);
 }
 
 /**
diff --git a/includes/cache.inc b/includes/cache.inc
index a19d3c3..164a8c7 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -20,9 +20,7 @@
  * @see DrupalCacheInterface
  */
 function _cache_get_object($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;
+  $cache_objects = &drupal_static(__FUNCTION__, array());
   if (!isset($cache_objects[$bin])) {
     $class = variable_get('cache_class_' . $bin);
     if (!isset($class)) {
diff --git a/includes/common.inc b/includes/common.inc
index 50f20e6..3cab062 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -5114,6 +5114,7 @@ function drupal_cron_run() {
   @ignore_user_abort(TRUE);
 
   // Prevent session information from being saved while cron is running.
+  $old_save_session = drupal_save_session();
   drupal_save_session(FALSE);
 
   // Force the current user to anonymous to ensure consistent permissions on
@@ -5176,7 +5177,7 @@ function drupal_cron_run() {
   }
   // Restore the user.
   $GLOBALS['user'] = $original_user;
-  drupal_save_session(TRUE);
+  drupal_save_session($old_save_session);
 
   return $return;
 }
diff --git a/includes/install.core.inc b/includes/install.core.inc
index ec3a853..db8eabc 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -88,19 +88,27 @@ 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;
+  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);
     }
   }
 }
@@ -211,7 +219,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'])) {
@@ -230,7 +240,7 @@ function install_begin_request(&$install_state) {
   // 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;
   }
diff --git a/includes/session.inc b/includes/session.inc
index 8f1bcaf..8f89fe2 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -349,6 +349,12 @@ function drupal_session_started($set = NULL) {
  */
 function drupal_session_regenerate() {
   global $user, $is_https;
+
+  // Nothing to do if we are not allowed to change the session.
+  if (!drupal_save_session()) {
+    return;
+  }
+
   if ($is_https && variable_get('https', FALSE)) {
     $insecure_session_name = substr(session_name(), 1);
     if (!isset($GLOBALS['lazy_session']) && isset($_COOKIE[$insecure_session_name])) {
@@ -418,6 +424,11 @@ function drupal_session_regenerate() {
 function _drupal_session_destroy($sid) {
   global $user, $is_https;
 
+  // Nothing to do if we are not allowed to change the session.
+  if (!drupal_save_session()) {
+    return;
+  }
+
   // Delete session data.
   db_delete('sessions')
     ->condition($is_https ? 'ssid' : 'sid', $sid)
@@ -465,6 +476,11 @@ function _drupal_session_delete_cookie($name, $secure = NULL) {
  *   User ID.
  */
 function drupal_session_destroy_uid($uid) {
+  // Nothing to do if we are not allowed to change the session.
+  if (!drupal_save_session()) {
+    return;
+  }
+
   db_delete('sessions')
     ->condition('uid', $uid)
     ->execute();
@@ -507,7 +523,10 @@ function _drupal_session_garbage_collection($lifetime) {
  *   FALSE if writing session data has been disabled. Otherwise, TRUE.
  */
 function drupal_save_session($status = NULL) {
-  $save_session = &drupal_static(__FUNCTION__, TRUE);
+  // PHP session ID, session, and cookie handling happens in the global scope.
+  // This value has to persist across calls to drupal_static_reset(), since a
+  // potentially wrong or disallowed session would be written otherwise.
+  static $save_session = TRUE;
   if (isset($status)) {
     $save_session = $status;
   }
diff --git a/modules/node/node.module b/modules/node/node.module
index 71ea3b9..32995e1 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -3882,6 +3882,9 @@ function node_unpublish_by_keyword_action($node, $context) {
  */
 function node_requirements($phase) {
   $requirements = array();
+  if ($phase !== 'runtime') {
+    return $requirements;
+  }
   // Ensure translations don't break at install time
   $t = get_t();
   // Only show rebuild button if there are either 0, or 2 or more, rows
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 251c5c1..068c42f 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -139,15 +139,7 @@ abstract class DrupalTestCase {
     );
 
     // Store assertion for display after the test has completed.
-    try {
-      $connection = Database::getConnection('default', 'simpletest_original_default');
-    }
-    catch (DatabaseConnectionNotDefinedException $e) {
-      // If the test was not set up, the simpletest_original_default
-      // connection does not exist.
-      $connection = Database::getConnection('default', 'default');
-    }
-    $connection
+    self::getDatabaseConnection()
       ->insert('simpletest')
       ->fields($assertion)
       ->execute();
@@ -201,7 +193,8 @@ abstract class DrupalTestCase {
       'file' => $caller['file'],
     );
 
-    return db_insert('simpletest')
+    return self::getDatabaseConnection()
+      ->insert('simpletest')
       ->fields($assertion)
       ->execute();
   }
@@ -217,11 +210,24 @@ abstract class DrupalTestCase {
    * @see DrupalTestCase::insertAssert()
    */
   public static function deleteAssert($message_id) {
-    return (bool) db_delete('simpletest')
+    return (bool) self::getDatabaseConnection()
+      ->delete('simpletest')
       ->condition('message_id', $message_id)
       ->execute();
   }
 
+  public static function getDatabaseConnection() {
+    try {
+      $connection = Database::getConnection('default', 'simpletest_original_default');
+    }
+    catch (DatabaseConnectionNotDefinedException $e) {
+      // If the test was not set up, the simpletest_original_default
+      // connection does not exist.
+      $connection = Database::getConnection('default', 'default');
+    }
+    return $connection;
+  }
+  
   /**
    * Cycles through backtrace until the first non-assertion method is found.
    *
@@ -1264,6 +1270,13 @@ class DrupalWebTestCase extends DrupalTestCase {
   protected function setUp() {
     global $user, $language, $conf;
 
+    // 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();
+    $this->originalCacheClass = variable_get('cache_default_class', 'DrupalDatabaseCache');
     // Generate a temporary prefixed database to ensure that tests have a clean starting point.
     $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
     db_update('simpletest_test_id')
@@ -1284,6 +1297,14 @@ class DrupalWebTestCase extends DrupalTestCase {
       );
     }
     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'];
 
     // Store necessary current values before switching to prefixed database.
     $this->originalLanguage = $language;
@@ -1327,18 +1348,73 @@ class DrupalWebTestCase extends DrupalTestCase {
     $test_info['test_run_id'] = $this->databasePrefix;
     $test_info['in_child_site'] = 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;
 
-    include_once DRUPAL_ROOT . '/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']['default'],
+        ),
+        '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,
+          ),
+        ),
+      ),
+    );
 
-    $this->preloadRegistry();
+    // Reset the static batch to remove Simpletest's batch operations.
+    $batch = &batch_get();
+    $batch = array();
 
+    // Avoid writing session changes while installing.
+    drupal_save_session(FALSE);
+
+    // Execute the non-interactive installer.
+    require_once DRUPAL_ROOT . '/includes/install.core.inc';
+    install_drupal($settings);
+
+    // Revert install_begin_request() cache and lock service overrides.
+    unset($conf['cache_classes']);
+    unset($conf['lock_backend']);
+    unset($GLOBALS['install_state']);
+
+    
     // Set path variables.
     variable_set('file_public_path', $public_files_directory);
     variable_set('file_private_path', $private_files_directory);
@@ -1347,16 +1423,8 @@ class DrupalWebTestCase extends DrupalTestCase {
     // 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()
-    // @todo This may need to be primed like 'install_profile' above.
     variable_set('simpletest_parent_profile', $this->originalProfile);
 
-    // 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);
-
     // Install modules needed for this test. This could have been passed in as
     // either a single array argument or a variable number of string arguments.
     // @todo Remove this compatibility layer in Drupal 8, and only accept
@@ -1370,31 +1438,23 @@ class DrupalWebTestCase extends DrupalTestCase {
       $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);
-    }
-
+    // Reset cache default class.
+    variable_set('cache_default_class', $this->originalCacheClass);
+    $conf['cache_default_class'] = $this->originalCacheClass;
+    
     // 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();
-
     // Log in with a clean $user.
-    $this->originalUser = $user;
-    drupal_save_session(FALSE);
+    $this->originalUser = clone $user;
     $user = user_load(1);
-
+    
     // Restore necessary variables.
     variable_set('install_task', 'done');
     variable_set('clean_url', $clean_url_original);
     variable_set('site_mail', 'simpletest@example.com');
     variable_set('date_default_timezone', date_default_timezone_get());
+
     // Set up English language.
     unset($GLOBALS['conf']['language_default']);
     $language = language_default();
@@ -1407,42 +1467,6 @@ class DrupalWebTestCase extends DrupalTestCase {
   }
 
   /**
-   * Preload the registry from the testing site.
-   *
-   * This method is called by DrupalWebTestCase::setUp(), and preloads the
-   * registry from the testing site to cut down on the time it takes to
-   * set up a clean environment for the current test run.
-   */
-  protected function preloadRegistry() {
-    // Use two separate queries, each with their own connections: copy the
-    // {registry} and {registry_file} tables over from the parent installation
-    // to the child installation.
-    $original_connection = Database::getConnection('default', 'simpletest_original_default');
-    $test_connection = Database::getConnection();
-
-    foreach (array('registry', 'registry_file') as $table) {
-      // Find the records from the parent database.
-      $source_query = $original_connection
-        ->select($table, array(), array('fetch' => PDO::FETCH_ASSOC))
-        ->fields($table);
-
-      $dest_query = $test_connection->insert($table);
-
-      $first = TRUE;
-      foreach ($source_query->execute() as $row) {
-        if ($first) {
-          $dest_query->fields(array_keys($row));
-          $first = FALSE;
-        }
-        // Insert the records into the child database.
-        $dest_query->values($row);
-      }
-
-      $dest_query->execute();
-    }
-  }
-
-  /**
    * Reset all data structures after having enabled new modules.
    *
    * This method is called by DrupalWebTestCase::setUp() after enabling
@@ -1515,7 +1539,15 @@ class DrupalWebTestCase extends DrupalTestCase {
     // Get back to the original 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 the original Simpletest batch.
+    $batch = &batch_get();
+    $batch = $this->originalBatch;
+    
     // Restore original shutdown callbacks array to prevent original
     // environment of calling handlers from test run.
     $callbacks = &drupal_register_shutdown_function();
diff --git a/modules/simpletest/tests/ajax.test b/modules/simpletest/tests/ajax.test
index 014a350..403ead2 100644
--- a/modules/simpletest/tests/ajax.test
+++ b/modules/simpletest/tests/ajax.test
@@ -488,7 +488,7 @@ class AJAXMultiFormTestCase extends AJAXTestCase {
     // page update, ensure the same as above.
     foreach ($field_xpaths as $form_html_id => $field_xpath) {
       for ($i = 0; $i < 2; $i++) {
-        $this->drupalPostAJAX(NULL, array(), array($button_name => $button_value), 'system/ajax', array(), array(), $form_html_id);
+        $this->drupalPostAJAX(NULL, array(), array($button_name => $button_value), NULL, array(), array(), $form_html_id);
         $this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == $i+2, t('Found the correct number of field items after an AJAX submission.'));
         $this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button after an AJAX submission.'));
         $this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
-- 
1.7.9.5

