Newer
Older
<?php
Dries Buytaert
committed
/**
* @file
* Tests for system.module.
*/
Dries Buytaert
committed
/**
* Helper class for module test cases.
*/
class ModuleTestCase extends DrupalWebTestCase {
protected $admin_user;
Dries Buytaert
committed
function setUp() {
parent::setUp('system_test');
Dries Buytaert
committed
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules'));
Dries Buytaert
committed
$this->drupalLogin($this->admin_user);
}
/**
Dries Buytaert
committed
* Assert there are tables that begin with the specified base table name.
*
* @param $base_table
* Beginning of table name to look for.
* @param $count
* (optional) Whether or not to assert that there are tables that match the
* specified base table. Defaults to TRUE.
*/
Dries Buytaert
committed
function assertTableCount($base_table, $count = TRUE) {
Angie Byron
committed
$tables = db_find_tables(Database::getConnection()->prefixTables('{' . $base_table . '}') . '%');
Dries Buytaert
committed
if ($count) {
Jennifer Hodgdon
committed
return $this->assertTrue($tables, format_string('Tables matching "@base_table" found.', array('@base_table' => $base_table)));
Dries Buytaert
committed
}
Jennifer Hodgdon
committed
return $this->assertFalse($tables, format_string('Tables matching "@base_table" not found.', array('@base_table' => $base_table)));
}
/**
* Assert that all tables defined in a module's hook_schema() exist.
*
* @param $module
* The name of the module.
*/
function assertModuleTablesExist($module) {
$tables = array_keys(drupal_get_schema_unprocessed($module));
$tables_exist = TRUE;
foreach ($tables as $table) {
if (!db_table_exists($table)) {
$tables_exist = FALSE;
}
}
Jennifer Hodgdon
committed
return $this->assertTrue($tables_exist, format_string('All database tables defined by the @module module exist.', array('@module' => $module)));
}
/**
* Assert that none of the tables defined in a module's hook_schema() exist.
*
* @param $module
* The name of the module.
*/
function assertModuleTablesDoNotExist($module) {
$tables = array_keys(drupal_get_schema_unprocessed($module));
$tables_exist = FALSE;
foreach ($tables as $table) {
if (db_table_exists($table)) {
$tables_exist = TRUE;
}
}
Jennifer Hodgdon
committed
return $this->assertFalse($tables_exist, format_string('None of the database tables defined by the @module module exist.', array('@module' => $module)));
}
/**
Dries Buytaert
committed
* Assert the list of modules are enabled or disabled.
*
* @param $modules
* Module list to check.
* @param $enabled
* Expected module state.
*/
Dries Buytaert
committed
function assertModules(array $modules, $enabled) {
module_list(TRUE);
foreach ($modules as $module) {
if ($enabled) {
$message = 'Module "@module" is enabled.';
}
else {
$message = 'Module "@module" is not enabled.';
}
Jennifer Hodgdon
committed
$this->assertEqual(module_exists($module), $enabled, format_string($message, array('@module' => $module)));
Dries Buytaert
committed
}
}
Dries Buytaert
committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* Verify a log entry was entered for a module's status change.
* Called in the same way of the expected original watchdog() execution.
*
* @param $type
* The category to which this message belongs.
* @param $message
* The message to store in the log. Keep $message translatable
* by not concatenating dynamic values into it! Variables in the
* message should be added by using placeholder strings alongside
* the variables argument to declare the value of the placeholders.
* See t() for documentation on how $message and $variables interact.
* @param $variables
* Array of variables to replace in the message on display or
* NULL if message is already translated or not possible to
* translate.
* @param $severity
* The severity of the message, as per RFC 3164.
* @param $link
* A link to associate with the message.
*/
function assertLogMessage($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = '') {
$count = db_select('watchdog', 'w')
->condition('type', $type)
->condition('message', $message)
->condition('variables', serialize($variables))
->condition('severity', $severity)
->condition('link', $link)
->countQuery()
->execute()
->fetchField();
Jennifer Hodgdon
committed
$this->assertTrue($count > 0, format_string('watchdog table contains @count rows for @message', array('@count' => $count, '@message' => $message)));
Dries Buytaert
committed
}
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Test module enabling/disabling functionality.
*/
class EnableDisableTestCase extends ModuleTestCase {
protected $profile = 'testing';
Angie Byron
committed
public static function getInfo() {
Dries Buytaert
committed
return array(
'name' => 'Enable/disable modules',
'description' => 'Enable/disable core module and confirm table creation/deletion.',
'group' => 'Module',
Dries Buytaert
committed
);
}
/**
* Test that all core modules can be enabled, disabled and uninstalled.
*/
function testEnableDisable() {
// Try to enable, disable and uninstall all core modules, unless they are
// hidden or required.
$modules = system_rebuild_module_data();
foreach ($modules as $name => $module) {
if ($module->info['package'] != 'Core' || !empty($module->info['hidden']) || !empty($module->info['required'])) {
unset($modules[$name]);
}
}
Jennifer Hodgdon
committed
$this->assertTrue(count($modules), format_string('Found @count core modules that we can try to enable in this test.', array('@count' => count($modules))));
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Enable the dblog module first, since we will be asserting the presence
// of log messages throughout the test.
if (isset($modules['dblog'])) {
$modules = array('dblog' => $modules['dblog']) + $modules;
}
// Set a variable so that the hook implementations in system_test.module
// will display messages via drupal_set_message().
variable_set('test_verbose_module_hooks', TRUE);
// Throughout this test, some modules may be automatically enabled (due to
// dependencies). We'll keep track of them in an array, so we can handle
// them separately.
$automatically_enabled = array();
// Go through each module in the list and try to enable it (unless it was
// already enabled automatically due to a dependency).
foreach ($modules as $name => $module) {
if (empty($automatically_enabled[$name])) {
// Start a list of modules that we expect to be enabled this time.
$modules_to_enable = array($name);
// Find out if the module has any dependencies that aren't enabled yet;
// if so, add them to the list of modules we expect to be automatically
// enabled.
foreach (array_keys($module->requires) as $dependency) {
if (isset($modules[$dependency]) && empty($automatically_enabled[$dependency])) {
$modules_to_enable[] = $dependency;
$automatically_enabled[$dependency] = TRUE;
}
}
// Check that each module is not yet enabled and does not have any
// database tables yet.
foreach ($modules_to_enable as $module_to_enable) {
$this->assertModules(array($module_to_enable), FALSE);
$this->assertModuleTablesDoNotExist($module_to_enable);
}
// Install and enable the module.
$edit = array();
$edit['modules[Core][' . $name . '][enable]'] = $name;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
// Handle the case where modules were installed along with this one and
// where we therefore hit a confirmation screen.
if (count($modules_to_enable) > 1) {
$this->drupalPost(NULL, array(), t('Continue'));
}
Jennifer Hodgdon
committed
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
// Check that hook_modules_installed() and hook_modules_enabled() were
// invoked with the expected list of modules, that each module's
// database tables now exist, and that appropriate messages appear in
// the logs.
foreach ($modules_to_enable as $module_to_enable) {
$this->assertText(t('hook_modules_installed fired for @module', array('@module' => $module_to_enable)));
$this->assertText(t('hook_modules_enabled fired for @module', array('@module' => $module_to_enable)));
$this->assertModules(array($module_to_enable), TRUE);
$this->assertModuleTablesExist($module_to_enable);
$this->assertLogMessage('system', "%module module installed.", array('%module' => $module_to_enable), WATCHDOG_INFO);
$this->assertLogMessage('system', "%module module enabled.", array('%module' => $module_to_enable), WATCHDOG_INFO);
}
// Disable and uninstall the original module, and check appropriate
// hooks, tables, and log messages. (Later, we'll go back and do the
// same thing for modules that were enabled automatically.) Skip this
// for the dblog module, because that is needed for the test; we'll go
// back and do that one at the end also.
if ($name != 'dblog') {
$this->assertSuccessfulDisableAndUninstall($name);
}
}
}
// Go through all modules that were automatically enabled, and try to
// disable and uninstall them one by one.
while (!empty($automatically_enabled)) {
$initial_count = count($automatically_enabled);
foreach (array_keys($automatically_enabled) as $name) {
// If the module can't be disabled due to dependencies, skip it and try
// again the next time. Otherwise, try to disable it.
$this->drupalGet('admin/modules');
$disabled_checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Core][' . $name . '][enable]"]');
if (empty($disabled_checkbox) && $name != 'dblog') {
unset($automatically_enabled[$name]);
$this->assertSuccessfulDisableAndUninstall($name);
}
}
$final_count = count($automatically_enabled);
// If all checkboxes were disabled, something is really wrong with the
// test. Throw a failure and avoid an infinite loop.
if ($initial_count == $final_count) {
$this->fail(t('Remaining modules could not be disabled.'));
break;
}
}
// Disable and uninstall the dblog module last, since we needed it for
// assertions in all the above tests.
if (isset($modules['dblog'])) {
$this->assertSuccessfulDisableAndUninstall('dblog');
}
Dries Buytaert
committed
// Now that all modules have been tested, go back and try to enable them
// all again at once. This tests two things:
// - That each module can be successfully enabled again after being
// uninstalled.
// - That enabling more than one module at the same time does not lead to
// any errors.
Dries Buytaert
committed
$edit = array();
foreach (array_keys($modules) as $name) {
$edit['modules[Core][' . $name . '][enable]'] = $name;
}
Angie Byron
committed
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
Jennifer Hodgdon
committed
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
}
Dries Buytaert
committed
/**
* Ensures entity info cache is updated after changes.
*/
function testEntityInfoChanges() {
module_enable(array('entity_cache_test'));
$entity_info = entity_get_info();
$this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.');
// Change the label of the test entity type and make sure changes appear
// after flushing caches.
variable_set('entity_cache_test_label', 'New label.');
drupal_flush_all_caches();
$info = entity_get_info('entity_cache_test');
$this->assertEqual($info['label'], 'New label.', 'New label appears in entity info.');
// Disable the providing module and make sure the entity type is gone.
module_disable(array('entity_cache_test', 'entity_cache_test_dependency'));
$entity_info = entity_get_info();
$this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.');
}
/**
* Tests entity info cache after enabling a module with a dependency on an entity providing module.
Angie Byron
committed
*
* @see entity_cache_test_watchdog()
Dries Buytaert
committed
*/
function testEntityInfoCacheWatchdog() {
Dries Buytaert
committed
module_enable(array('entity_cache_test'));
$info = variable_get('entity_cache_test');
Angie Byron
committed
$this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.');
$this->assertEqual($info['controller class'], 'DrupalDefaultEntityController', 'Entity controller class info is correct.');
Dries Buytaert
committed
}
/**
* Disables and uninstalls a module and asserts that it was done correctly.
*
* @param $module
* The name of the module to disable and uninstall.
*/
function assertSuccessfulDisableAndUninstall($module) {
// Disable the module.
$edit = array();
$edit['modules[Core][' . $module . '][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
Jennifer Hodgdon
committed
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
$this->assertModules(array($module), FALSE);
// Check that the appropriate hook was fired and the appropriate log
// message appears.
$this->assertText(t('hook_modules_disabled fired for @module', array('@module' => $module)));
$this->assertLogMessage('system', "%module module disabled.", array('%module' => $module), WATCHDOG_INFO);
// Check that the module's database tables still exist.
$this->assertModuleTablesExist($module);
// Uninstall the module.
$edit = array();
$edit['uninstall[' . $module . ']'] = $module;
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, NULL, t('Uninstall'));
Jennifer Hodgdon
committed
$this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
$this->assertModules(array($module), FALSE);
// Check that the appropriate hook was fired and the appropriate log
// message appears. (But don't check for the log message if the dblog
// module was just uninstalled, since the {watchdog} table won't be there
// anymore.)
$this->assertText(t('hook_modules_uninstalled fired for @module', array('@module' => $module)));
if ($module != 'dblog') {
$this->assertLogMessage('system', "%module module uninstalled.", array('%module' => $module), WATCHDOG_INFO);
}
// Check that the module's database tables no longer exist.
$this->assertModuleTablesDoNotExist($module);
}
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Tests failure of hook_requirements('install').
*/
class HookRequirementsTestCase extends ModuleTestCase {
public static function getInfo() {
return array(
'name' => 'Requirements hook failure',
'description' => "Attempts enabling a module that fails hook_requirements('install').",
'group' => 'Module',
);
}
/**
* Assert that a module cannot be installed if it fails hook_requirements().
*/
function testHookRequirementsFailure() {
$this->assertModules(array('requirements1_test'), FALSE);
// Attempt to install the requirements1_test module.
$edit = array();
$edit['modules[Testing][requirements1_test][enable]'] = 'requirements1_test';
Dries Buytaert
committed
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
// Makes sure the module was NOT installed.
Jennifer Hodgdon
committed
$this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.');
Dries Buytaert
committed
$this->assertModules(array('requirements1_test'), FALSE);
}
}
Dries Buytaert
committed
/**
* Test module dependency functionality.
*/
class ModuleDependencyTestCase extends ModuleTestCase {
Angie Byron
committed
public static function getInfo() {
Dries Buytaert
committed
return array(
'name' => 'Module dependencies',
'description' => 'Enable module without dependency enabled.',
'group' => 'Module',
Dries Buytaert
committed
);
}
/**
* Attempt to enable translation module without locale enabled.
*/
function testEnableWithoutDependency() {
// Attempt to enable content translation without locale enabled.
$edit = array();
Angie Byron
committed
$edit['modules[Core][translation][enable]'] = 'translation';
Angie Byron
committed
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
Jennifer Hodgdon
committed
$this->assertText(t('Some required modules must be enabled'), 'Dependency required.');
$this->assertModules(array('translation', 'locale'), FALSE);
// Assert that the locale tables weren't enabled.
$this->assertTableCount('languages', FALSE);
$this->assertTableCount('locale', FALSE);
$this->drupalPost(NULL, NULL, t('Continue'));
Jennifer Hodgdon
committed
$this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
$this->assertModules(array('translation', 'locale'), TRUE);
// Assert that the locale tables were enabled.
$this->assertTableCount('languages', TRUE);
$this->assertTableCount('locale', TRUE);
}
/**
* Attempt to enable a module with a missing dependency.
*/
function testMissingModules() {
// Test that the system_dependencies_test module is marked
// as missing a dependency.
Angie Byron
committed
$this->drupalGet('admin/modules');
Jennifer Hodgdon
committed
$this->assertRaw(t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst('_missing_dependency'))), 'A module with missing dependencies is marked as such.');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_dependencies_test][enable]"]');
Jennifer Hodgdon
committed
$this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
// Force enable the system_dependencies_test module.
Angie Byron
committed
module_enable(array('system_dependencies_test'), FALSE);
// Verify that the module is forced to be disabled when submitting
// the module page.
Angie Byron
committed
$this->drupalPost('admin/modules', array(), t('Save configuration'));
Jennifer Hodgdon
committed
$this->assertText(t('The @module module is missing, so the following module will be disabled: @depends.', array('@module' => '_missing_dependency', '@depends' => 'system_dependencies_test')), 'The module missing dependencies will be disabled.');
// Confirm.
$this->drupalPost(NULL, NULL, t('Continue'));
// Verify that the module has been disabled.
$this->assertModules(array('system_dependencies_test'), FALSE);
}
Dries Buytaert
committed
Angie Byron
committed
/**
* Tests enabling a module that depends on an incompatible version of a module.
*/
function testIncompatibleModuleVersionDependency() {
// Test that the system_incompatible_module_version_dependencies_test is
// marked as having an incompatible dependency.
$this->drupalGet('admin/modules');
$this->assertRaw(t('@module (<span class="admin-missing">incompatible with</span> version @version)', array(
'@module' => 'System incompatible module version test (>2.0)',
'@version' => '1.0',
)), 'A module that depends on an incompatible version of a module is marked as such.');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_incompatible_module_version_dependencies_test][enable]"]');
Jennifer Hodgdon
committed
$this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
Angie Byron
committed
}
/**
* Tests enabling a module that depends on a module with an incompatible core version.
*/
function testIncompatibleCoreVersionDependency() {
// Test that the system_incompatible_core_version_dependencies_test is
// marked as having an incompatible dependency.
$this->drupalGet('admin/modules');
$this->assertRaw(t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array(
'@module' => 'System incompatible core version test',
)), 'A module that depends on a module with an incompatible core version is marked as such.');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_incompatible_core_version_dependencies_test][enable]"]');
Jennifer Hodgdon
committed
$this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
Angie Byron
committed
}
Dries Buytaert
committed
/**
* Tests enabling a module that depends on a module which fails hook_requirements().
*/
function testEnableRequirementsFailureDependency() {
$this->assertModules(array('requirements1_test'), FALSE);
$this->assertModules(array('requirements2_test'), FALSE);
// Attempt to install both modules at the same time.
$edit = array();
$edit['modules[Testing][requirements1_test][enable]'] = 'requirements1_test';
$edit['modules[Testing][requirements2_test][enable]'] = 'requirements2_test';
Dries Buytaert
committed
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
// Makes sure the modules were NOT installed.
Jennifer Hodgdon
committed
$this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.');
Dries Buytaert
committed
$this->assertModules(array('requirements1_test'), FALSE);
$this->assertModules(array('requirements2_test'), FALSE);
// Makes sure that already enabled modules the failing modules depend on
// were not disabled.
$this->assertModules(array('comment'), TRUE);
}
Angie Byron
committed
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
/**
* Tests that module dependencies are enabled in the correct order via the
* UI. Dependencies should be enabled before their dependents.
*/
function testModuleEnableOrder() {
module_enable(array('module_test'), FALSE);
$this->resetAll();
$this->assertModules(array('module_test'), TRUE);
variable_set('dependency_test', 'dependency');
// module_test creates a dependency chain: forum depends on poll, which
// depends on php. The correct enable order is, php, poll, forum.
$expected_order = array('php', 'poll', 'forum');
// Enable the modules through the UI, verifying that the dependency chain
// is correct.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
$this->assertText(t('You must enable the Poll, PHP filter modules to install Forum.'), t('Dependency chain created.'));
$edit['modules[Core][poll][enable]'] = 'poll';
$edit['modules[Core][php][enable]'] = 'php';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum', 'poll', 'php'), TRUE);
// Check the actual order which is saved by module_test_modules_enabled().
$this->assertIdentical(variable_get('test_module_enable_order', FALSE), $expected_order, t('Modules enabled in the correct order.'));
}
Angie Byron
committed
/**
* Tests attempting to uninstall a module that has installed dependents.
*/
function testUninstallDependents() {
// Enable the forum module.
$edit = array('modules[Core][forum][enable]' => 'forum');
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), TRUE);
Angie Byron
committed
// Disable forum and comment. Both should now be installed but disabled.
Angie Byron
committed
$edit = array('modules[Core][forum][enable]' => FALSE);
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
Angie Byron
committed
$edit = array('modules[Core][comment][enable]' => FALSE);
Angie Byron
committed
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
Angie Byron
committed
$this->assertModules(array('comment'), FALSE);
Angie Byron
committed
// Check that the taxonomy module cannot be uninstalled.
$this->drupalGet('admin/modules/uninstall');
Angie Byron
committed
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]');
Jennifer Hodgdon
committed
$this->assert(count($checkbox) == 1, 'Checkbox for uninstalling the comment module is disabled.');
Angie Byron
committed
// Uninstall the forum module, and check that taxonomy now can also be
// uninstalled.
$edit = array('uninstall[forum]' => 'forum');
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, NULL, t('Uninstall'));
Jennifer Hodgdon
committed
$this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
Angie Byron
committed
$edit = array('uninstall[comment]' => 'comment');
Angie Byron
committed
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, NULL, t('Uninstall'));
Jennifer Hodgdon
committed
$this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
Angie Byron
committed
}
David Rothstein
committed
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
/**
* Tests whether the correct module metadata is returned.
*/
function testModuleMetaData() {
// Generate the list of available modules.
$modules = system_rebuild_module_data();
// Check that the mtime field exists for the system module.
$this->assertTrue(!empty($modules['system']->info['mtime']), 'The system.info file modification time field is present.');
// Use 0 if mtime isn't present, to avoid an array index notice.
$test_mtime = !empty($modules['system']->info['mtime']) ? $modules['system']->info['mtime'] : 0;
// Ensure the mtime field contains a number that is greater than zero.
$this->assertTrue(is_numeric($test_mtime) && ($test_mtime > 0), 'The system.info file modification time field contains a timestamp.');
}
/**
* Tests whether the correct theme metadata is returned.
*/
function testThemeMetaData() {
// Generate the list of available themes.
$themes = system_rebuild_theme_data();
// Check that the mtime field exists for the bartik theme.
$this->assertTrue(!empty($themes['bartik']->info['mtime']), 'The bartik.info file modification time field is present.');
// Use 0 if mtime isn't present, to avoid an array index notice.
$test_mtime = !empty($themes['bartik']->info['mtime']) ? $themes['bartik']->info['mtime'] : 0;
// Ensure the mtime field contains a number that is greater than zero.
$this->assertTrue(is_numeric($test_mtime) && ($test_mtime > 0), 'The bartik.info file modification time field contains a timestamp.');
}
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Test module dependency on specific versions.
*/
class ModuleVersionTestCase extends ModuleTestCase {
public static function getInfo() {
return array(
'name' => 'Module versions',
'description' => 'Check module version dependencies.',
'group' => 'Module',
);
}
Angie Byron
committed
function setUp() {
Dries Buytaert
committed
parent::setUp('module_test');
}
/**
* Test version dependencies.
*/
function testModuleVersions() {
$dependencies = array(
Angie Byron
committed
// Alternating between being compatible and incompatible with 7.x-2.4-beta3.
Dries Buytaert
committed
// The first is always a compatible.
'common_test',
// Branch incompatibility.
'common_test (1.x)',
// Branch compatibility.
'common_test (2.x)',
// Another branch incompatibility.
'common_test (>2.x)',
// Another branch compatibility.
'common_test (<=2.x)',
// Another branch incompatibility.
'common_test (<2.x)',
// Another branch compatibility.
'common_test (>=2.x)',
// Nonsense, misses a dash. Incompatible with everything.
'common_test (=7.x2.x, >=2.4)',
// Core version is optional. Compatible.
Angie Byron
committed
'common_test (=7.x-2.x, >=2.4-alpha2)',
Dries Buytaert
committed
// Test !=, explicitly incompatible.
Angie Byron
committed
'common_test (=2.x, !=2.4-beta3)',
Dries Buytaert
committed
// Three operations. Compatible.
'common_test (=2.x, !=2.3, <2.5)',
Angie Byron
committed
// Testing extra version. Incompatible.
'common_test (<=2.4-beta2)',
// Testing extra version. Compatible.
'common_test (>2.4-beta2)',
// Testing extra version. Incompatible.
'common_test (>2.4-rc0)',
Dries Buytaert
committed
);
variable_set('dependencies', $dependencies);
$n = count($dependencies);
for ($i = 0; $i < $n; $i++) {
Angie Byron
committed
$this->drupalGet('admin/modules');
Dries Buytaert
committed
$checkbox = $this->xpath('//input[@id="edit-modules-testing-module-test-enable"]');
Dries Buytaert
committed
$this->assertEqual(!empty($checkbox[0]['disabled']), $i % 2, $dependencies[$i]);
}
}
}
Dries Buytaert
committed
/**
* Test required modules functionality.
*/
class ModuleRequiredTestCase extends ModuleTestCase {
Angie Byron
committed
public static function getInfo() {
Dries Buytaert
committed
return array(
'name' => 'Required modules',
'description' => 'Attempt disabling of required modules.',
'group' => 'Module',
Dries Buytaert
committed
);
}
/**
* Assert that core required modules cannot be disabled.
*/
function testDisableRequired() {
Angie Byron
committed
$module_info = system_get_info('module');
Angie Byron
committed
$this->drupalGet('admin/modules');
Angie Byron
committed
foreach ($module_info as $module => $info) {
// Check to make sure the checkbox for each required module is disabled
// and checked (or absent from the page if the module is also hidden).
if (!empty($info['required'])) {
$field_name = "modules[{$info['package']}][$module][enable]";
if (empty($info['hidden'])) {
Jennifer Hodgdon
committed
$this->assertFieldByXPath("//input[@name='$field_name' and @disabled='disabled' and @checked='checked']", '', format_string('Field @name was disabled and checked.', array('@name' => $field_name)));
Angie Byron
committed
}
else {
$this->assertNoFieldByName($field_name);
}
}
}
Dries Buytaert
committed
Dries Buytaert
committed
class IPAddressBlockingTestCase extends DrupalWebTestCase {
protected $blocking_user;
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implement getInfo().
Dries Buytaert
committed
*/
Angie Byron
committed
public static function getInfo() {
Dries Buytaert
committed
return array(
'name' => 'IP address blocking',
'description' => 'Test IP address blocking.',
'group' => 'System'
Dries Buytaert
committed
);
}
/**
Dries Buytaert
committed
* Implement setUp().
Dries Buytaert
committed
*/
function setUp() {
parent::setUp();
// Create user.
Dries Buytaert
committed
$this->blocking_user = $this->drupalCreateUser(array('block IP addresses'));
$this->drupalLogin($this->blocking_user);
Dries Buytaert
committed
}
/**
* Test a variety of user input to confirm correct validation and saving of data.
Dries Buytaert
committed
*/
function testIPAddressValidation() {
$this->drupalGet('admin/config/people/ip-blocking');
Dries Buytaert
committed
// Block a valid IP address.
$edit = array();
$edit['ip'] = '192.168.1.1';
Dries Buytaert
committed
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
Dries Buytaert
committed
$ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField();
$this->assertTrue($ip, t('IP address found in database.'));
$this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.'));
Dries Buytaert
committed
// Try to block an IP address that's already blocked.
$edit = array();
$edit['ip'] = '192.168.1.1';
Dries Buytaert
committed
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
Dries Buytaert
committed
$this->assertText(t('This IP address is already blocked.'));
// Try to block a reserved IP address.
$edit = array();
$edit['ip'] = '255.255.255.255';
Dries Buytaert
committed
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
$this->assertText(t('Enter a valid IP address.'));
Dries Buytaert
committed
// Try to block a reserved IP address.
$edit = array();
$edit['ip'] = 'test.example.com';
Dries Buytaert
committed
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
$this->assertText(t('Enter a valid IP address.'));
Dries Buytaert
committed
// Submit an empty form.
$edit = array();
$edit['ip'] = '';
Dries Buytaert
committed
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
$this->assertText(t('Enter a valid IP address.'));
Dries Buytaert
committed
Dries Buytaert
committed
// Pass an IP address as a URL parameter and submit it.
$submit_ip = '1.2.3.4';
Dries Buytaert
committed
$this->drupalPost('admin/config/people/ip-blocking/' . $submit_ip, NULL, t('Add'));
Dries Buytaert
committed
$ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchField();
$this->assertTrue($ip, t('IP address found in database'));
$this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $submit_ip)), t('IP address was blocked.'));
Dries Buytaert
committed
Dries Buytaert
committed
// Submit your own IP address. This fails, although it works when testing manually.
// TODO: on some systems this test fails due to a bug or inconsistency in cURL.
// $edit = array();
// $edit['ip'] = ip_address();
// $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
// $this->assertText(t('You may not block your own IP address.'));
Dries Buytaert
committed
}
}
Dries Buytaert
committed
class CronRunTestCase extends DrupalWebTestCase {
Dries Buytaert
committed
* Implement getInfo().
Angie Byron
committed
public static function getInfo() {
'name' => 'Cron run',
'description' => 'Test cron run.',
'group' => 'System'
Angie Byron
committed
function setUp() {
parent::setUp(array('common_test', 'common_test_cron_helper'));
}
/**
* Test cron runs.
*/
function testCronRun() {
Dries Buytaert
committed
global $base_url;
Dries Buytaert
committed
// Run cron anonymously without any cron key.
Dries Buytaert
committed
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE));
$this->assertResponse(403);
// Run cron anonymously with a random cron key.
$key = $this->randomName(16);
Dries Buytaert
committed
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key)));
$this->assertResponse(403);
// Run cron anonymously with the valid cron key.
$key = variable_get('cron_key', 'drupal');
Dries Buytaert
committed
$this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key)));
$this->assertResponse(200);
}
Dries Buytaert
committed
Dries Buytaert
committed
/**
* Ensure that the automatic cron run feature is working.
Dries Buytaert
committed
*
* In these tests we do not use REQUEST_TIME to track start time, because we
* need the exact time when cron is triggered.
*/
Dries Buytaert
committed
function testAutomaticCron() {
Dries Buytaert
committed
// Ensure cron does not run when the cron threshold is enabled and was
// not passed.
Dries Buytaert
committed
$cron_last = time();
$cron_safe_threshold = 100;
variable_set('cron_last', $cron_last);
variable_set('cron_safe_threshold', $cron_safe_threshold);
Dries Buytaert
committed
$this->drupalGet('');
Jennifer Hodgdon
committed
$this->assertTrue($cron_last == variable_get('cron_last', NULL), 'Cron does not run when the cron threshold is not passed.');
Dries Buytaert
committed
// Test if cron runs when the cron threshold was passed.
Dries Buytaert
committed
$cron_last = time() - 200;
variable_set('cron_last', $cron_last);
Dries Buytaert
committed
$this->drupalGet('');
Dries Buytaert
committed
sleep(1);
Jennifer Hodgdon
committed
$this->assertTrue($cron_last < variable_get('cron_last', NULL), 'Cron runs when the cron threshold is passed.');
Dries Buytaert
committed
// Disable the cron threshold through the interface.
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->drupalLogin($admin_user);
$this->drupalPost('admin/config/system/cron', array('cron_safe_threshold' => 0), t('Save configuration'));
Dries Buytaert
committed
$this->assertText(t('The configuration options have been saved.'));
$this->drupalLogout();
// Test if cron does not run when the cron threshold is disabled.
$cron_last = time() - 200;
variable_set('cron_last', $cron_last);
Dries Buytaert
committed
$this->drupalGet('');
Jennifer Hodgdon
committed
$this->assertTrue($cron_last == variable_get('cron_last', NULL), 'Cron does not run when the cron threshold is disabled.');
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Ensure that temporary files are removed.
Dries Buytaert
committed
*
* Create files for all the possible combinations of age and status. We are
* using UPDATE statements rather than file_save() because it would set the
Dries Buytaert
committed
* timestamp.
Dries Buytaert
committed
*/
function testTempFileCleanup() {
// Temporary file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
$temp_old = file_save_data('');
Dries Buytaert
committed
db_update('file_managed')
Dries Buytaert
committed
->fields(array(
'status' => 0,
'timestamp' => 1,
))
->condition('fid', $temp_old->fid)
->execute();
Jennifer Hodgdon
committed
$this->assertTrue(file_exists($temp_old->uri), 'Old temp file was created correctly.');
Dries Buytaert
committed
// Temporary file that is less than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
$temp_new = file_save_data('');
Dries Buytaert
committed
db_update('file_managed')
Dries Buytaert
committed
->fields(array('status' => 0))
->condition('fid', $temp_new->fid)
->execute();
Jennifer Hodgdon
committed
$this->assertTrue(file_exists($temp_new->uri), 'New temp file was created correctly.');
Dries Buytaert
committed
// Permanent file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
$perm_old = file_save_data('');
Dries Buytaert
committed
db_update('file_managed')
Dries Buytaert
committed
->fields(array('timestamp' => 1))
->condition('fid', $temp_old->fid)
->execute();
Jennifer Hodgdon
committed
$this->assertTrue(file_exists($perm_old->uri), 'Old permanent file was created correctly.');
Dries Buytaert
committed
// Permanent file that is newer than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
$perm_new = file_save_data('');
Jennifer Hodgdon
committed
$this->assertTrue(file_exists($perm_new->uri), 'New permanent file was created correctly.');
Dries Buytaert
committed
// Run cron and then ensure that only the old, temp file was deleted.
Angie Byron
committed
$this->cronRun();
Jennifer Hodgdon
committed
$this->assertFalse(file_exists($temp_old->uri), 'Old temp file was correctly removed.');
$this->assertTrue(file_exists($temp_new->uri), 'New temp file was correctly ignored.');
$this->assertTrue(file_exists($perm_old->uri), 'Old permanent file was correctly ignored.');
$this->assertTrue(file_exists($perm_new->uri), 'New permanent file was correctly ignored.');
Dries Buytaert
committed
}
Angie Byron
committed
/**
* Make sure exceptions thrown on hook_cron() don't affect other modules.
*/
function testCronExceptions() {
variable_del('common_test_cron');
// The common_test module throws an exception. If it isn't caught, the tests
// won't finish successfully.
// The common_test_cron_helper module sets the 'common_test_cron' variable.
$this->cronRun();
$result = variable_get('common_test_cron');
Jennifer Hodgdon
committed
$this->assertEqual($result, 'success', 'Cron correctly handles exceptions thrown during hook_cron() invocations.');
Angie Byron
committed
}
Dries Buytaert
committed
}
David Rothstein
committed
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
/**
* Test execution of the cron queue.
*/
class CronQueueTestCase extends DrupalWebTestCase {
/**
* Implement getInfo().
*/
public static function getInfo() {
return array(
'name' => 'Cron queue functionality',
'description' => 'Tests the cron queue runner.',
'group' => 'System'
);
}
function setUp() {
parent::setUp(array('common_test', 'common_test_cron_helper'));
}
/**
* Tests that exceptions thrown by workers are handled properly.
*/
function testExceptions() {
$queue = DrupalQueue::get('cron_queue_test_exception');
// Enqueue an item for processing.
$queue->createItem(array($this->randomName() => $this->randomName()));
// Run cron; the worker for this queue should throw an exception and handle
// it.
$this->cronRun();
// The item should be left in the queue.
$this->assertEqual($queue->numberOfItems(), 1, 'Failing item still in the queue after throwing an exception.');
}
}
class AdminMetaTagTestCase extends DrupalWebTestCase {
/**
Dries Buytaert
committed
* Implement getInfo().
Angie Byron
committed
public static function getInfo() {
return array(
'name' => 'Fingerprinting meta tag',
'description' => 'Confirm that the fingerprinting meta tag appears as expected.',
'group' => 'System'
);
}
/**
* Verify that the meta tag HTML is generated correctly.
*/
public function testMetaTag() {
list($version, ) = explode('.', VERSION);
$string = '<meta name="Generator" content="Drupal ' . $version . ' (http://drupal.org)" />';
$this->drupalGet('node');
Jennifer Hodgdon
committed
$this->assertRaw($string, 'Fingerprinting meta tag generated correctly.', 'System');
}
}
Dries Buytaert
committed
/**
* Tests custom access denied functionality.
*/
class AccessDeniedTestCase extends DrupalWebTestCase {
protected $admin_user;
Angie Byron
committed
public static function getInfo() {
'name' => '403 functionality',
Dries Buytaert
committed
'description' => 'Tests page access denied functionality, including custom 403 pages.',
'group' => 'System'
);
}
function setUp() {
parent::setUp();
// Create an administrative user.
Dries Buytaert
committed
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'administer blocks'));
}
function testAccessDenied() {
$this->drupalGet('admin');
Jennifer Hodgdon
committed
$this->assertText(t('Access denied'), 'Found the default 403 page');
Angie Byron
committed
$this->assertResponse(403);
Dries Buytaert
committed
$this->drupalLogin($this->admin_user);
'title' => $this->randomName(10),
'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
);
$node = $this->drupalCreateNode($edit);
// Use a custom 403 page.
Angie Byron
committed
$this->drupalPost('admin/config/system/site-information', array('site_403' => 'node/' . $node->nid), t('Save configuration'));
Dries Buytaert
committed
$this->drupalLogout();
Jennifer Hodgdon
committed
$this->assertText($node->title, 'Found the custom 403 page');
// Logout and check that the user login block is shown on custom 403 pages.
$this->drupalLogout();