Index: index.php =================================================================== RCS file: /cvs/drupal/drupal/index.php,v retrieving revision 1.98 diff -u -r1.98 index.php --- index.php 8 Feb 2009 20:27:51 -0000 1.98 +++ index.php 2 Apr 2009 01:59:43 -0000 @@ -19,6 +19,89 @@ require_once DRUPAL_ROOT . '/includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + +if (TRUE) { +// http://drupal.d7x.loc/scripts/run-test.php?test=BlockTestCase&test_id=13370 +ini_set('display_errors', 1); +header('Content-Type: text/plain'); +module_load_include('environment.inc', 'simpletest'); + +class SampleTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Sample', + 'description' => 'Sample test', + 'group' => 'Sample group', + 'modules' => array('book'), + ); + } + + public function testSomething() { + $this->assertTrue(TRUE, 'works!'); + } + + public function testSomethingElse() { + $this->assertTrue(FALSE, 'works!'); + } +} + +// Remove left over simpletest tables. +$tables = db_find_tables('simpletest%'); +$ret = array(); +foreach ($tables as $table) { + if ($table != 'simpletest' && $table != 'simpletest_test_id') { + db_drop_table($ret, $table); + } +} + +d('Removed ' . count($ret) . ' of ' . count($tables) . ' tables'); + +// Start of test suite. +d('init()'); +simpletest_environment_init(); + +$classes = array('SampleTestCase'); + +foreach ($classes as $class) { + $info = call_user_func(array($class, 'getInfo')); + d("new $class()"); + $tests = array('testSomething'); //, 'testSomethingElse'); //, 'testBlock'); + foreach ($tests as $test) { + d("$test()"); + $prefix = simpletest_environment_setup($info); + print_r(variable_get('simpletest_environment_prefixes', array())); +// $instance = new $class(13370); +// $instance->$test(); + +// echo url('scripts/run-test.php', array('absolute' => TRUE, +// 'query' => array('class' => $class, 'method' => $test, 'test_id' => 13370))); + + $db_prefix = $prefix; // Fake so we get the header. + $result = drupal_http_request(url('scripts/run-test.php', array('absolute' => TRUE, + 'query' => array('class' => $class, 'method' => $test, 'test_id' => 13370)))); + $db_prefix = SIMPLETEST_ENVIRONMENT_PREFIX_ORIGINAL; + var_dump($result->data); + if ($result->data == 'not-altered') { + simpletest_environment_release(SIMPLETEST_ENVIRONMENT_BASE_DEFAULT, $prefix); + } + // TODO Call run-test.php. +// simpletest_environment_teardown($info, $prefix); + print_r(variable_get('simpletest_environment_prefixes', array())); + } +} + +d('deinit()'); +//simpletest_environment_deinit(); +d('exit()'); + +exit; +} + +function d($message) { + echo "$message...\n"; +} + $return = menu_execute_active_handler(); // Menu status constants are integers; page content is a string or array. Index: modules/simpletest/simpletest.info =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.info,v retrieving revision 1.4 diff -u -r1.4 simpletest.info --- modules/simpletest/simpletest.info 11 Oct 2008 02:33:01 -0000 1.4 +++ modules/simpletest/simpletest.info 2 Apr 2009 01:59:44 -0000 @@ -6,3 +6,5 @@ core = 7.x files[] = simpletest.module files[] = simpletest.install +files[] = simpletest.test +files[] = drupal_web_test_case.php Index: modules/simpletest/simpletest.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v retrieving revision 1.39 diff -u -r1.39 simpletest.module --- modules/simpletest/simpletest.module 31 Mar 2009 01:49:53 -0000 1.39 +++ modules/simpletest/simpletest.module 2 Apr 2009 01:59:44 -0000 @@ -347,6 +347,9 @@ * drupal being the default. */ function simpletest_run_tests($test_list, $reporter = 'drupal') { + module_load_include('environment.inc', 'simpletest'); + DrupalTestEnvironment::init(); + cache_clear_all(); $test_id = db_insert('simpletest_test_id')->useDefaults(array('test_id'))->execute(); @@ -430,6 +433,8 @@ } function _simpletest_batch_finished($success, $results, $operations, $elapsed) { + DrupalTestEnvironment::deinit(); + if (isset($results['test_id'])) { drupal_set_session('test_id', $results['test_id']); } @@ -523,7 +528,7 @@ foreach (array_diff_key($tables, $schema) as $table) { // Strip the prefix and skip tables without digits following "simpletest", // e.g. {simpletest_test_id}. - if (preg_match('/simpletest\d+.*/', $table, $matches)) { + if (preg_match('/simpletest\d+.*/', $table, $matches) || preg_match('/simpletest_base.*/', $table, $matches)) { db_drop_table($ret, $matches[0]); } } Index: modules/simpletest/drupal_web_test_case.php =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v retrieving revision 1.92 diff -u -r1.92 drupal_web_test_case.php --- modules/simpletest/drupal_web_test_case.php 30 Mar 2009 05:35:35 -0000 1.92 +++ modules/simpletest/drupal_web_test_case.php 2 Apr 2009 01:59:44 -0000 @@ -78,27 +78,6 @@ protected $additionalCurlOptions = array(); /** - * The original database prefix, before it was changed for testing purposes. - * - * @var string - */ - protected $originalPrefix = NULL; - - /** - * The original file directory, before it was changed for testing purposes. - * - * @var string - */ - protected $originalFileDirectory = NULL; - - /** - * The original user, before it was changed to a clean uid = 1 for testing purposes. - * - * @var object - */ - protected $originalUser = NULL; - - /** * Current results of this test case. * * @var Array @@ -394,11 +373,11 @@ /** * Run all tests in this class. */ - public function run() { + public function run($method) { set_error_handler(array($this, 'errorHandler')); - $methods = array(); +// $methods = array(); // Iterate through all the methods in this class. - foreach (get_class_methods(get_class($this)) as $method) { +// foreach (get_class_methods(get_class($this)) as $method) { // If the current method starts with "test", run it - it's a test. if (strtolower(substr($method, 0, 4)) == 'test') { $this->setUp(); @@ -411,7 +390,7 @@ } $this->tearDown(); } - } +// } // Clear out the error messages and restore error handler. drupal_get_messages(); restore_error_handler(); @@ -811,128 +790,16 @@ * List of modules to enable for the duration of the test. */ protected function 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); - - // Generate temporary prefixed database to ensure that tests have a clean starting point. - $db_prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}'); - - include_once DRUPAL_ROOT . '/includes/install.inc'; - drupal_install_system(); - - $this->preloadRegistry(); - - // Add the specified modules to the list of modules in the default profile. - $args = func_get_args(); - $modules = array_unique(array_merge(drupal_get_profile_modules('default', 'en'), $args)); - drupal_install_modules($modules, TRUE); - - // 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); - - // Run default profile tasks. - $task = 'profile'; - default_profile_tasks($task, ''); - - // Rebuild caches. - actions_synchronize(); - _drupal_flush_css_js(); - $this->refreshVariables(); - $this->checkPermissions(array(), TRUE); - - // Log in with a clean $user. - $this->originalUser = $user; - drupal_save_session(FALSE); - $user = user_load(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); } /** - * 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. - */ - 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'); - } - - /** - * Refresh the in-memory set of variables. Useful after a page request is made - * that changes a variable in a different thread. - * - * In other words calling a settings page with $this->drupalPost() with a changed - * value would update a variable to reflect that change, but in the thread that - * made the call (thread running the test) the changed variable would not be - * picked up. - * - * This method clears the variables cache and loads a fresh copy from the database - * to ensure that the most up-to-date set of variables is loaded. - */ - protected function refreshVariables() { - global $conf; - cache_clear_all('variables', 'cache'); - $conf = variable_init(); - } - - /** * Delete created files and temporary files directory, delete the tables created by setUp(), * and reset the database prefix. */ protected function tearDown() { global $db_prefix, $user; if (preg_match('/simpletest\d+/', $db_prefix)) { - // Delete temporary files directory and reset files directory path. - file_unmanaged_delete_recursive(file_directory_path()); - variable_set('file_directory_path', $this->originalFileDirectory); - - // 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($ret, $name); - } - - // Return the database prefix to the original. - $db_prefix = $this->originalPrefix; - - // Return the user to the original one. - $user = $this->originalUser; - drupal_save_session(TRUE); - - // Ensure that internal logged in variable and cURL options are reset. - $this->isLoggedIn = 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(MODULE_IMPLEMENTS_CLEAR_CACHE); - - // Reset the Field API. - field_cache_clear(); - - // Rebuild caches. - $this->refreshVariables(); - // Close the CURL handler. $this->curlClose(); } Index: scripts/run-tests.sh =================================================================== RCS file: /cvs/drupal/drupal/scripts/run-tests.sh,v retrieving revision 1.25 diff -u -r1.25 run-tests.sh --- scripts/run-tests.sh 31 Mar 2009 01:49:55 -0000 1.25 +++ scripts/run-tests.sh 2 Apr 2009 01:59:44 -0000 @@ -281,7 +281,7 @@ exit; } if ($args['concurrency'] == 1) { - // Fallback to mono-threaded execution. + // Fallback to mono-process execution. if (count($args['test_names']) > 1) { foreach ($args['test_names'] as $test_class) { // Execute each test in its separate Drupal environment. @@ -298,7 +298,7 @@ } } else { - // Multi-threaded execution. + // Multi-process execution. $children = array(); while (!empty($args['test_names']) || !empty($children)) { // Fork children safely since Drupal is not bootstrapped yet. Index: modules/aggregator/aggregator.test =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.test,v retrieving revision 1.21 diff -u -r1.21 aggregator.test --- modules/aggregator/aggregator.test 1 Apr 2009 19:56:34 -0000 1.21 +++ modules/aggregator/aggregator.test 2 Apr 2009 01:59:43 -0000 @@ -7,7 +7,7 @@ */ class AggregatorTestCase extends DrupalWebTestCase { - private static $prefix = 'simpletest_aggregator_'; + private static $stringPrefix = 'simpletest_aggregator_'; function setUp() { parent::setUp('aggregator', 'aggregator_test'); @@ -452,7 +452,7 @@ } class CategorizeFeedItemTestCase extends AggregatorTestCase { - private static $prefix = 'simpletest_aggregator_'; + private static $stringPrefix = 'simpletest_aggregator_'; public static function getInfo() { return array( @@ -470,7 +470,7 @@ $this->createSampleNodes(); // Simulate form submission on "admin/content/aggregator/add/category". - $edit = array('title' => $this->randomName(10, self::$prefix), 'description' => ''); + $edit = array('title' => $this->randomName(10, self::$stringPrefix), 'description' => ''); $this->drupalPost('admin/content/aggregator/add/category', $edit, t('Save')); $this->assertRaw(t('The category %title has been added.', array('%title' => $edit['title'])), t('The category %title has been added.', array('%title' => $edit['title']))); @@ -511,7 +511,7 @@ } class ImportOPMLTestCase extends AggregatorTestCase { - private static $prefix = 'simpletest_aggregator_'; + private static $stringPrefix = 'simpletest_aggregator_'; public static function getInfo() { return array( @@ -527,7 +527,7 @@ function openImportForm() { db_delete('aggregator_category')->execute(); - $category = $this->randomName(10, self::$prefix); + $category = $this->randomName(10, self::$stringPrefix); $cid = db_insert('aggregator_category') ->fields(array( 'title' => $category, @@ -590,7 +590,7 @@ db_delete('aggregator_category')->execute(); db_delete('aggregator_category_feed')->execute(); - $category = $this->randomName(10, self::$prefix); + $category = $this->randomName(10, self::$stringPrefix); db_insert('aggregator_category') ->fields(array( 'cid' => 1, Index: modules/block/block.info =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.info,v retrieving revision 1.12 diff -u -r1.12 block.info --- modules/block/block.info 3 Feb 2009 12:30:14 -0000 1.12 +++ modules/block/block.info 2 Apr 2009 01:59:43 -0000 @@ -8,3 +8,4 @@ files[] = block.module files[] = block.admin.inc files[] = block.install +files[] = block.test Index: modules/simpletest/simpletest.environment.inc =================================================================== RCS file: modules/simpletest/simpletest.environment.inc diff -N modules/simpletest/simpletest.environment.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/simpletest/simpletest.environment.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,268 @@ + 0'); + continue; + } + db_query('INSERT INTO ' . $destination_table . ' SELECT * FROM ' . $source_table); + } +} + +function simpletest_environment_modules_install(array $modules) { + require_once DRUPAL_ROOT . '/includes/install.inc'; + drupal_install_modules($modules, TRUE); +} + +function simpletest_environment_modules_uninstall(array $modules) { + require_once DRUPAL_ROOT . '/includes/install.inc'; + drupal_uninstall_modules($modules); +} + +function simpletest_environment_teardown(array $info) { + $base = isset($info['base']) ? $info['base'] : SIMPLETEST_ENVIRONMENT_BASE_DEFAULT; + $modules = isset($info['modules']) ? $info['modules'] : array(); + + if (!module_implements('schema_alter')) { + simpletest_environment_modules_uninstall($modules); +// simpletest_environment_release($base, $prefix); + return FALSE; + } + else { +// echo "free($prefix)\n"; + return TRUE; + } +} + +function simpletest_environment_flush_statics() { + // 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); + + // Reload module list and implementations to ensure that test module hooks + // aren't called after tests. + module_list(TRUE); + module_implements(MODULE_IMPLEMENTS_CLEAR_CACHE); + + // Reset the Field API. + field_cache_clear(); +} + +function simpletest_environment_request($base) { + $prefixes = variable_get('simpletest_environment_prefixes', array()); + + if (isset($prefixes[$base]) && $prefixes[$base]) { + // Use an existing database as a starting shell. + $prefix = array_pop($prefixes[$base]); + variable_set('simpletest_environment_prefixes', $prefixes); + return $prefix; + } + + // Ensure that base exists. + if (!simpletest_environment_base_exists($base)) { + // Create base database using default install profile. + simpletest_environment_base_create($base); + } + + // Create test database from base. TODO comment is old. + $prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}'); + simpletest_environment_schema_create($prefix, simpletest_environment_modules_get($base)); + return $prefix; +} + +function simpletest_environment_schema_create($prefix, array $modules) { + global $db_prefix; + + $db_prefix = $prefix; + + $ret = array(); + foreach ($modules as $module) { + module_load_install($module); + // Ensure that module implements hook_schema, as drupal_install_schem() + // crashes if called on a module that does not have schema. + if (function_exists($module . '_schema')) { + $ret[] = drupal_install_schema($module); + } + $modules[] = $module; + } + // TODO Check $ret. + + $db_prefix = SIMPLETEST_ENVIRONMENT_PREFIX_ORIGINAL; +} + +function simpletest_environment_modules_get($prefix) { + global $db_prefix; + + $db_prefix = $prefix; + $result = db_query('SELECT name + FROM {system} + WHERE type = :type + AND status = :status', array(':type' => 'module', ':status' => TRUE)); + $db_prefix = SIMPLETEST_ENVIRONMENT_PREFIX_ORIGINAL; + + $modules = array(); + while ($module = db_result($result)) { + $modules[] = $module; + } + return $modules; +} + +function simpletest_environment_release($base, $prefix) { + $prefixes = variable_get('simpletest_environment_prefixes', array()); + + if (!isset($prefixes[$base])) { + $prefixes[$base] = array(); + } + + $prefixes[$base][] = $prefix; + variable_set('simpletest_environment_prefixes', $prefixes); +} + +function simpletest_environment_base_exists($base) { + return (bool) db_find_tables($base . '%'); +} + +function simpletest_environment_base_create($base) { + global $db_prefix; + + $clean_url_original = variable_get('clean_url', 0); + + $prefixOriginal = $db_prefix; + $db_prefix = $base; + + require_once DRUPAL_ROOT . '/includes/install.inc'; + drupal_install_system(); + + simpletest_environment_preload_registry(); + + $modules = drupal_get_profile_modules('default', 'en'); + drupal_install_modules($modules, TRUE); + + // Add the specified modules to the list of modules in the default profile. +// $args = func_get_args(); +// $modules = array_unique(array_merge(drupal_get_profile_modules('default', 'en'), $args)); + $modules = drupal_get_profile_modules('default', 'en'); + drupal_install_modules($modules, TRUE); + + // Run default profile tasks. + $task = 'profile'; + default_profile_tasks($task, ''); + + // 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'); + + $db_prefix = $prefixOriginal; +} + +/** + * 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. + */ +function simpletest_environment_preload_registry() { + db_query('INSERT INTO {registry} SELECT * FROM ' . SIMPLETEST_ENVIRONMENT_PREFIX_ORIGINAL . 'registry'); // TODO + db_query('INSERT INTO {registry_file} SELECT * FROM ' . SIMPLETEST_ENVIRONMENT_PREFIX_ORIGINAL . 'registry_file'); +} + +/** + * Refresh the in-memory set of variables. Useful after a page request is made + * that changes a variable in a different thread. + * + * In other words calling a settings page with $this->drupalPost() with a changed + * value would update a variable to reflect that change, but in the thread that + * made the call (thread running the test) the changed variable would not be + * picked up. + * + * This method clears the variables cache and loads a fresh copy from the database + * to ensure that the most up-to-date set of variables is loaded. + */ +function simpletest_environment_refresh_variables() { + global $conf; + cache_clear_all('variables', 'cache'); + $conf = variable_init(); +} + +function simpletest_environment_deinit() { + $prefixes = variable_get('simpletest_environment_prefixes', array()); + foreach ($prefixes as $base => $base_prefixes) { + simpletest_environment_destroy($base); + foreach ($base_prefixes as $prefix) { + simpletest_environment_destroy($prefix); + } + } +} + +function simpletest_environment_destroy($prefix) { + // Remove test database tables due to hook_schema_alter() implementation. + $tables = db_find_tables($prefix . '%'); + print_r($tables); + $ret = array(); + foreach ($tables as $table) { + db_drop_table($ret, $table); + } + + // Delete temporary files directory and reset files directory path. + file_unmanaged_delete_recursive(file_directory_path() . '/' . $prefix); +} + +//function simpletest_environment_() { +// +//} Index: scripts/run-test.php =================================================================== RCS file: scripts/run-test.php diff -N scripts/run-test.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scripts/run-test.php 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,75 @@ + 'Sample', + 'description' => 'Sample test', + 'group' => 'Sample group', + 'modules' => array('book'), + ); + } + + public function testSomething() { + $this->assertTrue(TRUE, 'works!'); + echo 'hax'; + } + + public function testSomethingElse() { + $this->assertTrue(FALSE, 'works!'); + } +} + +$class = $_GET['class']; +$method = $_GET['method']; +$test_id = $_GET['test_id']; +if (($info = call_user_func(array($class, 'getInfo'))) && is_numeric($test_id)) { + simpletest_environment_modules_install($info['modules']); + $test = new $class($test_id); + $test->run($method); + echo simpletest_environment_teardown($info) ? 'altered' : 'not-altered'; +// echo 'complete'; +} +else { + echo 'invalid'; +}