Extend SimpleTest to allow for cloning of an existing site.

From:  <>


---

 modules/simpletest/drupal_web_test_case.php |  147 +++++++++++++++++++++++++++
 1 files changed, 147 insertions(+), 0 deletions(-)

diff --git modules/simpletest/drupal_web_test_case.php modules/simpletest/drupal_web_test_case.php
index 424e1f3..487f03c 100644
--- modules/simpletest/drupal_web_test_case.php
+++ modules/simpletest/drupal_web_test_case.php
@@ -2128,3 +2128,150 @@ class DrupalWebTestCase {
   }
 }
 
+/**
+ * Test existing site configuration rather than building a Drupal site from
+ * the ground up.
+ */
+class DrupalWebCloneSiteTestCase extends DrupalWebTestCase {
+
+  /**
+   * List of tables to exclude the data cloning (the table structures are
+   * still mirrored into the prefixed copy.
+   */
+  protected $cloneExludes = array();
+
+  /**
+   * Copy existing tables and content into a prefixed set of identical tables.
+   */
+  function setUp() {
+    // BEGIN BLOCK FROM DrupalWebTestCase::setUp().
+    global $db_prefix, $user;
+ 
+    // Store necessary current values before switching to prefixed database.
+    $this->originalPrefix = $db_prefix;
+    $clean_url_original = variable_get('clean_url', 0);
+    // END BLOCK FROM DrupalWebTestCase::setUp().
+ 
+    // Because the schema is static cached, we need to flush
+    // it between each run. If we don't, then it will contain
+    // stale data for the previous run's database prefix and all
+    // calls to it will fail.
+    $schemas = drupal_get_schema(NULL, TRUE);
+ 
+    // BEGIN BLOCK FROM DrupalWebTestCase::setUp().
+    // Generate temporary prefixed database to ensure that tests have a clean starting point.
+    $db_prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
+ 
+    // END BLOCK FROM DrupalWebTestCase::setUp().
+ 
+    // Copy each table into new database.
+    foreach ($schemas as $name => $schema) {
+      $this->cloneTable($name, $schema);
+    }
+ 
+    // BEGIN BLOCK FROM DrupalWebTestCase::setUp().
+    // Because the schema is static cached, we need to flush
+    // it between each run. If we don't, then it will contain
+    // stale data for the previous run's database prefix and all
+    // calls to it will fail.
+    drupal_get_schema(NULL, TRUE);
+ 
+    // Rebuild caches.
+    actions_synchronize();
+    _drupal_flush_css_js();
+    $this->refreshVariables();
+    $this->checkPermissions(array(), TRUE);
+ 
+    // Log in with a clean $user.
+    $this->originalUser = $user;
+    session_save_session(FALSE);
+    $user = user_load(array('uid' => 1));
+ 
+    // Restore necessary variables.
+    variable_set('install_profile', 'default');
+    variable_set('install_task', 'profile-finished');
+    variable_set('clean_url', $clean_url_original);
+    variable_set('site_mail', 'simpletest@example.com');
+ 
+    // Use temporary files directory with the same prefix as database.
+    $this->originalFileDirectory = file_directory_path();
+    variable_set('file_directory_path', file_directory_path() . '/' . $db_prefix);
+    $directory = file_directory_path();
+    file_check_directory($directory, FILE_CREATE_DIRECTORY); // Create the files directory.
+    set_time_limit($this->timeLimit);
+    //END BLOCK FROM DrupalWebTestCase::setUp().
+  }
+
+  /**
+   * Mirror over an existing tables structure, and copy the data.
+   *
+   * @param $name
+   *   Table name.
+   * @param $schema
+   *   A Schema API definition array.
+   * @return
+   *   Array of table creation results.
+   */
+  protected function cloneTable($name, $schema) {
+    $return = array();
+    db_create_table($return, $name, $schema);
+
+    if (!in_array($name, $this->cloneExcludes)) {
+      if ($name == 'users') {
+        // UID = 0 confuses mysql. Special handling here, taken from system.install
+        db_query("INSERT INTO :clone_table SELECT uid +1, name, pass, mail, mode, sort, threshold, theme, signature, created, access, login, status, timezone, language, picture, init, data, timezone_name FROM :main_table", array(':clone_table' => $this->db_prefix_test . $name, ':main_table' => $this->db_prefix_original . $name));
+        // Update uid.
+        db_query("UPDATE :table SET uid = uid - 1", array(':table' => $this->db_prefix_test . $name));
+      }
+      else {
+        // Copy over data (brackets are /not/ used or this wouldn't work).
+        db_query("INSERT INTO :clone_table SELECT * FROM :main_table", array(':clone_table' => $this->db_prefix_test . $name, ':main_table' => $this->db_prefix_original . $name));
+      }
+    }
+  }
+
+  /**
+   * Create a user with a given role.
+   *
+   * @param string $role
+   *   An existing user role.
+   */
+  protected function drupalCreateUserWithRole($role) {
+    $rid = $this->_getRoleId($role);
+    if ($rid) {
+      $user = $this->drupalCreateUser(array('access content'));
+      $edit['roles'] = array($rid => $rid);
+      $account = user_save($user, $edit);
+      $account->pass_raw = $user->pass_raw;
+      return $account;
+    }
+  }
+
+  /**
+   * Create normal authenticated user without any additional roles.
+   */
+  protected function drupalCreateNormalUser() {
+    $user = $this->drupalCreateUser(array('access content'));
+    $edit['roles'] = array();
+    $account = user_save($user, $edit);
+    $account->pass_raw = $user->pass_raw;
+    return $account;
+  }
+
+  /**
+   * Find the role ID for a given role name.
+   *
+   * @param string $name
+   *   The role name
+   * @return integer
+   *   The corresponding role ID.
+   */
+  private function _getRoleId($name) {
+    $rid = db_result(db_query("SELECT rid FROM {role} WHERE name = ':role'", array(':role' => $name)));
+    if (!$rid) {
+      $this->fail(t('No corresponding rid found for the %role role.', array('%role' => $name)));
+      return FALSE;
+    }
+    return $rid;
+  }
+}
