/** * @param string[] $classes * * @return array */ protected static function buildSnapshot($classes) { $observations = array(); // Test that all classes are available immediately at boot time. foreach ($classes as $class) { $observations['class_exists'][$class] = class_exists($class); } // Check variable_get(). // @FIXME // // @FIXME // // The correct configuration object could not be determined. You'll need to // // rewrite this call manually. // $observations[XAUTOLOAD_VARNAME_CACHE_TYPES] = variable_get(XAUTOLOAD_VARNAME_CACHE_TYPES); // @FIXME // // @FIXME // // The correct configuration object could not be determined. You'll need to // // rewrite this call manually. // $observations[XAUTOLOAD_VARNAME_CACHE_LAZY] = variable_get(XAUTOLOAD_VARNAME_CACHE_LAZY); $observations['db_connection_info'] = \Database::getConnectionInfo(); $spl_autoload_stack = array(); foreach (spl_autoload_functions() as $callback) { $spl_autoload_stack[] = Util::callbackToString($callback); } $observations['spl_autoload_functions'] = $spl_autoload_stack; return $observations; }
/** * Get site default global prefix * * @return string */ public static function getGlobalPrefix() { // Provide a fallback for multisite. This is on purpose not inside the // getPrefixForBin() function in order to decouple the unified prefix // variable logic and custom module related security logic, that is not // necessary for all backends. We can't just use HTTP_HOST, as multiple // hosts might be using the same database. Or, more commonly, a site // might not be a multisite at all, but might be using Drush leading to // a separate HTTP_HOST of 'default'. Likewise, we can't rely on // conf_path(), as settings.php might be modifying what database to // connect to. To mirror what core does with database caching we use // the DB credentials to inform our cache key. if (null === self::$globalPrefix) { if (isset($GLOBALS['db_url'])) { // Drupal 6 specifics when using the cache_backport module, we // therefore cannot use \Database class to determine database // settings. self::$globalPrefix = md5($GLOBALS['db_url']); } else { require_once DRUPAL_ROOT . '/includes/database/database.inc'; $dbInfo = Database::getConnectionInfo(); $active = $dbInfo['default']; self::$globalPrefix = md5($active['host'] . $active['database'] . $active['prefix']['default']); } } return self::$globalPrefix; }
/** * Get information about the table and database name from the prefix. * * @return * A keyed array with information about the database, table name and prefix. */ protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) { $info = array('prefix' => $this->connection->tablePrefix($table)); if ($add_prefix) { $table = $info['prefix'] . $table; } if (($pos = strpos($table, '.')) !== FALSE) { $info['database'] = substr($table, 0, $pos); $info['table'] = substr($table, ++$pos); } else { $db_info = Database::getConnectionInfo(); $info['database'] = $db_info['default']['database']; $info['table'] = $table; } return $info; }
/** * @param string[] $classes * * @return array */ protected static function buildSnapshot($classes) { $observations = array(); // Test that all classes are available immediately at boot time. foreach ($classes as $class) { $observations['class_exists'][$class] = class_exists($class); } // Check variable_get(). $observations[XAUTOLOAD_VARNAME_CACHE_TYPES] = variable_get(XAUTOLOAD_VARNAME_CACHE_TYPES); $observations[XAUTOLOAD_VARNAME_CACHE_LAZY] = variable_get(XAUTOLOAD_VARNAME_CACHE_LAZY); $observations['db_connection_info'] = \Database::getConnectionInfo(); $spl_autoload_stack = array(); foreach (spl_autoload_functions() as $callback) { $spl_autoload_stack[] = Util::callbackToString($callback); } $observations['spl_autoload_functions'] = $spl_autoload_stack; return $observations; }
/** * Before calling this we need to be bootstrapped to DRUPAL_BOOTSTRAP_SESSION. */ function registry_rebuild_rebuild() { // This section is not functionally important. It's just using the // registry_get_parsed_files() so that it can report the change. Drupal 7 only. if (function_exists('registry_rebuild')) { $connection_info = Database::getConnectionInfo(); $driver = $connection_info['default']['driver']; global $include_dir; require_once $include_dir . '/database/' . $driver . '/query.inc'; $parsed_before = registry_get_parsed_files(); } // Separate bootstrap cache exists only in Drupal 7 or newer. // They are cleared later again via drupal_flush_all_caches(). if (function_exists('registry_rebuild')) { // D7 cache_clear_all('lookup_cache', 'cache_bootstrap'); cache_clear_all('variables', 'cache_bootstrap'); cache_clear_all('module_implements', 'cache_bootstrap'); print "Bootstrap caches have been cleared in DRUPAL_BOOTSTRAP_SESSION<br/>\n"; } elseif (!function_exists('cache_clear_all')) { // D8+ cache('bootstrap')->deleteAll(); print "Bootstrap caches have been cleared in DRUPAL_BOOTSTRAP_SESSION<br/>\n"; } // We later run system_rebuild_module_data() and registry_update() on Drupal 7 via // D7-only registry_rebuild() wrapper, which is run inside drupal_flush_all_caches(). // It is an equivalent of module_rebuild_cache() in D5-D6 and is normally run via // our universal wrapper registry_rebuild_cc_all() -- see further below. // However, we are still on the DRUPAL_BOOTSTRAP_SESSION level here, // and we want to make the initial rebuild as atomic as possible, so we can't // run everything from registry_rebuild_cc_all() yet, so we run an absolute // minimum we can at this stage, core specific. if (function_exists('registry_rebuild')) { // D7 only print "Doing registry_rebuild() in DRUPAL_BOOTSTRAP_SESSION<br/>\n"; registry_rebuild(); } elseif (!function_exists('registry_rebuild') && function_exists('system_rebuild_module_data')) { // D8+ print "Doing system_rebuild_module_data() in DRUPAL_BOOTSTRAP_SESSION<br/>\n"; system_rebuild_module_data(); } else { // D5-D6 print "Doing module_rebuild_cache() in DRUPAL_BOOTSTRAP_SESSION<br/>\n"; module_list(TRUE, FALSE); module_rebuild_cache(); } print "Bootstrapping to DRUPAL_BOOTSTRAP_FULL<br/>\n"; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); // We can run our wrapper now, since we are in a full bootstrap already. print "Rebuilding registry via registry_rebuild_cc_all in DRUPAL_BOOTSTRAP_FULL<br/>\n"; registry_rebuild_cc_all(); // Extra cleanup available for D7 only. if (function_exists('registry_rebuild')) { $parsed_after = registry_get_parsed_files(); // Remove files which don't exist anymore. $filenames = array(); foreach ($parsed_after as $filename => $file) { if (!file_exists($filename)) { $filenames[] = $filename; } } if (!empty($filenames)) { db_delete('registry_file')->condition('filename', $filenames)->execute(); db_delete('registry')->condition('filename', $filenames)->execute(); print "Deleted " . count($filenames) . ' stale files from registry manually.'; } $parsed_after = registry_get_parsed_files(); print "There were " . count($parsed_before) . " files in the registry before and " . count($parsed_after) . " files now.<br/>\n"; registry_rebuild_cc_all(); } print "If you don't see any crazy fatal errors, your registry has been rebuilt.<br/>\n"; }
/** * Delete created files and temporary files directory, delete the tables created by setUp(), * and reset the database prefix. */ protected function tearDown() { global $user, $language, $settings, $config_directories; // In case a fatal error occurred that was not in the test process read the // log to pick up any fatal errors. simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE); $emailCount = count(state_get('test_email_collector', array())); if ($emailCount) { $message = format_plural($emailCount, '1 e-mail was sent during this test.', '@count e-mails were sent during this test.'); $this->pass($message, t('E-mail')); } // Delete temporary files directory. file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10)); // Remove all prefixed tables. $connection_info = Database::getConnectionInfo('default'); $tables = db_find_tables($connection_info['default']['prefix']['default'] . '%'); if (empty($tables)) { $this->fail('Failed to find test tables to drop.'); } $prefix_length = strlen($connection_info['default']['prefix']['default']); foreach ($tables as $table) { if (db_drop_table(substr($table, $prefix_length))) { unset($tables[$table]); } } if (!empty($tables)) { $this->fail('Failed to drop all prefixed tables.'); } // Get back to the original connection. Database::removeConnection('default'); Database::renameConnection('simpletest_original_default', 'default'); // Delete the database table prefix record. db_delete('simpletest_prefix')->condition('test_id', $this->testId)->condition('prefix', $this->databasePrefix)->execute(); // Set the configuration direcotires back to the originals. $config_directories = $this->originalConfigDirectories; // Restore the original settings. $settings = $this->originalSettings; // Restore original shutdown callbacks array to prevent original // environment of calling handlers from test run. $callbacks =& backdrop_register_shutdown_function(); $callbacks = $this->originalShutdownCallbacks; // Return the user to the original one. $user = $this->originalUser; backdrop_save_session(TRUE); // Ensure that internal logged in variable and cURL options are reset. $this->loggedInUser = FALSE; $this->additionalCurlOptions = array(); // Reload module list and implementations to ensure that test module hooks // aren't called after tests. module_list(TRUE); module_implements_reset(); // Reset the Field API. field_cache_clear(); // Rebuild caches. $this->refreshVariables(); // Reset public files directory. $GLOBALS['conf']['file_public_path'] = $this->originalFileDirectory; // Reset language. $language = $this->originalLanguage; if ($this->originalLanguageDefault) { $GLOBALS['conf']['language_default'] = $this->originalLanguageDefault; } // Close the CURL handler. $this->curlClose(); }
/** * Generates a random database prefix, runs the install scripts on the * prefixed database and enable the specified modules. After installation * many caches are flushed and the internal browser is setup so that the * page requests will run on the new prefix. A temporary files directory * is created with the same name as the database prefix. * * @param ... * List of modules to enable for the duration of the test. This can be * either a single array or a variable number of string arguments. */ protected function setUp() { 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->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); $this->originalProfile = drupal_get_profile(); $clean_url_original = variable_get('clean_url', 0); // Set to English to prevent exceptions from utf8_truncate() from t() // during install if the current language is not 'en'. // The following array/object conversion is copied from language_default(). $language = (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => ''); // Save and clean shutdown callbacks array because it static cached and // will be changed by the test run. If we don't, then it will contain // callbacks from both environments. So testing environment will try // to call handlers from original environment. $callbacks =& drupal_register_shutdown_function(); $this->originalShutdownCallbacks = $callbacks; $callbacks = array(); // 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($this->databasePrefix, 10); $private_files_directory = $public_files_directory . '/private'; $temp_files_directory = $private_files_directory . '/temp'; // Create the directories file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); file_prepare_directory($private_files_directory, FILE_CREATE_DIRECTORY); file_prepare_directory($temp_files_directory, FILE_CREATE_DIRECTORY); $this->generatedTestFiles = FALSE; // Log fatal errors. ini_set('log_errors', 1); ini_set('error_log', $public_files_directory . '/error.log'); // Reset all statics and variables to perform tests in a clean environment. $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(); $this->preloadRegistry(); // Set path variables. variable_set('file_public_path', $public_files_directory); variable_set('file_private_path', $private_files_directory); variable_set('file_temporary_path', $temp_files_directory); // 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 // $modules as a single array argument. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; } if ($modules) { $success = module_enable($modules, TRUE); $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/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); $user = user_load(1); // Restore necessary variables. variable_set('install_task', 'done'); variable_set('clean_url', $clean_url_original); variable_set('site_mail', '*****@*****.**'); variable_set('date_default_timezone', date_default_timezone_get()); // Set up English language. unset($GLOBALS['conf']['language_default']); $language = language_default(); // Use the test mail class instead of the default mail handler class. variable_set('mail_system', array('default-system' => 'TestingMailSystem')); drupal_set_time_limit($this->timeLimit); }
/** * Determine when to run against remote environment. */ protected function setUp() { // // BEGIN: Excerpt from DrupalUnitTestCase. // global $conf; // // Set to that verbose mode works properly. $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); // // spl_autoload_register('db_autoload'); // // // Reset all statics so that test is performed with a clean environment. // drupal_static_reset(); // // // Generate temporary prefixed database to ensure that tests have a clean starting point. // $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'] = $this->databasePrefix; // // // If locale is enabled then t() will try to access the database and // // subsequently will fail as the database is not accessible. // $module_list = module_list(); // if (isset($module_list['locale'])) { // $this->originalModuleList = $module_list; // unset($module_list['locale']); // module_list(TRUE, FALSE, FALSE, $module_list); // } // // END: Excerpt from DrupalUnitTestCase. if (!$this->remoteUrl && !($this->remoteUrl = variable_get('simpletest_remote_url', FALSE))) { $this->remoteUrl = url('', array('absolute' => TRUE)); } // Point the internal browser to the staging site. foreach (self::$URL_VARIABLES as $variable) { $this->originalUrls[$variable] = $GLOBALS[$variable]; $GLOBALS[$variable] = $this->remoteUrl; } $GLOBALS['base_secure_url'] = str_replace('http://', 'https://', $GLOBALS['base_secure_url']); // Generate unique remote prefix. self::$REMOTE_PREFIX = 'test' . mt_rand(100, 100000); // Set the time-limit for the test case. drupal_set_time_limit($this->timeLimit); }
/** * Generates a random database prefix, runs the install scripts on the * prefixed database and enable the specified modules. After installation * many caches are flushed and the internal browser is setup so that the * page requests will run on the new prefix. A temporary files directory * is created with the same name as the database prefix. * * @param ... * List of modules to enable for the duration of the test. This can be * either a single array or a variable number of string arguments. */ protected function setUp() { 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->originalFileDirectory = file_directory_path(); $this->originalProfile = drupal_get_profile(); $clean_url_original = variable_get('clean_url', 0); // Save and clean shutdown callbacks array because it static cached and // will be changed by the test run. If we don't, then it will contain // callbacks from both environments. So testing environment will try // to call handlers from original environment. $callbacks =& drupal_register_shutdown_function(); $this->originalShutdownCallbacks = $callbacks; $callbacks = array(); // 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($this->databasePrefix, 10); $private_files_directory = $public_files_directory . '/private'; $temp_files_directory = $private_files_directory . '/temp'; // Create the directories file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); file_prepare_directory($private_files_directory, FILE_CREATE_DIRECTORY); file_prepare_directory($temp_files_directory, FILE_CREATE_DIRECTORY); $this->generatedTestFiles = FALSE; // Log fatal errors. ini_set('log_errors', 1); ini_set('error_log', $public_files_directory . '/error.log'); // Reset all statics and variables to perform tests in a clean environment. $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(); $this->preloadRegistry(); // Set path variables. variable_set('file_public_path', $public_files_directory); variable_set('file_private_path', $private_files_directory); variable_set('file_temporary_path', $temp_files_directory); // 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. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; } if ($modules) { module_enable($modules, TRUE); } // Run default profile tasks. module_enable(array('standard'), FALSE); // Rebuild caches. drupal_static_reset(); drupal_flush_all_caches(); // Register actions declared by any modules. actions_synchronize(); // Reload global $conf array and permissions. $this->refreshVariables(); $this->checkPermissions(array(), TRUE); // Reset statically cached schema for new database prefix. drupal_get_schema(NULL, TRUE); // 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); $user = user_load(1); // Restore necessary variables. variable_set('install_task', 'done'); variable_set('clean_url', $clean_url_original); variable_set('site_mail', '*****@*****.**'); variable_set('date_default_timezone', date_default_timezone_get()); // Set up English language. unset($GLOBALS['conf']['language_default']); $language = language_default(); // Use the test mail class instead of the default mail handler class. variable_set('mail_system', array('default-system' => 'TestingMailSystem')); drupal_set_time_limit($this->timeLimit); }
/** * Don't create test db via install, instead copy existing db. */ protected function setUp() { // Copy of parent::setUp(); 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(); // Store necessary current values before switching to prefixed database. $this->originalLanguage = $language; $this->originalLanguageDefault = variable_get('language_default'); $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); $this->originalProfile = drupal_get_profile(); $clean_url_original = variable_get('clean_url', 0); // Save and clean shutdown callbacks array because it static cached and // will be changed by the test run. If we don't, then it will contain // callbacks from both environments. So testing environment will try // to call handlers from original environment. $callbacks =& drupal_register_shutdown_function(); $this->originalShutdownCallbacks = $callbacks; $callbacks = array(); // 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. $this->public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10); $this->private_files_directory = $this->public_files_directory . '/private'; $this->temp_files_directory = $this->private_files_directory . '/temp'; // Create the directories file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY); file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY); $this->generatedTestFiles = FALSE; // Log fatal errors. ini_set('log_errors', 1); ini_set('error_log', $this->public_files_directory . '/error.log'); // 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; // 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 . '}'); } // 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']); // Clone each table into the new database. foreach ($schemas as $name => $schema) { $this->cloneTable($name, $sources[$name], $schema); } // Log in with a clean $user. $this->originalUser = $user; drupal_save_session(FALSE); $user = user_load(1); // Set up English language. unset($GLOBALS['conf']['language_default']); $language = language_default(); // Use the test mail class instead of the default mail handler class. variable_set('mail_system', array('default-system' => 'TestingMailSystem')); drupal_set_time_limit($this->timeLimit); $this->resetAll(); $this->refreshVariables(); $this->setup = TRUE; }