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) {
return $this->assertTrue($tables, t('Tables matching "@base_table" found.', array('@base_table' => $base_table)));

Dries Buytaert
committed
}
return $this->assertFalse($tables, t('Tables matching "@base_table" not found.', array('@base_table' => $base_table)));
}
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* 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;
}
}
return $this->assertTrue($tables_exist, t('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;
}
}
return $this->assertFalse($tables_exist, t('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.';
}
$this->assertEqual(module_exists($module), $enabled, t($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();
$this->assertTrue($count > 0, t('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() {
147
148
149
150
151
152
153
154
155
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// 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]);
}
}
$this->assertTrue(count($modules), t('Found @count core modules that we can try to enable in this test.', array('@count' => count($modules))));
// 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'));
}
$this->assertText(t('The configuration options have been saved.'), t('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'));
$this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
}

Dries Buytaert
committed
/**
* Tests entity cache after enabling a module with a dependency on an enitity
* providing module.

Angie Byron
committed
*
* @see entity_cache_test_watchdog()

Dries Buytaert
committed
*/
function testEntityCache() {
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
}
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/**
* 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'));
$this->assertText(t('The configuration options have been saved.'), t('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'));
$this->assertText(t('The selected modules have been uninstalled.'), t('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.
$this->assertText(t('Requirements 1 Test failed requirements'), t('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'));
$this->assertText(t('Some required modules must be enabled'), t('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'));
$this->assertText(t('The configuration options have been saved.'), t('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');
$this->assertRaw(t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst('_missing_dependency'))), t('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]"]');
$this->assert(count($checkbox) == 1, t('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'));
$this->assertText(t('The @module module is missing, so the following module will be disabled: @depends.', array('@module' => '_missing_dependency', '@depends' => 'system_dependencies_test')), t('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
/**
* 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.
$this->assertText(t('Requirements 1 Test failed requirements'), t('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);
}
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
/**
* Tests re-enabling forum with taxonomy disabled.
*/
function testEnableForumTaxonomyFieldDependency() {
// Enable the forum module.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), TRUE);
// Disable the forum module.
$edit = array();
$edit['modules[Core][forum][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
// Disable the taxonomy module.
$edit = array();
$edit['modules[Core][taxonomy][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('taxonomy'), FALSE);
// Attempt to re-enable the forum module with taxonomy disabled and ensure
// forum does not try to recreate the taxonomy_forums field.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('Some required modules must be enabled'), t('Dependency required.'));
$this->drupalPost(NULL, NULL, t('Continue'));
$this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
$this->assertModules(array('taxonomy', 'forum'), TRUE);
}

Angie Byron
committed
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
/**
* 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
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
/**
* 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);
// Disable forum and taxonomy. Both should now be installed but disabled.
$edit = array('modules[Core][forum][enable]' => FALSE);
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
$edit = array('modules[Core][taxonomy][enable]' => FALSE);
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('taxonomy'), FALSE);
// Check that the taxonomy module cannot be uninstalled.
$this->drupalGet('admin/modules/uninstall');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[taxonomy]"]');
$this->assert(count($checkbox) == 1, t('Checkbox for uninstalling the taxonomy module is disabled.'));
// 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'));
$this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
$edit = array('uninstall[taxonomy]' => 'taxonomy');
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, NULL, t('Uninstall'));
$this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
}

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'])) {
$this->assertFieldByXPath("//input[@name='$field_name' and @disabled='disabled' and @checked='checked']", '', t('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'
);
}
/**
* 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('');
$this->assertTrue($cron_last == variable_get('cron_last', NULL), t('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);
$this->assertTrue($cron_last < variable_get('cron_last', NULL), t('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('');
$this->assertTrue($cron_last == variable_get('cron_last', NULL), t('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();
$this->assertTrue(file_exists($temp_old->uri), t('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();
$this->assertTrue(file_exists($temp_new->uri), t('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();
$this->assertTrue(file_exists($perm_old->uri), t('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('');
$this->assertTrue(file_exists($perm_new->uri), t('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();
$this->assertFalse(file_exists($temp_old->uri), t('Old temp file was correctly removed.'));
$this->assertTrue(file_exists($temp_new->uri), t('New temp file was correctly ignored.'));
$this->assertTrue(file_exists($perm_old->uri), t('Old permanent file was correctly ignored.'));
$this->assertTrue(file_exists($perm_new->uri), t('New permanent file was correctly ignored.'));

Dries Buytaert
committed
}

Dries Buytaert
committed
}
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');
$this->assertRaw($string, t('Fingerprinting meta tag generated correctly.'), t('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');
$this->assertText(t('Access denied'), t('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();
$this->assertText($node->title, t('Found the custom 403 page'));
// Logout and check that the user login block is shown on custom 403 pages.
$this->drupalLogout();
$this->drupalGet('admin');
$this->assertText($node->title, t('Found the custom 403 page'));
$this->assertText(t('User login'), t('Blocks are shown on the custom 403 page'));
// Log back in and remove the custom 403 page.
$this->drupalLogin($this->admin_user);

Angie Byron
committed
$this->drupalPost('admin/config/system/site-information', array('site_403' => ''), t('Save configuration'));
// Logout and check that the user login block is shown on default 403 pages.
$this->drupalLogout();
$this->drupalGet('admin');
$this->assertText(t('Access denied'), t('Found the default 403 page'));

Angie Byron
committed
$this->assertResponse(403);
$this->assertText(t('User login'), t('Blocks are shown on the default 403 page'));

Angie Byron
committed
// Log back in, set the custom 403 page to /user and remove the block
$this->drupalLogin($this->admin_user);
variable_set('site_403', 'user');
$this->drupalPost('admin/structure/block', array('blocks[user_login][region]' => '-1'), t('Save blocks'));

Angie Byron
committed
// Check that we can log in from the 403 page.
$this->drupalLogout();
$edit = array(
'name' => $this->admin_user->name,
'pass' => $this->admin_user->pass_raw,
);

Angie Byron
committed
$this->drupalPost('admin/config/system/site-information', $edit, t('Log in'));

Angie Byron
committed
// Check that we're still on the same page.
$this->assertText(t('Site information'));

Dries Buytaert
committed
class PageNotFoundTestCase extends DrupalWebTestCase {
protected $admin_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' => '404 functionality',
'description' => "Tests page not found functionality, including custom 404 pages.",
'group' => 'System'

Dries Buytaert
committed
);
}

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Implement setUp().

Dries Buytaert
committed
*/
function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->drupalLogin($this->admin_user);
}
function testPageNotFound() {
$this->drupalGet($this->randomName(10));
$this->assertText(t('Page not found'), t('Found the default 404 page'));

Dries Buytaert
committed
$edit = array(
'title' => $this->randomName(10),
'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),

Dries Buytaert
committed
);
$node = $this->drupalCreateNode($edit);
// Use a custom 404 page.

Angie Byron
committed
$this->drupalPost('admin/config/system/site-information', array('site_404' => 'node/' . $node->nid), t('Save configuration'));

Dries Buytaert
committed
$this->drupalGet($this->randomName(10));
$this->assertText($node->title, t('Found the custom 404 page'));

Dries Buytaert
committed
}
}

Angie Byron
committed
/**
* Tests site maintenance functionality.
*/
class SiteMaintenanceTestCase extends DrupalWebTestCase {
protected $admin_user;
public static function getInfo() {
return array(
'name' => 'Site maintenance mode functionality',
'description' => 'Test access to site while in maintenance mode.',
'group' => 'System',
);
}
function setUp() {
parent::setUp();
// Create a user allowed to access site in maintenance mode.
$this->user = $this->drupalCreateUser(array('access site in maintenance mode'));
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access site in maintenance mode'));