Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.206
diff -u -r1.206 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	27 Mar 2010 18:32:06 -0000	1.206
+++ modules/simpletest/drupal_web_test_case.php	31 Mar 2010 18:57:14 -0000
@@ -1148,31 +1148,7 @@
     $conf = array();
     drupal_static_reset();
 
-    include_once DRUPAL_ROOT . '/includes/install.inc';
-    drupal_install_system();
-
-    $this->preloadRegistry();
-
-    // Include the default profile.
-    variable_set('install_profile', 'standard');
-    $profile_details = install_profile_info('standard', 'en');
-
-    // Install the modules specified by the default 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
-    // $modules as a single array argument.
-    if (!is_array($modules)) {
-      $modules = func_get_args();
-    }
-    if ($modules) {
-      module_enable($modules, TRUE);
-    }
-
-    // Run default profile tasks.
-    module_enable(array('standard'), FALSE);
+    $this->setUpInstall(func_get_args());
 
     // Rebuild caches.
     drupal_static_reset();
@@ -1197,10 +1173,8 @@
     drupal_save_session(FALSE);
     $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');
+    $this->setUpVariables($clean_url_original);
+
     // Set up English language.
     unset($GLOBALS['conf']['language_default']);
     $language = language_default();
@@ -1217,6 +1191,47 @@
   }
 
   /**
+   * Perform Drupal installation.
+   */
+  protected function setUpInstall(array $modules = array()) {
+    include_once DRUPAL_ROOT . '/includes/install.inc';
+    drupal_install_system();
+
+    $this->preloadRegistry();
+
+    // Include the default profile.
+    variable_set('install_profile', 'standard');
+    $profile_details = install_profile_info('standard', 'en');
+
+    // Install the modules specified by the default 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
+    // $modules as a single array argument.
+    if (!is_array($modules)) {
+      $modules = func_get_args();
+    }
+    if ($modules) {
+      module_enable($modules, TRUE);
+    }
+
+    // Run default profile tasks.
+    module_enable(array('standard'), FALSE);
+  }
+
+  /**
+   * Set post-installation variables.
+   */
+  protected function setUpVariables($clean_url_original) {
+    // Restore necessary variables.
+    variable_set('install_task', 'done');
+    variable_set('clean_url', $clean_url_original);
+    variable_set('site_mail', 'simpletest@example.com');
+  }
+
+  /**
    * This method is called by DrupalWebTestCase::setUp, and preloads the
    * registry from the testing site to cut down on the time it takes to
    * setup a clean environment for the current test run.
@@ -2811,6 +2826,79 @@
 }
 
 /**
+ * Clone an existing database and use it for testing.
+ */
+class DrupalCloneTestCase extends DrupalWebTestCase {
+
+  /**
+   * Tables to exlude during data cloning, only their structure will be cloned.
+   *
+   * @var array
+   */
+  protected $excludeTables = array(
+    'cache',
+    'cache_block',
+    'cache_bootstrap',
+    'cache_field',
+    'cache_filter',
+    'cache_form',
+    'cache_image',
+    'cache_menu',
+    'cache_page',
+    'cache_path',
+    'cache_update',
+    'watchdog',
+  );
+
+  protected function setUpInstall() {
+    global $db_prefix;
+
+    // Store new database prefix.
+    $db_prefix_new = $db_prefix;
+    $db_prefix = $this->originalPrefix;
+
+    // Rebuild schema based on prefixed database and such.
+    $schemas = drupal_get_schema(NULL, TRUE);
+    // Create a list of prefixed source table names.
+    $sources = array();
+    foreach ($schemas as $name => $schema) {
+      $sources[$name] = Database::getConnection()->prefixTables('{' . $name . '}');
+    }
+
+    // Return to new prefix before performing cloning.
+    $db_prefix = $db_prefix_new;
+
+    // Clone each table into the new database.
+    foreach ($schemas as $name => $schema) {
+      $this->cloneTable($name, $sources[$name], $schema);
+    }
+  }
+
+  protected function setUpVariables() {
+    // Do nothing.
+  }
+
+  /**
+   * Clone an existing table structure and data.
+   *
+   * @param $name
+   *   Table name.
+   * @param $source
+   *   Source table name.
+   * @param $schema
+   *   A Schema API definition array.
+   */
+  protected function cloneTable($name, $source, $schema) {
+    db_create_table($name, $schema);
+
+    $target = Database::getConnection()->prefixTables('{' . $name . '}');
+    if (!in_array($name, $this->excludeTables)) {
+      db_query('INSERT INTO ' . $target . ' SELECT * FROM ' . $source);
+    }
+  }
+}
+
+/**
  * Log verbose message in a text file.
  *
  * If verbose mode is enabled then page requests will be dumped to a file and
