Extend SimpleTest to allow for cloning of an existing site. From: <> --- modules/simpletest/drupal_web_test_case.php | 165 +++++++++++++++++++++++++++ 1 files changed, 165 insertions(+), 0 deletions(-) diff --git modules/simpletest/drupal_web_test_case.php modules/simpletest/drupal_web_test_case.php index 424e1f3..5a3464a 100644 --- modules/simpletest/drupal_web_test_case.php +++ modules/simpletest/drupal_web_test_case.php @@ -2128,3 +2128,168 @@ 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(). + } + + /** + * Correctly prefix a table name. + * + * This code is based off of core's db_prefix_tables(). + * + * @param $db_prefix + * Mixed array or string with prefixes. + * @param $name + * String with the table name. + * @return + * String with prefixed table name. + */ + function prefixTable($db_prefix, $name) { + if (is_array($db_prefix)) { + if (array_key_exists($name, $db_prefix)) { + return $db_prefix[$name] . $name; + } + elseif (array_key_exists('default', $db_prefix)) { + return $db_prefix['default'] . $name; + } + return $name; + } + return $db_prefix . $name; + } + + /** + * 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) { + global $db_prefix; + + $return = array(); + db_create_table($return, $name, $schema); + + // Do our own prefixing of the table names. + $source = db_escape_table($this->prefixTable($this->originalPrefix, $name)); + $target = db_escape_table($this->prefixTable($db_prefix, $name)); + + if (!in_array($name, $this->cloneExcludes)) { + if ($name == 'users') { + // UID = 0 confuses mysql. Special handling here, taken from system.install + db_query("INSERT INTO $target (uid, name, pass, mail, mode, sort, threshold, theme, signature, created, access, login, status, timezone, language, picture, init, data) + SELECT uid + 1, name, pass, mail, mode, sort, threshold, theme, signature, created, access, login, status, timezone, language, picture, init, data FROM $source"); + // Update uid + db_query("UPDATE $target SET uid = uid - 1"); + } + else { + db_query("INSERT INTO $target SELECT * FROM $source"); + } + } + } + + /** + * Create a user with a given role. + * + * @param string $role + * An existing user role. + */ + protected function drupalCreateUserWithRole($role) { + $roles = array_flip(user_roles()); + $rid = $roles[$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; + } + else { + $this->fail(t('No corresponding rid found for the %role role.', array('%role' => $name))); + return FALSE; + } + } + + /** + * DrupalWebTestCase's tearDown() rebuilds module_list() in bootstrap mode. + * This will cause things like drupal_get_schema() to only think devel + * modules are loaded. Put it back into run mode. + */ + function tearDown() { + parent::tearDown(); + module_list(TRUE, FALSE); + } +}