summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/bootstrap.inc62
-rw-r--r--includes/common.inc17
-rw-r--r--includes/database/database.inc152
-rw-r--r--includes/database/mysql/schema.inc2
-rw-r--r--includes/database/schema.inc4
-rw-r--r--includes/errors.inc3
-rw-r--r--includes/install.core.inc18
-rw-r--r--modules/simpletest/drupal_web_test_case.php192
-rw-r--r--modules/simpletest/simpletest.test5
-rw-r--r--sites/default/default.settings.php33
10 files changed, 311 insertions, 177 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index f1faa9a42..622914d65 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -560,7 +560,7 @@ function drupal_settings_initialize() {
global $base_url, $base_path, $base_root;
// Export the following settings.php variables to the global namespace
- global $databases, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;
+ global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;
$conf = array();
if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
@@ -2149,14 +2149,6 @@ function _drupal_bootstrap_page_cache() {
* Bootstrap database: Initialize database system and register autoload functions.
*/
function _drupal_bootstrap_database() {
- // 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 we
- // validate we ourselves made the request.
- if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) && !drupal_valid_test_ua($_SERVER['HTTP_USER_AGENT'])) {
- header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
- exit;
- }
-
// Redirect the user to the installation script if Drupal has not been
// installed yet (i.e., if no $databases array has been defined in the
// settings.php file) and we are not already installing.
@@ -2165,6 +2157,42 @@ function _drupal_bootstrap_database() {
install_goto('install.php');
}
+ // 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 we
+ // validate we ourselves made the request.
+ if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
+ if (!drupal_valid_test_ua($_SERVER['HTTP_USER_AGENT'])) {
+ header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
+ exit;
+ }
+
+ // The first part of the user agent is the prefix itself.
+ $test_prefix = $matches[1];
+
+ // Set the test run id for use in other parts of Drupal.
+ $test_info = &$GLOBALS['drupal_test_info'];
+ $test_info['test_run_id'] = $test_prefix;
+ $test_info['in_child_site'] = TRUE;
+
+ foreach ($GLOBALS['databases']['default'] as &$value) {
+ // Extract the current default database prefix.
+ if (!isset($value['prefix'])) {
+ $current_prefix = '';
+ }
+ else if (is_array($value['prefix'])) {
+ $current_prefix = $value['prefix']['default'];
+ }
+ else {
+ $current_prefix = $value['prefix'];
+ }
+
+ // Remove the current database prefix and replace it by our own.
+ $value['prefix'] = array(
+ 'default' => $current_prefix . $test_prefix,
+ );
+ }
+ }
+
// Initialize the database system. Note that the connection
// won't be initialized until it is actually requested.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
@@ -2222,15 +2250,15 @@ function drupal_get_bootstrap_phase() {
* Validate the HMAC and timestamp of a user agent header from simpletest.
*/
function drupal_valid_test_ua($user_agent) {
- global $databases;
+ global $drupal_hash_salt;
list($prefix, $time, $salt, $hmac) = explode(';', $user_agent);
$check_string = $prefix . ';' . $time . ';' . $salt;
- // We use the database credentials from settings.php to make the HMAC key, since
+ // We use the salt from settings.php to make the HMAC key, since
// the database is not yet initialized and we can't access any Drupal variables.
// The file properties add more entropy not easily accessible to others.
$filepath = DRUPAL_ROOT . '/includes/bootstrap.inc';
- $key = serialize($databases) . filectime($filepath) . fileinode($filepath);
+ $key = $drupal_hash_salt . filectime($filepath) . fileinode($filepath);
// The HMAC must match.
return $hmac == drupal_hmac_base64($check_string, $key);
}
@@ -2239,15 +2267,15 @@ function drupal_valid_test_ua($user_agent) {
* Generate a user agent string with a HMAC and timestamp for simpletest.
*/
function drupal_generate_test_ua($prefix) {
- global $databases;
+ global $drupal_hash_salt;
static $key;
if (!isset($key)) {
- // We use the database credentials to make the HMAC key, since we
- // check the HMAC before the database is initialized. filectime()
- // and fileinode() are not easily determined from remote.
+ // We use the salt from settings.php to make the HMAC key, since
+ // the database is not yet initialized and we can't access any Drupal variables.
+ // The file properties add more entropy not easily accessible to others.
$filepath = DRUPAL_ROOT . '/includes/bootstrap.inc';
- $key = serialize($databases) . filectime($filepath) . fileinode($filepath);
+ $key = $drupal_hash_salt . filectime($filepath) . fileinode($filepath);
}
// Generate a moderately secure HMAC based on the database credentials.
$salt = uniqid('', TRUE);
diff --git a/includes/common.inc b/includes/common.inc
index 83da25e2b..ebc8c1c07 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -766,8 +766,6 @@ function drupal_access_denied() {
* A string containing the response body that was received.
*/
function drupal_http_request($url, array $options = array()) {
- global $db_prefix;
-
$result = new stdClass();
// Parse the URL and make sure we can handle the schema.
@@ -867,8 +865,9 @@ function drupal_http_request($url, array $options = array()) {
// user-agent is used to ensure that multiple testing sessions running at the
// same time won't interfere with each other as they would if the database
// prefix were stored statically in a file or database variable.
- if (is_string($db_prefix) && preg_match("/simpletest\d+/", $db_prefix, $matches)) {
- $options['headers']['User-Agent'] = drupal_generate_test_ua($matches[0]);
+ $test_info = &$GLOBALS['drupal_test_info'];
+ if (!empty($test_info['test_run_id'])) {
+ $options['headers']['User-Agent'] = drupal_generate_test_ua($test_info['test_run_id']);
}
$request = $options['method'] . ' ' . $path . " HTTP/1.0\r\n";
@@ -4505,13 +4504,15 @@ function _drupal_bootstrap_full() {
module_load_all();
// Make sure all stream wrappers are registered.
file_get_stream_wrappers();
- if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'simpletest') !== FALSE) {
- // Valid SimpleTest user-agent, log fatal errors to test specific file
- // directory. The user-agent is validated in DRUPAL_BOOTSTRAP_DATABASE
- // phase so as long as it is a SimpleTest user-agent it is valid.
+
+ $test_info = &$GLOBALS['drupal_test_info'];
+ if (!empty($test_info['in_child_site'])) {
+ // Running inside the simpletest child site, log fatal errors to test
+ // specific file directory.
ini_set('log_errors', 1);
ini_set('error_log', file_directory_path() . '/error.log');
}
+
// Initialize $_GET['q'] prior to invoking hook_init().
drupal_path_initialize();
// Set a custom theme for the current page, if there is one. We need to run
diff --git a/includes/database/database.inc b/includes/database/database.inc
index a4f00dc46..6b878d99f 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -259,7 +259,26 @@ abstract class DatabaseConnection extends PDO {
*/
protected $schema = NULL;
+ /**
+ * The default prefix used by this database connection.
+ *
+ * Separated from the other prefixes for performance reasons.
+ *
+ * @var string
+ */
+ protected $defaultPrefix = '';
+
+ /**
+ * The non-default prefixes used by this database connection.
+ *
+ * @var array
+ */
+ protected $prefixes = array();
+
function __construct($dsn, $username, $password, $driver_options = array()) {
+ // Initialize and prepare the connection prefix.
+ $this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : '');
+
// Because the other methods don't seem to work right.
$driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
@@ -343,6 +362,25 @@ abstract class DatabaseConnection extends PDO {
}
/**
+ * Preprocess the prefixes used by this database connection.
+ *
+ * @param $prefix
+ * The prefixes, in any of the multiple forms documented in
+ * default.settings.php.
+ */
+ protected function setPrefix($prefix) {
+ if (is_array($prefix)) {
+ $this->defaultPrefix = isset($prefix['default']) ? $prefix['default'] : '';
+ unset($prefix['default']);
+ $this->prefixes = $prefix;
+ }
+ else {
+ $this->defaultPrefix = $prefix;
+ $this->prefixes = array();
+ }
+ }
+
+ /**
* Appends a database prefix to all tables in a query.
*
* Queries sent to Drupal should wrap all table names in curly brackets. This
@@ -357,27 +395,12 @@ abstract class DatabaseConnection extends PDO {
* The properly-prefixed string.
*/
public function prefixTables($sql) {
- global $db_prefix;
-
- if (is_array($db_prefix)) {
- if (array_key_exists('default', $db_prefix)) {
- $tmp = $db_prefix;
- unset($tmp['default']);
- foreach ($tmp as $key => $val) {
- $sql = strtr($sql, array('{' . $key . '}' => $val . $key));
- }
- return strtr($sql, array('{' => $db_prefix['default'] , '}' => ''));
- }
- else {
- foreach ($db_prefix as $key => $val) {
- $sql = strtr($sql, array('{' . $key . '}' => $val . $key));
- }
- return strtr($sql, array('{' => '' , '}' => ''));
- }
- }
- else {
- return strtr($sql, array('{' => $db_prefix , '}' => ''));
+ // Replace specific table prefixes first.
+ foreach ($this->prefixes as $key => $val) {
+ $sql = strtr($sql, array('{' . $key . '}' => $val . $key));
}
+ // Then replace remaining tables with the default prefix.
+ return strtr($sql, array('{' => $this->defaultPrefix , '}' => ''));
}
/**
@@ -387,17 +410,12 @@ abstract class DatabaseConnection extends PDO {
* is not used in prefixTables due to performance reasons.
*/
public function tablePrefix($table = 'default') {
- global $db_prefix;
- if (is_array($db_prefix)) {
- if (isset($db_prefix[$table])) {
- return $db_prefix[$table];
- }
- elseif (isset($db_prefix['default'])) {
- return $db_prefix['default'];
- }
- return '';
+ if (isset($this->prefixes[$table])) {
+ return $this->prefixes[$table];
+ }
+ else {
+ return $this->defaultPrefix;
}
- return $db_prefix;
}
/**
@@ -1314,6 +1332,20 @@ abstract class Database {
if (empty($value['driver'])) {
$database_info[$index][$target] = $database_info[$index][$target][mt_rand(0, count($database_info[$index][$target]) - 1)];
}
+
+ // Parse the prefix information.
+ if (!isset($database_info[$index][$target]['prefix'])) {
+ // Default to an empty prefix.
+ $database_info[$index][$target]['prefix'] = array(
+ 'default' => '',
+ );
+ }
+ else if (!is_array($database_info[$index][$target]['prefix'])) {
+ // Transform the flat form into an array form.
+ $database_info[$index][$target]['prefix'] = array(
+ 'default' => $database_info[$index][$target]['prefix'],
+ );
+ }
}
}
@@ -1373,7 +1405,58 @@ abstract class Database {
if (!empty(self::$databaseInfo[$key])) {
return self::$databaseInfo[$key];
}
+ }
+
+ /**
+ * Rename a connection and its corresponding connection information.
+ *
+ * @param $old_key
+ * The old connection key.
+ * @param $new_key
+ * The new connection key.
+ * @return
+ * TRUE in case of success, FALSE otherwise.
+ */
+ final public static function renameConnection($old_key, $new_key) {
+ if (empty(self::$databaseInfo)) {
+ self::parseConnectionInfo();
+ }
+ if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
+ // Migrate the database connection information.
+ self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
+ unset(self::$databaseInfo[$old_key]);
+
+ // Migrate over the DatabaseConnection object if it exists.
+ if (isset(self::$connections[$old_key])) {
+ self::$connections[$new_key] = self::$connections[$old_key];
+ unset(self::$connections[$old_key]);
+ }
+
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Remove a connection and its corresponding connection information.
+ *
+ * @param $key
+ * The connection key.
+ * @return
+ * TRUE in case of success, FALSE otherwise.
+ */
+ final public static function removeConnection($key) {
+ if (isset(self::$databaseInfo[$key])) {
+ unset(self::$databaseInfo[$key]);
+ unset(self::$connections[$key]);
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
}
/**
@@ -1386,8 +1469,6 @@ abstract class Database {
* The database target to open.
*/
final protected static function openConnection($key, $target) {
- global $db_prefix;
-
if (empty(self::$databaseInfo)) {
self::parseConnectionInfo();
}
@@ -1415,13 +1496,6 @@ abstract class Database {
$new_connection->setLogger(self::$logs[$key]);
}
- // We need to pass around the simpletest database prefix in the request
- // and we put that in the user_agent header. The header HMAC was already
- // validated in bootstrap.inc.
- if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
- $db_prefix_string = is_array($db_prefix) ? $db_prefix['default'] : $db_prefix;
- $db_prefix = $db_prefix_string . $matches[1];
- }
return $new_connection;
}
diff --git a/includes/database/mysql/schema.inc b/includes/database/mysql/schema.inc
index 6a173d4fe..7be5d0280 100644
--- a/includes/database/mysql/schema.inc
+++ b/includes/database/mysql/schema.inc
@@ -25,7 +25,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
const COMMENT_MAX_COLUMN = 255;
/**
- * Get information about the table and database name from the db_prefix.
+ * Get information about the table and database name from the prefix.
*
* @return
* A keyed array with information about the database, table name and prefix.
diff --git a/includes/database/schema.inc b/includes/database/schema.inc
index 91503002f..07212418f 100644
--- a/includes/database/schema.inc
+++ b/includes/database/schema.inc
@@ -170,11 +170,11 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
}
/**
- * Get information about the table name and schema from the db_prefix.
+ * Get information about the table name and schema from the prefix.
*
* @param
* Name of table to look prefix up for. Defaults to 'default' because thats
- * default key for db_prefix.
+ * default key for prefix.
* @return
* A keyed array with information about the schema, table name and prefix.
*/
diff --git a/includes/errors.inc b/includes/errors.inc
index 1047a6665..96bf8fdb2 100644
--- a/includes/errors.inc
+++ b/includes/errors.inc
@@ -182,7 +182,8 @@ function _drupal_log_error($error, $fatal = FALSE) {
// When running inside the testing framework, we relay the errors
// to the tested site by the way of HTTP headers.
- if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^simpletest\d+;/", $_SERVER['HTTP_USER_AGENT']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
+ $test_info = &$GLOBALS['drupal_test_info'];
+ if (!empty($test_info['in_child_site']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
// $number does not use drupal_static as it should not be reset
// as it uniquely identifies each PHP error.
static $number = 0;
diff --git a/includes/install.core.inc b/includes/install.core.inc
index 9a81a9b5c..e2e7752bc 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -800,7 +800,7 @@ function install_verify_completed_task() {
* Verifies the existing settings in settings.php.
*/
function install_verify_settings() {
- global $db_prefix, $databases;
+ global $databases;
// Verify existing settings (if any).
if (!empty($databases) && install_verify_pdo()) {
@@ -834,7 +834,7 @@ function install_verify_pdo() {
* The form API definition for the database configuration form.
*/
function install_settings_form($form, &$form_state, &$install_state) {
- global $databases, $db_prefix;
+ global $databases;
$profile = $install_state['parameters']['profile'];
$install_locale = $install_state['parameters']['locale'];
@@ -945,6 +945,10 @@ function install_settings_form($form, &$form_state, &$install_state) {
* Form API validate for install_settings form.
*/
function install_settings_form_validate($form, &$form_state) {
+ // TODO: remove when PIFR will be updated to use 'db_prefix' instead of
+ // 'prefix' in the database settings form.
+ $form_state['values']['prefix'] = $form_state['values']['db_prefix'];
+
form_set_value($form['_database'], $form_state['values'], $form_state);
$errors = install_database_errors($form_state['values'], $form_state['values']['settings_file']);
foreach ($errors as $name => $message) {
@@ -959,8 +963,8 @@ function install_database_errors($database, $settings_file) {
global $databases;
$errors = array();
// Verify the table prefix.
- if (!empty($database['db_prefix']) && is_string($database['db_prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['db_prefix'])) {
- $errors['db_prefix'] = st('The database table prefix you have entered, %db_prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%db_prefix' => $database['db_prefix']));
+ if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
+ $errors['prefix'] = st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $database['prefix']));
}
if (!empty($database['port']) && !is_numeric($database['port'])) {
@@ -1000,16 +1004,12 @@ function install_database_errors($database, $settings_file) {
function install_settings_form_submit($form, &$form_state) {
global $install_state;
- $database = array_intersect_key($form_state['values']['_database'], array_flip(array('driver', 'database', 'username', 'password', 'host', 'port')));
+ $database = array_intersect_key($form_state['values']['_database'], array_flip(array('driver', 'database', 'username', 'password', 'host', 'port', 'prefix')));
// Update global settings array and save.
$settings['databases'] = array(
'value' => array('default' => array('default' => $database)),
'required' => TRUE,
);
- $settings['db_prefix'] = array(
- 'value' => $form_state['values']['db_prefix'],
- 'required' => TRUE,
- );
$settings['drupal_hash_salt'] = array(
'value' => drupal_hash_base64(drupal_random_bytes(55)),
'required' => TRUE,
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 3232c9df6..d96db0cce 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -2,6 +2,18 @@
// $Id$
/**
+ * Global variable that holds information about the tests being run.
+ *
+ * An array, with the following keys:
+ * - 'test_run_id': the ID of the test being run, in the form 'simpletest_%"
+ * - 'in_child_site': TRUE if the current request is a cURL request from
+ * the parent site.
+ *
+ * @var array
+ */
+global $drupal_test_info;
+
+/**
* Base class for Drupal tests.
*
* Do not extend this class, use one of the subclasses in this file.
@@ -15,11 +27,11 @@ abstract class DrupalTestCase {
protected $testId;
/**
- * The original database prefix, before it was changed for testing purposes.
+ * The database prefix of this test run.
*
* @var string
*/
- protected $originalPrefix = NULL;
+ protected $databasePrefix = NULL;
/**
* The original file directory, before it was changed for testing purposes.
@@ -90,8 +102,6 @@ abstract class DrupalTestCase {
* is the caller function itself.
*/
protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) {
- global $db_prefix;
-
// Convert boolean status to string status.
if (is_bool($status)) {
$status = $status ? 'pass' : 'fail';
@@ -105,10 +115,6 @@ abstract class DrupalTestCase {
$caller = $this->getAssertionCall();
}
- // Switch to non-testing database to store results in.
- $current_db_prefix = $db_prefix;
- $db_prefix = $this->originalPrefix;
-
// Creation assertion array that can be displayed while tests are running.
$this->assertions[] = $assertion = array(
'test_id' => $this->testId,
@@ -122,12 +128,11 @@ abstract class DrupalTestCase {
);
// Store assertion for display after the test has completed.
- db_insert('simpletest')
+ Database::getConnection('default', 'simpletest_original_default')
+ ->insert('simpletest')
->fields($assertion)
->execute();
- // Return to testing prefix.
- $db_prefix = $current_db_prefix;
// We do not use a ternary operator here to allow a breakpoint on
// test failure.
if ($status == 'pass') {
@@ -560,10 +565,9 @@ class DrupalUnitTestCase extends DrupalTestCase {
}
protected function setUp() {
- global $db_prefix, $conf;
+ global $conf;
- // Store necessary current values before switching to prefixed database.
- $this->originalPrefix = $db_prefix;
+ // Store necessary current values before switching to the test environment.
$this->originalFileDirectory = file_directory_path();
spl_autoload_register('db_autoload');
@@ -572,11 +576,21 @@ class DrupalUnitTestCase extends DrupalTestCase {
drupal_static_reset();
// Generate temporary prefixed database to ensure that tests have a clean starting point.
- $db_prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
- $conf['file_public_path'] = $this->originalFileDirectory . '/' . $db_prefix;
+ $this->databasePrefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
+ $conf['file_public_path'] = $this->originalFileDirectory . '/' . $this->databasePrefix;
+
+ // Clone the current connection and replace the current prefix.
+ $connection_info = Database::getConnectionInfo('default');
+ Database::renameConnection('default', 'simpletest_original_default');
+ foreach ($connection_info as $target => $value) {
+ $connection_info[$target]['prefix'] = array(
+ 'default' => $value['prefix']['default'] . $this->databasePrefix,
+ );
+ }
+ Database::addConnectionInfo('default', 'default', $connection_info['default']);
// Set user agent to be consistent with web test case.
- $_SERVER['HTTP_USER_AGENT'] = $db_prefix;
+ $_SERVER['HTTP_USER_AGENT'] = $this->databasePrefix;
// If locale is enabled then t() will try to access the database and
// subsequently will fail as the database is not accessible.
@@ -589,15 +603,16 @@ class DrupalUnitTestCase extends DrupalTestCase {
}
protected function tearDown() {
- global $db_prefix, $conf;
- if (preg_match('/simpletest\d+/', $db_prefix)) {
- $conf['file_public_path'] = $this->originalFileDirectory;
- // Return the database prefix to the original.
- $db_prefix = $this->originalPrefix;
- // Restore modules if necessary.
- if (isset($this->originalModuleList)) {
- module_list(TRUE, FALSE, FALSE, $this->originalModuleList);
- }
+ global $conf;
+
+ // Get back to the original connection.
+ Database::removeConnection('default');
+ Database::renameConnection('simpletest_original_default', 'default');
+
+ $conf['file_public_path'] = $this->originalFileDirectory;
+ // Restore modules if necessary.
+ if (isset($this->originalModuleList)) {
+ module_list(TRUE, FALSE, FALSE, $this->originalModuleList);
}
}
}
@@ -1107,12 +1122,28 @@ class DrupalWebTestCase extends DrupalTestCase {
* either a single array or a variable number of string arguments.
*/
protected function setUp() {
- global $db_prefix, $user, $language, $conf;
+ global $user, $language, $conf;
+
+ // 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')
+ ->fields(array('last_prefix' => $this->databasePrefix))
+ ->condition('test_id', $this->testId)
+ ->execute();
+
+ // Clone the current connection and replace the current prefix.
+ $connection_info = Database::getConnectionInfo('default');
+ Database::renameConnection('default', 'simpletest_original_default');
+ foreach ($connection_info as $target => $value) {
+ $connection_info[$target]['prefix'] = array(
+ 'default' => $value['prefix']['default'] . $this->databasePrefix,
+ );
+ }
+ Database::addConnectionInfo('default', 'default', $connection_info['default']);
// Store necessary current values before switching to prefixed database.
$this->originalLanguage = $language;
$this->originalLanguageDefault = variable_get('language_default');
- $this->originalPrefix = $db_prefix;
$this->originalFileDirectory = file_directory_path();
$this->originalProfile = drupal_get_profile();
$clean_url_original = variable_get('clean_url', 0);
@@ -1125,18 +1156,10 @@ class DrupalWebTestCase extends DrupalTestCase {
$this->originalShutdownCallbacks = $callbacks;
$callbacks = array();
- // Generate temporary prefixed database to ensure that tests have a clean starting point.
- $db_prefix_new = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
- db_update('simpletest_test_id')
- ->fields(array('last_prefix' => $db_prefix_new))
- ->condition('test_id', $this->testId)
- ->execute();
- $db_prefix = $db_prefix_new;
-
// Create test directory ahead of installation so fatal errors and debug
// information can be logged during installation process.
// Use temporary files directory with the same prefix as the database.
- $public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($db_prefix, 10);
+ $public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
$private_files_directory = $public_files_directory . '/private';
$temp_files_directory = $private_files_directory . '/temp';
@@ -1154,6 +1177,11 @@ class DrupalWebTestCase extends DrupalTestCase {
$conf = array();
drupal_static_reset();
+ // Set the test information for use in other parts of Drupal.
+ $test_info = &$GLOBALS['drupal_test_info'];
+ $test_info['test_run_id'] = $this->databasePrefix;
+ $test_info['in_child_site'] = FALSE;
+
include_once DRUPAL_ROOT . '/includes/install.inc';
drupal_install_system();
@@ -1230,8 +1258,9 @@ class DrupalWebTestCase extends DrupalTestCase {
* setup a clean environment for the current test run.
*/
protected function preloadRegistry() {
- db_query('INSERT INTO {registry} SELECT * FROM ' . $this->originalPrefix . 'registry');
- db_query('INSERT INTO {registry_file} SELECT * FROM ' . $this->originalPrefix . 'registry_file');
+ $original_connection = Database::getConnection('default', 'simpletest_original_default');
+ db_query('INSERT INTO {registry} SELECT * FROM ' . $original_connection->prefixTables('{registry}'));
+ db_query('INSERT INTO {registry_file} SELECT * FROM ' . $original_connection->prefixTables('{registry_file}'));
}
/**
@@ -1257,14 +1286,11 @@ class DrupalWebTestCase extends DrupalTestCase {
* and reset the database prefix.
*/
protected function tearDown() {
- global $db_prefix, $user, $language;
+ global $user, $language;
// In case a fatal error occured that was not in the test process read the
// log to pick up any fatal errors.
- $db_prefix_temp = $db_prefix;
- $db_prefix = $this->originalPrefix;
- simpletest_log_read($this->testId, $db_prefix, get_class($this), TRUE);
- $db_prefix = $db_prefix_temp;
+ simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE);
$emailCount = count(variable_get('drupal_test_email_collector', array()));
if ($emailCount) {
@@ -1272,53 +1298,52 @@ class DrupalWebTestCase extends DrupalTestCase {
$this->pass($message, t('E-mail'));
}
- if (preg_match('/simpletest\d+/', $db_prefix)) {
- // Delete temporary files directory.
- file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($db_prefix, 10));
+ // Delete temporary files directory.
+ file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10));
- // Remove all prefixed tables (all the tables in the schema).
- $schema = drupal_get_schema(NULL, TRUE);
- $ret = array();
- foreach ($schema as $name => $table) {
- db_drop_table($name);
- }
-
- // Return the database prefix to the original.
- $db_prefix = $this->originalPrefix;
+ // Remove all prefixed tables (all the tables in the schema).
+ $schema = drupal_get_schema(NULL, TRUE);
+ $ret = array();
+ foreach ($schema as $name => $table) {
+ db_drop_table($name);
+ }
- // Restore original shutdown callbacks array to prevent original
- // environment of calling handlers from test run.
- $callbacks = &drupal_register_shutdown_function();
- $callbacks = $this->originalShutdownCallbacks;
+ // Get back to the original connection.
+ Database::removeConnection('default');
+ Database::renameConnection('simpletest_original_default', 'default');
- // Return the user to the original one.
- $user = $this->originalUser;
- drupal_save_session(TRUE);
+ // Restore original shutdown callbacks array to prevent original
+ // environment of calling handlers from test run.
+ $callbacks = &drupal_register_shutdown_function();
+ $callbacks = $this->originalShutdownCallbacks;
- // Ensure that internal logged in variable and cURL options are reset.
- $this->loggedInUser = FALSE;
- $this->additionalCurlOptions = array();
+ // Return the user to the original one.
+ $user = $this->originalUser;
+ drupal_save_session(TRUE);
- // Reload module list and implementations to ensure that test module hooks
- // aren't called after tests.
- module_list(TRUE);
- module_implements('', FALSE, TRUE);
+ // Ensure that internal logged in variable and cURL options are reset.
+ $this->loggedInUser = FALSE;
+ $this->additionalCurlOptions = array();
- // Reset the Field API.
- field_cache_clear();
+ // Reload module list and implementations to ensure that test module hooks
+ // aren't called after tests.
+ module_list(TRUE);
+ module_implements('', FALSE, TRUE);
- // Rebuild caches.
- $this->refreshVariables();
+ // Reset the Field API.
+ field_cache_clear();
- // Reset language.
- $language = $this->originalLanguage;
- if ($this->originalLanguageDefault) {
- $GLOBALS['conf']['language_default'] = $this->originalLanguageDefault;
- }
+ // Rebuild caches.
+ $this->refreshVariables();
- // Close the CURL handler.
- $this->curlClose();
+ // Reset language.
+ $language = $this->originalLanguage;
+ if ($this->originalLanguageDefault) {
+ $GLOBALS['conf']['language_default'] = $this->originalLanguageDefault;
}
+
+ // Close the CURL handler.
+ $this->curlClose();
}
/**
@@ -1330,7 +1355,7 @@ class DrupalWebTestCase extends DrupalTestCase {
* See the description of $curl_options for other options.
*/
protected function curlInitialize() {
- global $base_url, $db_prefix;
+ global $base_url;
if (!isset($this->curlHandle)) {
$this->curlHandle = curl_init();
@@ -1342,6 +1367,7 @@ class DrupalWebTestCase extends DrupalTestCase {
CURLOPT_SSL_VERIFYPEER => FALSE, // Required to make the tests run on https.
CURLOPT_SSL_VERIFYHOST => FALSE, // Required to make the tests run on https.
CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'),
+ CURLOPT_USERAGENT => $this->databasePrefix,
);
if (isset($this->httpauth_credentials)) {
$curl_options[CURLOPT_HTTPAUTH] = $this->httpauth_method;
@@ -1354,7 +1380,7 @@ class DrupalWebTestCase extends DrupalTestCase {
}
// We set the user agent header on each request so as to use the current
// time and a new uniqid.
- if (preg_match('/simpletest\d+/', $db_prefix, $matches)) {
+ if (preg_match('/simpletest\d+/', $this->databasePrefix, $matches)) {
curl_setopt($this->curlHandle, CURLOPT_USERAGENT, drupal_generate_test_ua($matches[0]));
}
}
diff --git a/modules/simpletest/simpletest.test b/modules/simpletest/simpletest.test
index b3522f962..13cd5ae42 100644
--- a/modules/simpletest/simpletest.test
+++ b/modules/simpletest/simpletest.test
@@ -272,10 +272,11 @@ class SimpleTestFunctionalTest extends DrupalWebTestCase {
/**
* Check if the test is being run from inside a CURL request.
- *
- * @return The test is being run from inside a CURL request.
*/
function inCURL() {
+ // We cannot rely on drupal_static('drupal_test_info') here, because
+ // 'in_child_site' would be FALSE for the parent site when we are
+ // executing the tests. Default to direct detection of the HTTP headers.
return isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^simpletest\d+/", $_SERVER['HTTP_USER_AGENT']);
}
}
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index 549898c6c..1b5fbd44d 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -61,6 +61,7 @@
* 'password' => 'password',
* 'host' => 'localhost',
* 'port' => 3306,
+ * 'prefix' => 'myprefix_',
* );
*
* The "driver" property indicates what Drupal database driver the
@@ -106,44 +107,45 @@
* 'username' => 'username',
* 'password' => 'password',
* 'host' => 'localhost',
+ * 'prefix' => 'main_',
* );
*
* You can optionally set prefixes for some or all database table names
- * by using the $db_prefix setting. If a prefix is specified, the table
+ * by using the 'prefix' setting. If a prefix is specified, the table
* name will be prepended with its value. Be sure to use valid database
* characters only, usually alphanumeric and underscore. If no prefixes
* are desired, leave it as an empty string ''.
*
- * To have all database names prefixed, set $db_prefix as a string:
+ * To have all database names prefixed, set 'prefix' as a string:
*
- * $db_prefix = 'main_';
+ * 'prefix' => 'main_',
*
- * To provide prefixes for specific tables, set $db_prefix as an array.
+ * To provide prefixes for specific tables, set 'prefix' as an array.
* The array's keys are the table names and the values are the prefixes.
- * The 'default' element holds the prefix for any tables not specified
- * elsewhere in the array. Example:
+ * The 'default' element is mandatory and holds the prefix for any tables
+ * not specified elsewhere in the array. Example:
*
- * $db_prefix = array(
+ * 'prefix' => array(
* 'default' => 'main_',
- * 'users' => 'shared_',
+ * 'users' => 'shared_',
* 'sessions' => 'shared_',
* 'role' => 'shared_',
* 'authmap' => 'shared_',
- * );
+ * ),
*
- * You can also use db_prefix as a reference to a schema/database. This maybe
+ * You can also use a reference to a schema/database as a prefix. This maybe
* useful if your Drupal installation exists in a schema that is not the default
* or you want to access several databases from the same code base at the same
* time.
* Example:
*
- * $db_prefix = array(
- * 'default' => 'main.',
- * 'users' => 'shared.',
+ * 'prefix' => array(
+ * 'default' => 'main.',
+ * 'users' => 'shared.',
* 'sessions' => 'shared.',
* 'role' => 'shared.',
* 'authmap' => 'shared.',
- * );
+ * );
*
* NOTE: MySQL and SQLite's definition of a schema is a database.
*
@@ -154,6 +156,7 @@
* 'username' => 'username',
* 'password' => 'password',
* 'host' => 'localhost',
+ * 'prefix' => '',
* );
* $databases['default']['default'] = array(
* 'driver' => 'pgsql',
@@ -161,6 +164,7 @@
* 'username' => 'username',
* 'password' => 'password',
* 'host' => 'localhost',
+ * 'prefix' => '',
* );
* $databases['default']['default'] = array(
* 'driver' => 'sqlite',
@@ -168,7 +172,6 @@
* );
*/
$databases = array();
-$db_prefix = '';
/**
* Access control for update.php script.