|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Tests for system.module. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Helper class for module test cases. |
|
10 */ |
|
11 class ModuleTestCase extends DrupalWebTestCase { |
|
12 protected $admin_user; |
|
13 |
|
14 function setUp() { |
|
15 parent::setUp('system_test'); |
|
16 |
|
17 $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules')); |
|
18 $this->drupalLogin($this->admin_user); |
|
19 } |
|
20 |
|
21 /** |
|
22 * Assert there are tables that begin with the specified base table name. |
|
23 * |
|
24 * @param $base_table |
|
25 * Beginning of table name to look for. |
|
26 * @param $count |
|
27 * (optional) Whether or not to assert that there are tables that match the |
|
28 * specified base table. Defaults to TRUE. |
|
29 */ |
|
30 function assertTableCount($base_table, $count = TRUE) { |
|
31 $tables = db_find_tables(Database::getConnection()->prefixTables('{' . $base_table . '}') . '%'); |
|
32 |
|
33 if ($count) { |
|
34 return $this->assertTrue($tables, format_string('Tables matching "@base_table" found.', array('@base_table' => $base_table))); |
|
35 } |
|
36 return $this->assertFalse($tables, format_string('Tables matching "@base_table" not found.', array('@base_table' => $base_table))); |
|
37 } |
|
38 |
|
39 /** |
|
40 * Assert that all tables defined in a module's hook_schema() exist. |
|
41 * |
|
42 * @param $module |
|
43 * The name of the module. |
|
44 */ |
|
45 function assertModuleTablesExist($module) { |
|
46 $tables = array_keys(drupal_get_schema_unprocessed($module)); |
|
47 $tables_exist = TRUE; |
|
48 foreach ($tables as $table) { |
|
49 if (!db_table_exists($table)) { |
|
50 $tables_exist = FALSE; |
|
51 } |
|
52 } |
|
53 return $this->assertTrue($tables_exist, format_string('All database tables defined by the @module module exist.', array('@module' => $module))); |
|
54 } |
|
55 |
|
56 /** |
|
57 * Assert that none of the tables defined in a module's hook_schema() exist. |
|
58 * |
|
59 * @param $module |
|
60 * The name of the module. |
|
61 */ |
|
62 function assertModuleTablesDoNotExist($module) { |
|
63 $tables = array_keys(drupal_get_schema_unprocessed($module)); |
|
64 $tables_exist = FALSE; |
|
65 foreach ($tables as $table) { |
|
66 if (db_table_exists($table)) { |
|
67 $tables_exist = TRUE; |
|
68 } |
|
69 } |
|
70 return $this->assertFalse($tables_exist, format_string('None of the database tables defined by the @module module exist.', array('@module' => $module))); |
|
71 } |
|
72 |
|
73 /** |
|
74 * Assert the list of modules are enabled or disabled. |
|
75 * |
|
76 * @param $modules |
|
77 * Module list to check. |
|
78 * @param $enabled |
|
79 * Expected module state. |
|
80 */ |
|
81 function assertModules(array $modules, $enabled) { |
|
82 module_list(TRUE); |
|
83 foreach ($modules as $module) { |
|
84 if ($enabled) { |
|
85 $message = 'Module "@module" is enabled.'; |
|
86 } |
|
87 else { |
|
88 $message = 'Module "@module" is not enabled.'; |
|
89 } |
|
90 $this->assertEqual(module_exists($module), $enabled, format_string($message, array('@module' => $module))); |
|
91 } |
|
92 } |
|
93 |
|
94 /** |
|
95 * Verify a log entry was entered for a module's status change. |
|
96 * Called in the same way of the expected original watchdog() execution. |
|
97 * |
|
98 * @param $type |
|
99 * The category to which this message belongs. |
|
100 * @param $message |
|
101 * The message to store in the log. Keep $message translatable |
|
102 * by not concatenating dynamic values into it! Variables in the |
|
103 * message should be added by using placeholder strings alongside |
|
104 * the variables argument to declare the value of the placeholders. |
|
105 * See t() for documentation on how $message and $variables interact. |
|
106 * @param $variables |
|
107 * Array of variables to replace in the message on display or |
|
108 * NULL if message is already translated or not possible to |
|
109 * translate. |
|
110 * @param $severity |
|
111 * The severity of the message, as per RFC 3164. |
|
112 * @param $link |
|
113 * A link to associate with the message. |
|
114 */ |
|
115 function assertLogMessage($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = '') { |
|
116 $count = db_select('watchdog', 'w') |
|
117 ->condition('type', $type) |
|
118 ->condition('message', $message) |
|
119 ->condition('variables', serialize($variables)) |
|
120 ->condition('severity', $severity) |
|
121 ->condition('link', $link) |
|
122 ->countQuery() |
|
123 ->execute() |
|
124 ->fetchField(); |
|
125 $this->assertTrue($count > 0, format_string('watchdog table contains @count rows for @message', array('@count' => $count, '@message' => $message))); |
|
126 } |
|
127 } |
|
128 |
|
129 /** |
|
130 * Test module enabling/disabling functionality. |
|
131 */ |
|
132 class EnableDisableTestCase extends ModuleTestCase { |
|
133 protected $profile = 'testing'; |
|
134 |
|
135 public static function getInfo() { |
|
136 return array( |
|
137 'name' => 'Enable/disable modules', |
|
138 'description' => 'Enable/disable core module and confirm table creation/deletion.', |
|
139 'group' => 'Module', |
|
140 ); |
|
141 } |
|
142 |
|
143 /** |
|
144 * Test that all core modules can be enabled, disabled and uninstalled. |
|
145 */ |
|
146 function testEnableDisable() { |
|
147 // Try to enable, disable and uninstall all core modules, unless they are |
|
148 // hidden or required. |
|
149 $modules = system_rebuild_module_data(); |
|
150 foreach ($modules as $name => $module) { |
|
151 if ($module->info['package'] != 'Core' || !empty($module->info['hidden']) || !empty($module->info['required'])) { |
|
152 unset($modules[$name]); |
|
153 } |
|
154 } |
|
155 $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 // Enable the dblog module first, since we will be asserting the presence |
|
158 // of log messages throughout the test. |
|
159 if (isset($modules['dblog'])) { |
|
160 $modules = array('dblog' => $modules['dblog']) + $modules; |
|
161 } |
|
162 |
|
163 // Set a variable so that the hook implementations in system_test.module |
|
164 // will display messages via drupal_set_message(). |
|
165 variable_set('test_verbose_module_hooks', TRUE); |
|
166 |
|
167 // Throughout this test, some modules may be automatically enabled (due to |
|
168 // dependencies). We'll keep track of them in an array, so we can handle |
|
169 // them separately. |
|
170 $automatically_enabled = array(); |
|
171 |
|
172 // Go through each module in the list and try to enable it (unless it was |
|
173 // already enabled automatically due to a dependency). |
|
174 foreach ($modules as $name => $module) { |
|
175 if (empty($automatically_enabled[$name])) { |
|
176 // Start a list of modules that we expect to be enabled this time. |
|
177 $modules_to_enable = array($name); |
|
178 |
|
179 // Find out if the module has any dependencies that aren't enabled yet; |
|
180 // if so, add them to the list of modules we expect to be automatically |
|
181 // enabled. |
|
182 foreach (array_keys($module->requires) as $dependency) { |
|
183 if (isset($modules[$dependency]) && empty($automatically_enabled[$dependency])) { |
|
184 $modules_to_enable[] = $dependency; |
|
185 $automatically_enabled[$dependency] = TRUE; |
|
186 } |
|
187 } |
|
188 |
|
189 // Check that each module is not yet enabled and does not have any |
|
190 // database tables yet. |
|
191 foreach ($modules_to_enable as $module_to_enable) { |
|
192 $this->assertModules(array($module_to_enable), FALSE); |
|
193 $this->assertModuleTablesDoNotExist($module_to_enable); |
|
194 } |
|
195 |
|
196 // Install and enable the module. |
|
197 $edit = array(); |
|
198 $edit['modules[Core][' . $name . '][enable]'] = $name; |
|
199 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
200 // Handle the case where modules were installed along with this one and |
|
201 // where we therefore hit a confirmation screen. |
|
202 if (count($modules_to_enable) > 1) { |
|
203 $this->drupalPost(NULL, array(), t('Continue')); |
|
204 } |
|
205 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
206 |
|
207 // Check that hook_modules_installed() and hook_modules_enabled() were |
|
208 // invoked with the expected list of modules, that each module's |
|
209 // database tables now exist, and that appropriate messages appear in |
|
210 // the logs. |
|
211 foreach ($modules_to_enable as $module_to_enable) { |
|
212 $this->assertText(t('hook_modules_installed fired for @module', array('@module' => $module_to_enable))); |
|
213 $this->assertText(t('hook_modules_enabled fired for @module', array('@module' => $module_to_enable))); |
|
214 $this->assertModules(array($module_to_enable), TRUE); |
|
215 $this->assertModuleTablesExist($module_to_enable); |
|
216 $this->assertLogMessage('system', "%module module installed.", array('%module' => $module_to_enable), WATCHDOG_INFO); |
|
217 $this->assertLogMessage('system', "%module module enabled.", array('%module' => $module_to_enable), WATCHDOG_INFO); |
|
218 } |
|
219 |
|
220 // Disable and uninstall the original module, and check appropriate |
|
221 // hooks, tables, and log messages. (Later, we'll go back and do the |
|
222 // same thing for modules that were enabled automatically.) Skip this |
|
223 // for the dblog module, because that is needed for the test; we'll go |
|
224 // back and do that one at the end also. |
|
225 if ($name != 'dblog') { |
|
226 $this->assertSuccessfulDisableAndUninstall($name); |
|
227 } |
|
228 } |
|
229 } |
|
230 |
|
231 // Go through all modules that were automatically enabled, and try to |
|
232 // disable and uninstall them one by one. |
|
233 while (!empty($automatically_enabled)) { |
|
234 $initial_count = count($automatically_enabled); |
|
235 foreach (array_keys($automatically_enabled) as $name) { |
|
236 // If the module can't be disabled due to dependencies, skip it and try |
|
237 // again the next time. Otherwise, try to disable it. |
|
238 $this->drupalGet('admin/modules'); |
|
239 $disabled_checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Core][' . $name . '][enable]"]'); |
|
240 if (empty($disabled_checkbox) && $name != 'dblog') { |
|
241 unset($automatically_enabled[$name]); |
|
242 $this->assertSuccessfulDisableAndUninstall($name); |
|
243 } |
|
244 } |
|
245 $final_count = count($automatically_enabled); |
|
246 // If all checkboxes were disabled, something is really wrong with the |
|
247 // test. Throw a failure and avoid an infinite loop. |
|
248 if ($initial_count == $final_count) { |
|
249 $this->fail(t('Remaining modules could not be disabled.')); |
|
250 break; |
|
251 } |
|
252 } |
|
253 |
|
254 // Disable and uninstall the dblog module last, since we needed it for |
|
255 // assertions in all the above tests. |
|
256 if (isset($modules['dblog'])) { |
|
257 $this->assertSuccessfulDisableAndUninstall('dblog'); |
|
258 } |
|
259 |
|
260 // Now that all modules have been tested, go back and try to enable them |
|
261 // all again at once. This tests two things: |
|
262 // - That each module can be successfully enabled again after being |
|
263 // uninstalled. |
|
264 // - That enabling more than one module at the same time does not lead to |
|
265 // any errors. |
|
266 $edit = array(); |
|
267 foreach (array_keys($modules) as $name) { |
|
268 $edit['modules[Core][' . $name . '][enable]'] = $name; |
|
269 } |
|
270 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
271 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
272 } |
|
273 |
|
274 /** |
|
275 * Ensures entity info cache is updated after changes. |
|
276 */ |
|
277 function testEntityInfoChanges() { |
|
278 module_enable(array('entity_cache_test')); |
|
279 $entity_info = entity_get_info(); |
|
280 $this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.'); |
|
281 |
|
282 // Change the label of the test entity type and make sure changes appear |
|
283 // after flushing caches. |
|
284 variable_set('entity_cache_test_label', 'New label.'); |
|
285 drupal_flush_all_caches(); |
|
286 $info = entity_get_info('entity_cache_test'); |
|
287 $this->assertEqual($info['label'], 'New label.', 'New label appears in entity info.'); |
|
288 |
|
289 // Disable the providing module and make sure the entity type is gone. |
|
290 module_disable(array('entity_cache_test', 'entity_cache_test_dependency')); |
|
291 $entity_info = entity_get_info(); |
|
292 $this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.'); |
|
293 } |
|
294 |
|
295 /** |
|
296 * Tests entity info cache after enabling a module with a dependency on an entity providing module. |
|
297 * |
|
298 * @see entity_cache_test_watchdog() |
|
299 */ |
|
300 function testEntityInfoCacheWatchdog() { |
|
301 module_enable(array('entity_cache_test')); |
|
302 $info = variable_get('entity_cache_test'); |
|
303 $this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.'); |
|
304 $this->assertEqual($info['controller class'], 'DrupalDefaultEntityController', 'Entity controller class info is correct.'); |
|
305 } |
|
306 |
|
307 /** |
|
308 * Disables and uninstalls a module and asserts that it was done correctly. |
|
309 * |
|
310 * @param $module |
|
311 * The name of the module to disable and uninstall. |
|
312 */ |
|
313 function assertSuccessfulDisableAndUninstall($module) { |
|
314 // Disable the module. |
|
315 $edit = array(); |
|
316 $edit['modules[Core][' . $module . '][enable]'] = FALSE; |
|
317 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
318 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
319 $this->assertModules(array($module), FALSE); |
|
320 |
|
321 // Check that the appropriate hook was fired and the appropriate log |
|
322 // message appears. |
|
323 $this->assertText(t('hook_modules_disabled fired for @module', array('@module' => $module))); |
|
324 $this->assertLogMessage('system', "%module module disabled.", array('%module' => $module), WATCHDOG_INFO); |
|
325 |
|
326 // Check that the module's database tables still exist. |
|
327 $this->assertModuleTablesExist($module); |
|
328 |
|
329 // Uninstall the module. |
|
330 $edit = array(); |
|
331 $edit['uninstall[' . $module . ']'] = $module; |
|
332 $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); |
|
333 $this->drupalPost(NULL, NULL, t('Uninstall')); |
|
334 $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.'); |
|
335 $this->assertModules(array($module), FALSE); |
|
336 |
|
337 // Check that the appropriate hook was fired and the appropriate log |
|
338 // message appears. (But don't check for the log message if the dblog |
|
339 // module was just uninstalled, since the {watchdog} table won't be there |
|
340 // anymore.) |
|
341 $this->assertText(t('hook_modules_uninstalled fired for @module', array('@module' => $module))); |
|
342 if ($module != 'dblog') { |
|
343 $this->assertLogMessage('system', "%module module uninstalled.", array('%module' => $module), WATCHDOG_INFO); |
|
344 } |
|
345 |
|
346 // Check that the module's database tables no longer exist. |
|
347 $this->assertModuleTablesDoNotExist($module); |
|
348 } |
|
349 } |
|
350 |
|
351 /** |
|
352 * Tests failure of hook_requirements('install'). |
|
353 */ |
|
354 class HookRequirementsTestCase extends ModuleTestCase { |
|
355 public static function getInfo() { |
|
356 return array( |
|
357 'name' => 'Requirements hook failure', |
|
358 'description' => "Attempts enabling a module that fails hook_requirements('install').", |
|
359 'group' => 'Module', |
|
360 ); |
|
361 } |
|
362 |
|
363 /** |
|
364 * Assert that a module cannot be installed if it fails hook_requirements(). |
|
365 */ |
|
366 function testHookRequirementsFailure() { |
|
367 $this->assertModules(array('requirements1_test'), FALSE); |
|
368 |
|
369 // Attempt to install the requirements1_test module. |
|
370 $edit = array(); |
|
371 $edit['modules[Testing][requirements1_test][enable]'] = 'requirements1_test'; |
|
372 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
373 |
|
374 // Makes sure the module was NOT installed. |
|
375 $this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.'); |
|
376 $this->assertModules(array('requirements1_test'), FALSE); |
|
377 } |
|
378 } |
|
379 |
|
380 /** |
|
381 * Test module dependency functionality. |
|
382 */ |
|
383 class ModuleDependencyTestCase extends ModuleTestCase { |
|
384 public static function getInfo() { |
|
385 return array( |
|
386 'name' => 'Module dependencies', |
|
387 'description' => 'Enable module without dependency enabled.', |
|
388 'group' => 'Module', |
|
389 ); |
|
390 } |
|
391 |
|
392 /** |
|
393 * Checks functionality of project namespaces for dependencies. |
|
394 */ |
|
395 function testProjectNamespaceForDependencies() { |
|
396 // Enable module with project namespace to ensure nothing breaks. |
|
397 $edit = array( |
|
398 'modules[Testing][system_project_namespace_test][enable]' => TRUE, |
|
399 ); |
|
400 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
401 $this->assertModules(array('system_project_namespace_test'), TRUE); |
|
402 } |
|
403 |
|
404 /** |
|
405 * Attempt to enable translation module without locale enabled. |
|
406 */ |
|
407 function testEnableWithoutDependency() { |
|
408 // Attempt to enable content translation without locale enabled. |
|
409 $edit = array(); |
|
410 $edit['modules[Core][translation][enable]'] = 'translation'; |
|
411 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
412 $this->assertText(t('Some required modules must be enabled'), 'Dependency required.'); |
|
413 |
|
414 $this->assertModules(array('translation', 'locale'), FALSE); |
|
415 |
|
416 // Assert that the locale tables weren't enabled. |
|
417 $this->assertTableCount('languages', FALSE); |
|
418 $this->assertTableCount('locale', FALSE); |
|
419 |
|
420 $this->drupalPost(NULL, NULL, t('Continue')); |
|
421 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
422 |
|
423 $this->assertModules(array('translation', 'locale'), TRUE); |
|
424 |
|
425 // Assert that the locale tables were enabled. |
|
426 $this->assertTableCount('languages', TRUE); |
|
427 $this->assertTableCount('locale', TRUE); |
|
428 } |
|
429 |
|
430 /** |
|
431 * Attempt to enable a module with a missing dependency. |
|
432 */ |
|
433 function testMissingModules() { |
|
434 // Test that the system_dependencies_test module is marked |
|
435 // as missing a dependency. |
|
436 $this->drupalGet('admin/modules'); |
|
437 $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.'); |
|
438 $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_dependencies_test][enable]"]'); |
|
439 $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.'); |
|
440 |
|
441 // Force enable the system_dependencies_test module. |
|
442 module_enable(array('system_dependencies_test'), FALSE); |
|
443 |
|
444 // Verify that the module is forced to be disabled when submitting |
|
445 // the module page. |
|
446 $this->drupalPost('admin/modules', array(), t('Save configuration')); |
|
447 $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.'); |
|
448 |
|
449 // Confirm. |
|
450 $this->drupalPost(NULL, NULL, t('Continue')); |
|
451 |
|
452 // Verify that the module has been disabled. |
|
453 $this->assertModules(array('system_dependencies_test'), FALSE); |
|
454 } |
|
455 |
|
456 /** |
|
457 * Tests enabling a module that depends on an incompatible version of a module. |
|
458 */ |
|
459 function testIncompatibleModuleVersionDependency() { |
|
460 // Test that the system_incompatible_module_version_dependencies_test is |
|
461 // marked as having an incompatible dependency. |
|
462 $this->drupalGet('admin/modules'); |
|
463 $this->assertRaw(t('@module (<span class="admin-missing">incompatible with</span> version @version)', array( |
|
464 '@module' => 'System incompatible module version test (>2.0)', |
|
465 '@version' => '1.0', |
|
466 )), 'A module that depends on an incompatible version of a module is marked as such.'); |
|
467 $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_incompatible_module_version_dependencies_test][enable]"]'); |
|
468 $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.'); |
|
469 } |
|
470 |
|
471 /** |
|
472 * Tests enabling a module that depends on a module with an incompatible core version. |
|
473 */ |
|
474 function testIncompatibleCoreVersionDependency() { |
|
475 // Test that the system_incompatible_core_version_dependencies_test is |
|
476 // marked as having an incompatible dependency. |
|
477 $this->drupalGet('admin/modules'); |
|
478 $this->assertRaw(t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array( |
|
479 '@module' => 'System incompatible core version test', |
|
480 )), 'A module that depends on a module with an incompatible core version is marked as such.'); |
|
481 $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_incompatible_core_version_dependencies_test][enable]"]'); |
|
482 $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.'); |
|
483 } |
|
484 |
|
485 /** |
|
486 * Tests enabling a module that depends on a module which fails hook_requirements(). |
|
487 */ |
|
488 function testEnableRequirementsFailureDependency() { |
|
489 $this->assertModules(array('requirements1_test'), FALSE); |
|
490 $this->assertModules(array('requirements2_test'), FALSE); |
|
491 |
|
492 // Attempt to install both modules at the same time. |
|
493 $edit = array(); |
|
494 $edit['modules[Testing][requirements1_test][enable]'] = 'requirements1_test'; |
|
495 $edit['modules[Testing][requirements2_test][enable]'] = 'requirements2_test'; |
|
496 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
497 |
|
498 // Makes sure the modules were NOT installed. |
|
499 $this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.'); |
|
500 $this->assertModules(array('requirements1_test'), FALSE); |
|
501 $this->assertModules(array('requirements2_test'), FALSE); |
|
502 |
|
503 // Makes sure that already enabled modules the failing modules depend on |
|
504 // were not disabled. |
|
505 $this->assertModules(array('comment'), TRUE); |
|
506 |
|
507 } |
|
508 |
|
509 /** |
|
510 * Tests that module dependencies are enabled in the correct order via the |
|
511 * UI. Dependencies should be enabled before their dependents. |
|
512 */ |
|
513 function testModuleEnableOrder() { |
|
514 module_enable(array('module_test'), FALSE); |
|
515 $this->resetAll(); |
|
516 $this->assertModules(array('module_test'), TRUE); |
|
517 variable_set('dependency_test', 'dependency'); |
|
518 // module_test creates a dependency chain: forum depends on poll, which |
|
519 // depends on php. The correct enable order is, php, poll, forum. |
|
520 $expected_order = array('php', 'poll', 'forum'); |
|
521 |
|
522 // Enable the modules through the UI, verifying that the dependency chain |
|
523 // is correct. |
|
524 $edit = array(); |
|
525 $edit['modules[Core][forum][enable]'] = 'forum'; |
|
526 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
527 $this->assertModules(array('forum'), FALSE); |
|
528 $this->assertText(t('You must enable the Poll, PHP filter modules to install Forum.'), t('Dependency chain created.')); |
|
529 $edit['modules[Core][poll][enable]'] = 'poll'; |
|
530 $edit['modules[Core][php][enable]'] = 'php'; |
|
531 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
532 $this->assertModules(array('forum', 'poll', 'php'), TRUE); |
|
533 |
|
534 // Check the actual order which is saved by module_test_modules_enabled(). |
|
535 $this->assertIdentical(variable_get('test_module_enable_order', FALSE), $expected_order, t('Modules enabled in the correct order.')); |
|
536 } |
|
537 |
|
538 /** |
|
539 * Tests attempting to uninstall a module that has installed dependents. |
|
540 */ |
|
541 function testUninstallDependents() { |
|
542 // Enable the forum module. |
|
543 $edit = array('modules[Core][forum][enable]' => 'forum'); |
|
544 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
545 $this->assertModules(array('forum'), TRUE); |
|
546 |
|
547 // Disable forum and comment. Both should now be installed but disabled. |
|
548 $edit = array('modules[Core][forum][enable]' => FALSE); |
|
549 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
550 $this->assertModules(array('forum'), FALSE); |
|
551 $edit = array('modules[Core][comment][enable]' => FALSE); |
|
552 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
553 $this->assertModules(array('comment'), FALSE); |
|
554 |
|
555 // Check that the taxonomy module cannot be uninstalled. |
|
556 $this->drupalGet('admin/modules/uninstall'); |
|
557 $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]'); |
|
558 $this->assert(count($checkbox) == 1, 'Checkbox for uninstalling the comment module is disabled.'); |
|
559 |
|
560 // Uninstall the forum module, and check that taxonomy now can also be |
|
561 // uninstalled. |
|
562 $edit = array('uninstall[forum]' => 'forum'); |
|
563 $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); |
|
564 $this->drupalPost(NULL, NULL, t('Uninstall')); |
|
565 $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.'); |
|
566 $edit = array('uninstall[comment]' => 'comment'); |
|
567 $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); |
|
568 $this->drupalPost(NULL, NULL, t('Uninstall')); |
|
569 $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.'); |
|
570 } |
|
571 |
|
572 /** |
|
573 * Tests whether the correct module metadata is returned. |
|
574 */ |
|
575 function testModuleMetaData() { |
|
576 // Generate the list of available modules. |
|
577 $modules = system_rebuild_module_data(); |
|
578 // Check that the mtime field exists for the system module. |
|
579 $this->assertTrue(!empty($modules['system']->info['mtime']), 'The system.info file modification time field is present.'); |
|
580 // Use 0 if mtime isn't present, to avoid an array index notice. |
|
581 $test_mtime = !empty($modules['system']->info['mtime']) ? $modules['system']->info['mtime'] : 0; |
|
582 // Ensure the mtime field contains a number that is greater than zero. |
|
583 $this->assertTrue(is_numeric($test_mtime) && ($test_mtime > 0), 'The system.info file modification time field contains a timestamp.'); |
|
584 } |
|
585 |
|
586 /** |
|
587 * Tests whether the correct theme metadata is returned. |
|
588 */ |
|
589 function testThemeMetaData() { |
|
590 // Generate the list of available themes. |
|
591 $themes = system_rebuild_theme_data(); |
|
592 // Check that the mtime field exists for the bartik theme. |
|
593 $this->assertTrue(!empty($themes['bartik']->info['mtime']), 'The bartik.info file modification time field is present.'); |
|
594 // Use 0 if mtime isn't present, to avoid an array index notice. |
|
595 $test_mtime = !empty($themes['bartik']->info['mtime']) ? $themes['bartik']->info['mtime'] : 0; |
|
596 // Ensure the mtime field contains a number that is greater than zero. |
|
597 $this->assertTrue(is_numeric($test_mtime) && ($test_mtime > 0), 'The bartik.info file modification time field contains a timestamp.'); |
|
598 } |
|
599 } |
|
600 |
|
601 /** |
|
602 * Test module dependency on specific versions. |
|
603 */ |
|
604 class ModuleVersionTestCase extends ModuleTestCase { |
|
605 public static function getInfo() { |
|
606 return array( |
|
607 'name' => 'Module versions', |
|
608 'description' => 'Check module version dependencies.', |
|
609 'group' => 'Module', |
|
610 ); |
|
611 } |
|
612 |
|
613 function setUp() { |
|
614 parent::setUp('module_test'); |
|
615 } |
|
616 |
|
617 /** |
|
618 * Test version dependencies. |
|
619 */ |
|
620 function testModuleVersions() { |
|
621 $dependencies = array( |
|
622 // Alternating between being compatible and incompatible with 7.x-2.4-beta3. |
|
623 // The first is always a compatible. |
|
624 'common_test', |
|
625 // Branch incompatibility. |
|
626 'common_test (1.x)', |
|
627 // Branch compatibility. |
|
628 'common_test (2.x)', |
|
629 // Another branch incompatibility. |
|
630 'common_test (>2.x)', |
|
631 // Another branch compatibility. |
|
632 'common_test (<=2.x)', |
|
633 // Another branch incompatibility. |
|
634 'common_test (<2.x)', |
|
635 // Another branch compatibility. |
|
636 'common_test (>=2.x)', |
|
637 // Nonsense, misses a dash. Incompatible with everything. |
|
638 'common_test (=7.x2.x, >=2.4)', |
|
639 // Core version is optional. Compatible. |
|
640 'common_test (=7.x-2.x, >=2.4-alpha2)', |
|
641 // Test !=, explicitly incompatible. |
|
642 'common_test (=2.x, !=2.4-beta3)', |
|
643 // Three operations. Compatible. |
|
644 'common_test (=2.x, !=2.3, <2.5)', |
|
645 // Testing extra version. Incompatible. |
|
646 'common_test (<=2.4-beta2)', |
|
647 // Testing extra version. Compatible. |
|
648 'common_test (>2.4-beta2)', |
|
649 // Testing extra version. Incompatible. |
|
650 'common_test (>2.4-rc0)', |
|
651 ); |
|
652 variable_set('dependencies', $dependencies); |
|
653 $n = count($dependencies); |
|
654 for ($i = 0; $i < $n; $i++) { |
|
655 $this->drupalGet('admin/modules'); |
|
656 $checkbox = $this->xpath('//input[@id="edit-modules-testing-module-test-enable"]'); |
|
657 $this->assertEqual(!empty($checkbox[0]['disabled']), $i % 2, $dependencies[$i]); |
|
658 } |
|
659 } |
|
660 } |
|
661 |
|
662 /** |
|
663 * Test required modules functionality. |
|
664 */ |
|
665 class ModuleRequiredTestCase extends ModuleTestCase { |
|
666 public static function getInfo() { |
|
667 return array( |
|
668 'name' => 'Required modules', |
|
669 'description' => 'Attempt disabling of required modules.', |
|
670 'group' => 'Module', |
|
671 ); |
|
672 } |
|
673 |
|
674 /** |
|
675 * Assert that core required modules cannot be disabled. |
|
676 */ |
|
677 function testDisableRequired() { |
|
678 $module_info = system_get_info('module'); |
|
679 $this->drupalGet('admin/modules'); |
|
680 foreach ($module_info as $module => $info) { |
|
681 // Check to make sure the checkbox for each required module is disabled |
|
682 // and checked (or absent from the page if the module is also hidden). |
|
683 if (!empty($info['required'])) { |
|
684 $field_name = "modules[{$info['package']}][$module][enable]"; |
|
685 if (empty($info['hidden'])) { |
|
686 $this->assertFieldByXPath("//input[@name='$field_name' and @disabled='disabled' and @checked='checked']", '', format_string('Field @name was disabled and checked.', array('@name' => $field_name))); |
|
687 } |
|
688 else { |
|
689 $this->assertNoFieldByName($field_name); |
|
690 } |
|
691 } |
|
692 } |
|
693 } |
|
694 } |
|
695 |
|
696 class IPAddressBlockingTestCase extends DrupalWebTestCase { |
|
697 protected $blocking_user; |
|
698 |
|
699 /** |
|
700 * Implement getInfo(). |
|
701 */ |
|
702 public static function getInfo() { |
|
703 return array( |
|
704 'name' => 'IP address blocking', |
|
705 'description' => 'Test IP address blocking.', |
|
706 'group' => 'System' |
|
707 ); |
|
708 } |
|
709 |
|
710 /** |
|
711 * Implement setUp(). |
|
712 */ |
|
713 function setUp() { |
|
714 parent::setUp(); |
|
715 |
|
716 // Create user. |
|
717 $this->blocking_user = $this->drupalCreateUser(array('block IP addresses')); |
|
718 $this->drupalLogin($this->blocking_user); |
|
719 } |
|
720 |
|
721 /** |
|
722 * Test a variety of user input to confirm correct validation and saving of data. |
|
723 */ |
|
724 function testIPAddressValidation() { |
|
725 $this->drupalGet('admin/config/people/ip-blocking'); |
|
726 |
|
727 // Block a valid IP address. |
|
728 $edit = array(); |
|
729 $edit['ip'] = '1.2.3.3'; |
|
730 $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); |
|
731 $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField(); |
|
732 $this->assertTrue($ip, t('IP address found in database.')); |
|
733 $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.')); |
|
734 |
|
735 // Try to block an IP address that's already blocked. |
|
736 $edit = array(); |
|
737 $edit['ip'] = '1.2.3.3'; |
|
738 $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); |
|
739 $this->assertText(t('This IP address is already blocked.')); |
|
740 |
|
741 // Try to block a reserved IP address. |
|
742 $edit = array(); |
|
743 $edit['ip'] = '255.255.255.255'; |
|
744 $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); |
|
745 $this->assertText(t('Enter a valid IP address.')); |
|
746 |
|
747 // Try to block a reserved IP address. |
|
748 $edit = array(); |
|
749 $edit['ip'] = 'test.example.com'; |
|
750 $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); |
|
751 $this->assertText(t('Enter a valid IP address.')); |
|
752 |
|
753 // Submit an empty form. |
|
754 $edit = array(); |
|
755 $edit['ip'] = ''; |
|
756 $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); |
|
757 $this->assertText(t('Enter a valid IP address.')); |
|
758 |
|
759 // Pass an IP address as a URL parameter and submit it. |
|
760 $submit_ip = '1.2.3.4'; |
|
761 $this->drupalPost('admin/config/people/ip-blocking/' . $submit_ip, NULL, t('Add')); |
|
762 $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchField(); |
|
763 $this->assertTrue($ip, t('IP address found in database')); |
|
764 $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $submit_ip)), t('IP address was blocked.')); |
|
765 |
|
766 // Submit your own IP address. This fails, although it works when testing manually. |
|
767 // TODO: on some systems this test fails due to a bug or inconsistency in cURL. |
|
768 // $edit = array(); |
|
769 // $edit['ip'] = ip_address(); |
|
770 // $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save')); |
|
771 // $this->assertText(t('You may not block your own IP address.')); |
|
772 } |
|
773 |
|
774 /** |
|
775 * Test duplicate IP addresses are not present in the 'blocked_ips' table. |
|
776 */ |
|
777 function testDuplicateIpAddress() { |
|
778 drupal_static_reset('ip_address'); |
|
779 $submit_ip = $_SERVER['REMOTE_ADDR'] = '192.168.1.1'; |
|
780 system_block_ip_action(); |
|
781 system_block_ip_action(); |
|
782 $ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount(); |
|
783 $this->assertEqual('1', $ip_count); |
|
784 drupal_static_reset('ip_address'); |
|
785 $submit_ip = $_SERVER['REMOTE_ADDR'] = ' '; |
|
786 system_block_ip_action(); |
|
787 system_block_ip_action(); |
|
788 system_block_ip_action(); |
|
789 $ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount(); |
|
790 $this->assertEqual('1', $ip_count); |
|
791 } |
|
792 } |
|
793 |
|
794 class CronRunTestCase extends DrupalWebTestCase { |
|
795 /** |
|
796 * Implement getInfo(). |
|
797 */ |
|
798 public static function getInfo() { |
|
799 return array( |
|
800 'name' => 'Cron run', |
|
801 'description' => 'Test cron run.', |
|
802 'group' => 'System' |
|
803 ); |
|
804 } |
|
805 |
|
806 function setUp() { |
|
807 parent::setUp(array('common_test', 'common_test_cron_helper')); |
|
808 } |
|
809 |
|
810 /** |
|
811 * Test cron runs. |
|
812 */ |
|
813 function testCronRun() { |
|
814 global $base_url; |
|
815 |
|
816 // Run cron anonymously without any cron key. |
|
817 $this->drupalGet($base_url . '/cron.php', array('external' => TRUE)); |
|
818 $this->assertResponse(403); |
|
819 |
|
820 // Run cron anonymously with a random cron key. |
|
821 $key = $this->randomName(16); |
|
822 $this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key))); |
|
823 $this->assertResponse(403); |
|
824 |
|
825 // Run cron anonymously with the valid cron key. |
|
826 $key = variable_get('cron_key', 'drupal'); |
|
827 $this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key))); |
|
828 $this->assertResponse(200); |
|
829 } |
|
830 |
|
831 /** |
|
832 * Ensure that the automatic cron run feature is working. |
|
833 * |
|
834 * In these tests we do not use REQUEST_TIME to track start time, because we |
|
835 * need the exact time when cron is triggered. |
|
836 */ |
|
837 function testAutomaticCron() { |
|
838 // Ensure cron does not run when the cron threshold is enabled and was |
|
839 // not passed. |
|
840 $cron_last = time(); |
|
841 $cron_safe_threshold = 100; |
|
842 variable_set('cron_last', $cron_last); |
|
843 variable_set('cron_safe_threshold', $cron_safe_threshold); |
|
844 $this->drupalGet(''); |
|
845 $this->assertTrue($cron_last == variable_get('cron_last', NULL), 'Cron does not run when the cron threshold is not passed.'); |
|
846 |
|
847 // Test if cron runs when the cron threshold was passed. |
|
848 $cron_last = time() - 200; |
|
849 variable_set('cron_last', $cron_last); |
|
850 $this->drupalGet(''); |
|
851 sleep(1); |
|
852 $this->assertTrue($cron_last < variable_get('cron_last', NULL), 'Cron runs when the cron threshold is passed.'); |
|
853 |
|
854 // Disable the cron threshold through the interface. |
|
855 $admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
856 $this->drupalLogin($admin_user); |
|
857 $this->drupalPost('admin/config/system/cron', array('cron_safe_threshold' => 0), t('Save configuration')); |
|
858 $this->assertText(t('The configuration options have been saved.')); |
|
859 $this->drupalLogout(); |
|
860 |
|
861 // Test if cron does not run when the cron threshold is disabled. |
|
862 $cron_last = time() - 200; |
|
863 variable_set('cron_last', $cron_last); |
|
864 $this->drupalGet(''); |
|
865 $this->assertTrue($cron_last == variable_get('cron_last', NULL), 'Cron does not run when the cron threshold is disabled.'); |
|
866 } |
|
867 |
|
868 /** |
|
869 * Ensure that temporary files are removed. |
|
870 * |
|
871 * Create files for all the possible combinations of age and status. We are |
|
872 * using UPDATE statements rather than file_save() because it would set the |
|
873 * timestamp. |
|
874 */ |
|
875 function testTempFileCleanup() { |
|
876 // Temporary file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE. |
|
877 $temp_old = file_save_data(''); |
|
878 db_update('file_managed') |
|
879 ->fields(array( |
|
880 'status' => 0, |
|
881 'timestamp' => 1, |
|
882 )) |
|
883 ->condition('fid', $temp_old->fid) |
|
884 ->execute(); |
|
885 $this->assertTrue(file_exists($temp_old->uri), 'Old temp file was created correctly.'); |
|
886 |
|
887 // Temporary file that is less than DRUPAL_MAXIMUM_TEMP_FILE_AGE. |
|
888 $temp_new = file_save_data(''); |
|
889 db_update('file_managed') |
|
890 ->fields(array('status' => 0)) |
|
891 ->condition('fid', $temp_new->fid) |
|
892 ->execute(); |
|
893 $this->assertTrue(file_exists($temp_new->uri), 'New temp file was created correctly.'); |
|
894 |
|
895 // Permanent file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE. |
|
896 $perm_old = file_save_data(''); |
|
897 db_update('file_managed') |
|
898 ->fields(array('timestamp' => 1)) |
|
899 ->condition('fid', $temp_old->fid) |
|
900 ->execute(); |
|
901 $this->assertTrue(file_exists($perm_old->uri), 'Old permanent file was created correctly.'); |
|
902 |
|
903 // Permanent file that is newer than DRUPAL_MAXIMUM_TEMP_FILE_AGE. |
|
904 $perm_new = file_save_data(''); |
|
905 $this->assertTrue(file_exists($perm_new->uri), 'New permanent file was created correctly.'); |
|
906 |
|
907 // Run cron and then ensure that only the old, temp file was deleted. |
|
908 $this->cronRun(); |
|
909 $this->assertFalse(file_exists($temp_old->uri), 'Old temp file was correctly removed.'); |
|
910 $this->assertTrue(file_exists($temp_new->uri), 'New temp file was correctly ignored.'); |
|
911 $this->assertTrue(file_exists($perm_old->uri), 'Old permanent file was correctly ignored.'); |
|
912 $this->assertTrue(file_exists($perm_new->uri), 'New permanent file was correctly ignored.'); |
|
913 } |
|
914 |
|
915 /** |
|
916 * Make sure exceptions thrown on hook_cron() don't affect other modules. |
|
917 */ |
|
918 function testCronExceptions() { |
|
919 variable_del('common_test_cron'); |
|
920 // The common_test module throws an exception. If it isn't caught, the tests |
|
921 // won't finish successfully. |
|
922 // The common_test_cron_helper module sets the 'common_test_cron' variable. |
|
923 $this->cronRun(); |
|
924 $result = variable_get('common_test_cron'); |
|
925 $this->assertEqual($result, 'success', 'Cron correctly handles exceptions thrown during hook_cron() invocations.'); |
|
926 } |
|
927 |
|
928 /** |
|
929 * Tests that hook_flush_caches() is not invoked on every single cron run. |
|
930 * |
|
931 * @see system_cron() |
|
932 */ |
|
933 public function testCronCacheExpiration() { |
|
934 module_enable(array('system_cron_test')); |
|
935 variable_del('system_cron_test_flush_caches'); |
|
936 |
|
937 // Invoke cron the first time: hook_flush_caches() should be called and then |
|
938 // get cached. |
|
939 drupal_cron_run(); |
|
940 $this->assertEqual(variable_get('system_cron_test_flush_caches'), 1, 'hook_flush_caches() was invoked the first time.'); |
|
941 $cache = cache_get('system_cache_tables'); |
|
942 $this->assertEqual(empty($cache), FALSE, 'Cache is filled with cache table data.'); |
|
943 |
|
944 // Run cron again and ensure that hook_flush_caches() is not called. |
|
945 variable_del('system_cron_test_flush_caches'); |
|
946 drupal_cron_run(); |
|
947 $this->assertNull(variable_get('system_cron_test_flush_caches'), 'hook_flush_caches() was not invoked the second time.'); |
|
948 } |
|
949 |
|
950 } |
|
951 |
|
952 /** |
|
953 * Test execution of the cron queue. |
|
954 */ |
|
955 class CronQueueTestCase extends DrupalWebTestCase { |
|
956 /** |
|
957 * Implement getInfo(). |
|
958 */ |
|
959 public static function getInfo() { |
|
960 return array( |
|
961 'name' => 'Cron queue functionality', |
|
962 'description' => 'Tests the cron queue runner.', |
|
963 'group' => 'System' |
|
964 ); |
|
965 } |
|
966 |
|
967 function setUp() { |
|
968 parent::setUp(array('common_test', 'common_test_cron_helper', 'cron_queue_test')); |
|
969 } |
|
970 |
|
971 /** |
|
972 * Tests that exceptions thrown by workers are handled properly. |
|
973 */ |
|
974 function testExceptions() { |
|
975 $queue = DrupalQueue::get('cron_queue_test_exception'); |
|
976 |
|
977 // Enqueue an item for processing. |
|
978 $queue->createItem(array($this->randomName() => $this->randomName())); |
|
979 |
|
980 // Run cron; the worker for this queue should throw an exception and handle |
|
981 // it. |
|
982 $this->cronRun(); |
|
983 |
|
984 // The item should be left in the queue. |
|
985 $this->assertEqual($queue->numberOfItems(), 1, 'Failing item still in the queue after throwing an exception.'); |
|
986 } |
|
987 |
|
988 /** |
|
989 * Tests worker defined as a class method callable. |
|
990 */ |
|
991 function testCallable() { |
|
992 $queue = DrupalQueue::get('cron_queue_test_callback'); |
|
993 |
|
994 // Enqueue an item for processing. |
|
995 $queue->createItem(array($this->randomName() => $this->randomName())); |
|
996 |
|
997 // Run cron; the worker should perform the task and delete the item from the |
|
998 // queue. |
|
999 $this->cronRun(); |
|
1000 |
|
1001 // The queue should be empty. |
|
1002 $this->assertEqual($queue->numberOfItems(), 0); |
|
1003 } |
|
1004 |
|
1005 } |
|
1006 |
|
1007 class AdminMetaTagTestCase extends DrupalWebTestCase { |
|
1008 /** |
|
1009 * Implement getInfo(). |
|
1010 */ |
|
1011 public static function getInfo() { |
|
1012 return array( |
|
1013 'name' => 'Fingerprinting meta tag', |
|
1014 'description' => 'Confirm that the fingerprinting meta tag appears as expected.', |
|
1015 'group' => 'System' |
|
1016 ); |
|
1017 } |
|
1018 |
|
1019 /** |
|
1020 * Verify that the meta tag HTML is generated correctly. |
|
1021 */ |
|
1022 public function testMetaTag() { |
|
1023 list($version, ) = explode('.', VERSION); |
|
1024 $string = '<meta name="Generator" content="Drupal ' . $version . ' (http://drupal.org)" />'; |
|
1025 $this->drupalGet('node'); |
|
1026 $this->assertRaw($string, 'Fingerprinting meta tag generated correctly.', 'System'); |
|
1027 } |
|
1028 } |
|
1029 |
|
1030 /** |
|
1031 * Tests custom access denied functionality. |
|
1032 */ |
|
1033 class AccessDeniedTestCase extends DrupalWebTestCase { |
|
1034 protected $admin_user; |
|
1035 |
|
1036 public static function getInfo() { |
|
1037 return array( |
|
1038 'name' => '403 functionality', |
|
1039 'description' => 'Tests page access denied functionality, including custom 403 pages.', |
|
1040 'group' => 'System' |
|
1041 ); |
|
1042 } |
|
1043 |
|
1044 function setUp() { |
|
1045 parent::setUp(); |
|
1046 |
|
1047 // Create an administrative user. |
|
1048 $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'administer blocks')); |
|
1049 } |
|
1050 |
|
1051 function testAccessDenied() { |
|
1052 $this->drupalGet('admin'); |
|
1053 $this->assertText(t('Access denied'), 'Found the default 403 page'); |
|
1054 $this->assertResponse(403); |
|
1055 |
|
1056 $this->drupalLogin($this->admin_user); |
|
1057 $edit = array( |
|
1058 'title' => $this->randomName(10), |
|
1059 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))), |
|
1060 ); |
|
1061 $node = $this->drupalCreateNode($edit); |
|
1062 |
|
1063 // Use a custom 403 page. |
|
1064 $this->drupalPost('admin/config/system/site-information', array('site_403' => 'node/' . $node->nid), t('Save configuration')); |
|
1065 |
|
1066 $this->drupalLogout(); |
|
1067 $this->drupalGet('admin'); |
|
1068 $this->assertText($node->title, 'Found the custom 403 page'); |
|
1069 |
|
1070 // Logout and check that the user login block is shown on custom 403 pages. |
|
1071 $this->drupalLogout(); |
|
1072 |
|
1073 $this->drupalGet('admin'); |
|
1074 $this->assertText($node->title, 'Found the custom 403 page'); |
|
1075 $this->assertText(t('User login'), 'Blocks are shown on the custom 403 page'); |
|
1076 |
|
1077 // Log back in and remove the custom 403 page. |
|
1078 $this->drupalLogin($this->admin_user); |
|
1079 $this->drupalPost('admin/config/system/site-information', array('site_403' => ''), t('Save configuration')); |
|
1080 |
|
1081 // Logout and check that the user login block is shown on default 403 pages. |
|
1082 $this->drupalLogout(); |
|
1083 |
|
1084 $this->drupalGet('admin'); |
|
1085 $this->assertText(t('Access denied'), 'Found the default 403 page'); |
|
1086 $this->assertResponse(403); |
|
1087 $this->assertText(t('User login'), 'Blocks are shown on the default 403 page'); |
|
1088 |
|
1089 // Log back in, set the custom 403 page to /user and remove the block |
|
1090 $this->drupalLogin($this->admin_user); |
|
1091 variable_set('site_403', 'user'); |
|
1092 $this->drupalPost('admin/structure/block', array('blocks[user_login][region]' => '-1'), t('Save blocks')); |
|
1093 |
|
1094 // Check that we can log in from the 403 page. |
|
1095 $this->drupalLogout(); |
|
1096 $edit = array( |
|
1097 'name' => $this->admin_user->name, |
|
1098 'pass' => $this->admin_user->pass_raw, |
|
1099 ); |
|
1100 $this->drupalPost('admin/config/system/site-information', $edit, t('Log in')); |
|
1101 |
|
1102 // Check that we're still on the same page. |
|
1103 $this->assertText(t('Site information')); |
|
1104 } |
|
1105 } |
|
1106 |
|
1107 class PageNotFoundTestCase extends DrupalWebTestCase { |
|
1108 protected $admin_user; |
|
1109 |
|
1110 /** |
|
1111 * Implement getInfo(). |
|
1112 */ |
|
1113 public static function getInfo() { |
|
1114 return array( |
|
1115 'name' => '404 functionality', |
|
1116 'description' => "Tests page not found functionality, including custom 404 pages.", |
|
1117 'group' => 'System' |
|
1118 ); |
|
1119 } |
|
1120 |
|
1121 /** |
|
1122 * Implement setUp(). |
|
1123 */ |
|
1124 function setUp() { |
|
1125 parent::setUp(); |
|
1126 |
|
1127 // Create an administrative user. |
|
1128 $this->admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
1129 $this->drupalLogin($this->admin_user); |
|
1130 } |
|
1131 |
|
1132 function testPageNotFound() { |
|
1133 $this->drupalGet($this->randomName(10)); |
|
1134 $this->assertText(t('Page not found'), 'Found the default 404 page'); |
|
1135 |
|
1136 $edit = array( |
|
1137 'title' => $this->randomName(10), |
|
1138 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))), |
|
1139 ); |
|
1140 $node = $this->drupalCreateNode($edit); |
|
1141 |
|
1142 // As node IDs must be integers, make sure requests for non-integer IDs |
|
1143 // return a page not found error. |
|
1144 $this->drupalGet('node/invalid'); |
|
1145 $this->assertResponse(404); |
|
1146 |
|
1147 // Use a custom 404 page. |
|
1148 $this->drupalPost('admin/config/system/site-information', array('site_404' => 'node/' . $node->nid), t('Save configuration')); |
|
1149 |
|
1150 $this->drupalGet($this->randomName(10)); |
|
1151 $this->assertText($node->title, 'Found the custom 404 page'); |
|
1152 } |
|
1153 } |
|
1154 |
|
1155 /** |
|
1156 * Tests site maintenance functionality. |
|
1157 */ |
|
1158 class SiteMaintenanceTestCase extends DrupalWebTestCase { |
|
1159 protected $admin_user; |
|
1160 |
|
1161 public static function getInfo() { |
|
1162 return array( |
|
1163 'name' => 'Site maintenance mode functionality', |
|
1164 'description' => 'Test access to site while in maintenance mode.', |
|
1165 'group' => 'System', |
|
1166 ); |
|
1167 } |
|
1168 |
|
1169 function setUp() { |
|
1170 parent::setUp(); |
|
1171 |
|
1172 // Create a user allowed to access site in maintenance mode. |
|
1173 $this->user = $this->drupalCreateUser(array('access site in maintenance mode')); |
|
1174 // Create an administrative user. |
|
1175 $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access site in maintenance mode')); |
|
1176 $this->drupalLogin($this->admin_user); |
|
1177 } |
|
1178 |
|
1179 /** |
|
1180 * Verify site maintenance mode functionality. |
|
1181 */ |
|
1182 function testSiteMaintenance() { |
|
1183 // Turn on maintenance mode. |
|
1184 $edit = array( |
|
1185 'maintenance_mode' => 1, |
|
1186 ); |
|
1187 $this->drupalPost('admin/config/development/maintenance', $edit, t('Save configuration')); |
|
1188 |
|
1189 $admin_message = t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/config/development/maintenance'))); |
|
1190 $user_message = t('Operating in maintenance mode.'); |
|
1191 $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))); |
|
1192 |
|
1193 $this->drupalGet(''); |
|
1194 $this->assertRaw($admin_message, 'Found the site maintenance mode message.'); |
|
1195 |
|
1196 // Logout and verify that offline message is displayed. |
|
1197 $this->drupalLogout(); |
|
1198 $this->drupalGet(''); |
|
1199 $this->assertText($offline_message); |
|
1200 $this->drupalGet('node'); |
|
1201 $this->assertText($offline_message); |
|
1202 $this->drupalGet('user/register'); |
|
1203 $this->assertText($offline_message); |
|
1204 |
|
1205 // Verify that user is able to log in. |
|
1206 $this->drupalGet('user'); |
|
1207 $this->assertNoText($offline_message); |
|
1208 $this->drupalGet('user/login'); |
|
1209 $this->assertNoText($offline_message); |
|
1210 |
|
1211 // Log in user and verify that maintenance mode message is displayed |
|
1212 // directly after login. |
|
1213 $edit = array( |
|
1214 'name' => $this->user->name, |
|
1215 'pass' => $this->user->pass_raw, |
|
1216 ); |
|
1217 $this->drupalPost(NULL, $edit, t('Log in')); |
|
1218 $this->assertText($user_message); |
|
1219 |
|
1220 // Log in administrative user and configure a custom site offline message. |
|
1221 $this->drupalLogout(); |
|
1222 $this->drupalLogin($this->admin_user); |
|
1223 $this->drupalGet('admin/config/development/maintenance'); |
|
1224 $this->assertNoRaw($admin_message, 'Site maintenance mode message not displayed.'); |
|
1225 |
|
1226 $offline_message = 'Sorry, not online.'; |
|
1227 $edit = array( |
|
1228 'maintenance_mode_message' => $offline_message, |
|
1229 ); |
|
1230 $this->drupalPost(NULL, $edit, t('Save configuration')); |
|
1231 |
|
1232 // Logout and verify that custom site offline message is displayed. |
|
1233 $this->drupalLogout(); |
|
1234 $this->drupalGet(''); |
|
1235 $this->assertRaw($offline_message, 'Found the site offline message.'); |
|
1236 |
|
1237 // Verify that custom site offline message is not displayed on user/password. |
|
1238 $this->drupalGet('user/password'); |
|
1239 $this->assertText(t('Username or e-mail address'), 'Anonymous users can access user/password'); |
|
1240 |
|
1241 // Submit password reset form. |
|
1242 $edit = array( |
|
1243 'name' => $this->user->name, |
|
1244 ); |
|
1245 $this->drupalPost('user/password', $edit, t('E-mail new password')); |
|
1246 $mails = $this->drupalGetMails(); |
|
1247 $start = strpos($mails[0]['body'], 'user/reset/'. $this->user->uid); |
|
1248 $path = substr($mails[0]['body'], $start, 66 + strlen($this->user->uid)); |
|
1249 |
|
1250 // Log in with temporary login link. |
|
1251 $this->drupalPost($path, array(), t('Log in')); |
|
1252 $this->assertText($user_message); |
|
1253 } |
|
1254 } |
|
1255 |
|
1256 /** |
|
1257 * Tests generic date and time handling capabilities of Drupal. |
|
1258 */ |
|
1259 class DateTimeFunctionalTest extends DrupalWebTestCase { |
|
1260 public static function getInfo() { |
|
1261 return array( |
|
1262 'name' => 'Date and time', |
|
1263 'description' => 'Configure date and time settings. Test date formatting and time zone handling, including daylight saving time.', |
|
1264 'group' => 'System', |
|
1265 ); |
|
1266 } |
|
1267 |
|
1268 function setUp() { |
|
1269 parent::setUp(array('locale')); |
|
1270 |
|
1271 // Create admin user and log in admin user. |
|
1272 $this->admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
1273 $this->drupalLogin($this->admin_user); |
|
1274 } |
|
1275 |
|
1276 |
|
1277 /** |
|
1278 * Test time zones and DST handling. |
|
1279 */ |
|
1280 function testTimeZoneHandling() { |
|
1281 // Setup date/time settings for Honolulu time. |
|
1282 variable_set('date_default_timezone', 'Pacific/Honolulu'); |
|
1283 variable_set('configurable_timezones', 0); |
|
1284 variable_set('date_format_medium', 'Y-m-d H:i:s O'); |
|
1285 |
|
1286 // Create some nodes with different authored-on dates. |
|
1287 $date1 = '2007-01-31 21:00:00 -1000'; |
|
1288 $date2 = '2007-07-31 21:00:00 -1000'; |
|
1289 $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article')); |
|
1290 $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article')); |
|
1291 |
|
1292 // Confirm date format and time zone. |
|
1293 $this->drupalGet("node/$node1->nid"); |
|
1294 $this->assertText('2007-01-31 21:00:00 -1000', 'Date should be identical, with GMT offset of -10 hours.'); |
|
1295 $this->drupalGet("node/$node2->nid"); |
|
1296 $this->assertText('2007-07-31 21:00:00 -1000', 'Date should be identical, with GMT offset of -10 hours.'); |
|
1297 |
|
1298 // Set time zone to Los Angeles time. |
|
1299 variable_set('date_default_timezone', 'America/Los_Angeles'); |
|
1300 |
|
1301 // Confirm date format and time zone. |
|
1302 $this->drupalGet("node/$node1->nid"); |
|
1303 $this->assertText('2007-01-31 23:00:00 -0800', 'Date should be two hours ahead, with GMT offset of -8 hours.'); |
|
1304 $this->drupalGet("node/$node2->nid"); |
|
1305 $this->assertText('2007-08-01 00:00:00 -0700', 'Date should be three hours ahead, with GMT offset of -7 hours.'); |
|
1306 } |
|
1307 |
|
1308 /** |
|
1309 * Test date type configuration. |
|
1310 */ |
|
1311 function testDateTypeConfiguration() { |
|
1312 // Confirm system date types appear. |
|
1313 $this->drupalGet('admin/config/regional/date-time'); |
|
1314 $this->assertText(t('Medium'), 'System date types appear in date type list.'); |
|
1315 $this->assertNoRaw('href="/admin/config/regional/date-time/types/medium/delete"', 'No delete link appear for system date types.'); |
|
1316 |
|
1317 // Add custom date type. |
|
1318 $this->clickLink(t('Add date type')); |
|
1319 $date_type = strtolower($this->randomName(8)); |
|
1320 $machine_name = 'machine_' . $date_type; |
|
1321 $date_format = 'd.m.Y - H:i'; |
|
1322 $edit = array( |
|
1323 'date_type' => $date_type, |
|
1324 'machine_name' => $machine_name, |
|
1325 'date_format' => $date_format, |
|
1326 ); |
|
1327 $this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type')); |
|
1328 $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time', array('absolute' => TRUE)), 'Correct page redirection.'); |
|
1329 $this->assertText(t('New date type added successfully.'), 'Date type added confirmation message appears.'); |
|
1330 $this->assertText($date_type, 'Custom date type appears in the date type list.'); |
|
1331 $this->assertText(t('delete'), 'Delete link for custom date type appears.'); |
|
1332 |
|
1333 // Delete custom date type. |
|
1334 $this->clickLink(t('delete')); |
|
1335 $this->drupalPost('admin/config/regional/date-time/types/' . $machine_name . '/delete', array(), t('Remove')); |
|
1336 $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time', array('absolute' => TRUE)), 'Correct page redirection.'); |
|
1337 $this->assertText(t('Removed date type ' . $date_type), 'Custom date type removed.'); |
|
1338 } |
|
1339 |
|
1340 /** |
|
1341 * Test date format configuration. |
|
1342 */ |
|
1343 function testDateFormatConfiguration() { |
|
1344 // Confirm 'no custom date formats available' message appears. |
|
1345 $this->drupalGet('admin/config/regional/date-time/formats'); |
|
1346 $this->assertText(t('No custom date formats available.'), 'No custom date formats message appears.'); |
|
1347 |
|
1348 // Add custom date format. |
|
1349 $this->clickLink(t('Add format')); |
|
1350 $edit = array( |
|
1351 'date_format' => 'Y', |
|
1352 ); |
|
1353 $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format')); |
|
1354 $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.'); |
|
1355 $this->assertNoText(t('No custom date formats available.'), 'No custom date formats message does not appear.'); |
|
1356 $this->assertText(t('Custom date format added.'), 'Custom date format added.'); |
|
1357 |
|
1358 // Ensure custom date format appears in date type configuration options. |
|
1359 $this->drupalGet('admin/config/regional/date-time'); |
|
1360 $this->assertRaw('<option value="Y">', 'Custom date format appears in options.'); |
|
1361 |
|
1362 // Edit custom date format. |
|
1363 $this->drupalGet('admin/config/regional/date-time/formats'); |
|
1364 $this->clickLink(t('edit')); |
|
1365 $edit = array( |
|
1366 'date_format' => 'Y m', |
|
1367 ); |
|
1368 $this->drupalPost($this->getUrl(), $edit, t('Save format')); |
|
1369 $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.'); |
|
1370 $this->assertText(t('Custom date format updated.'), 'Custom date format successfully updated.'); |
|
1371 |
|
1372 // Check that ajax callback is protected by CSRF token. |
|
1373 $this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('format' => 'Y m d'))); |
|
1374 $this->assertResponse(403, 'Access denied with no token'); |
|
1375 $this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('token' => 'invalid', 'format' => 'Y m d'))); |
|
1376 $this->assertResponse(403, 'Access denied with invalid token'); |
|
1377 $this->drupalGet('admin/config/regional/date-time/formats'); |
|
1378 $this->clickLink(t('edit')); |
|
1379 $settings = $this->drupalGetSettings(); |
|
1380 $lookup_url = $settings['dateTime']['date-format']['lookup']; |
|
1381 preg_match('/token=([^&]+)/', $lookup_url, $matches); |
|
1382 $this->assertFalse(empty($matches[1]), 'Found token value'); |
|
1383 $this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('token' => $matches[1], 'format' => 'Y m d'))); |
|
1384 $this->assertResponse(200, 'Access allowed with valid token'); |
|
1385 $this->assertText(format_date(time(), 'custom', 'Y m d')); |
|
1386 |
|
1387 // Delete custom date format. |
|
1388 $this->drupalGet('admin/config/regional/date-time/formats'); |
|
1389 $this->clickLink(t('delete')); |
|
1390 $this->drupalPost($this->getUrl(), array(), t('Remove')); |
|
1391 $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.'); |
|
1392 $this->assertText(t('Removed date format'), 'Custom date format removed successfully.'); |
|
1393 } |
|
1394 |
|
1395 /** |
|
1396 * Test if the date formats are stored properly. |
|
1397 */ |
|
1398 function testDateFormatStorage() { |
|
1399 $date_format = array( |
|
1400 'type' => 'short', |
|
1401 'format' => 'dmYHis', |
|
1402 'locked' => 0, |
|
1403 'is_new' => 1, |
|
1404 ); |
|
1405 system_date_format_save($date_format); |
|
1406 |
|
1407 $format = db_select('date_formats', 'df') |
|
1408 ->fields('df', array('format')) |
|
1409 ->condition('type', 'short') |
|
1410 ->condition('format', 'dmYHis') |
|
1411 ->execute() |
|
1412 ->fetchField(); |
|
1413 $this->verbose($format); |
|
1414 $this->assertEqual('dmYHis', $format, 'Unlocalized date format resides in general table.'); |
|
1415 |
|
1416 $format = db_select('date_format_locale', 'dfl') |
|
1417 ->fields('dfl', array('format')) |
|
1418 ->condition('type', 'short') |
|
1419 ->condition('format', 'dmYHis') |
|
1420 ->execute() |
|
1421 ->fetchField(); |
|
1422 $this->assertFalse($format, 'Unlocalized date format resides not in localized table.'); |
|
1423 |
|
1424 // Enable German language |
|
1425 locale_add_language('de', NULL, NULL, LANGUAGE_LTR, '', '', TRUE, 'en'); |
|
1426 |
|
1427 $date_format = array( |
|
1428 'type' => 'short', |
|
1429 'format' => 'YMDHis', |
|
1430 'locales' => array('de', 'tr'), |
|
1431 'locked' => 0, |
|
1432 'is_new' => 1, |
|
1433 ); |
|
1434 system_date_format_save($date_format); |
|
1435 |
|
1436 $format = db_select('date_format_locale', 'dfl') |
|
1437 ->fields('dfl', array('format')) |
|
1438 ->condition('type', 'short') |
|
1439 ->condition('format', 'YMDHis') |
|
1440 ->condition('language', 'de') |
|
1441 ->execute() |
|
1442 ->fetchField(); |
|
1443 $this->assertEqual('YMDHis', $format, 'Localized date format resides in localized table.'); |
|
1444 |
|
1445 $format = db_select('date_formats', 'df') |
|
1446 ->fields('df', array('format')) |
|
1447 ->condition('type', 'short') |
|
1448 ->condition('format', 'YMDHis') |
|
1449 ->execute() |
|
1450 ->fetchField(); |
|
1451 $this->assertEqual('YMDHis', $format, 'Localized date format resides in general table too.'); |
|
1452 |
|
1453 $format = db_select('date_format_locale', 'dfl') |
|
1454 ->fields('dfl', array('format')) |
|
1455 ->condition('type', 'short') |
|
1456 ->condition('format', 'YMDHis') |
|
1457 ->condition('language', 'tr') |
|
1458 ->execute() |
|
1459 ->fetchColumn(); |
|
1460 $this->assertFalse($format, 'Localized date format for disabled language is ignored.'); |
|
1461 } |
|
1462 } |
|
1463 |
|
1464 /** |
|
1465 * Tests date format configuration. |
|
1466 */ |
|
1467 class DateFormatTestCase extends DrupalWebTestCase { |
|
1468 public static function getInfo() { |
|
1469 return array( |
|
1470 'name' => 'Date format', |
|
1471 'description' => 'Test date format configuration and defaults.', |
|
1472 'group' => 'System', |
|
1473 ); |
|
1474 } |
|
1475 |
|
1476 function setUp() { |
|
1477 parent::setUp(); |
|
1478 |
|
1479 // Create admin user and log in admin user. |
|
1480 $this->admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
1481 $this->drupalLogin($this->admin_user); |
|
1482 } |
|
1483 |
|
1484 /** |
|
1485 * Test the default date type formats are consistent. |
|
1486 */ |
|
1487 function testDefaultDateFormats() { |
|
1488 // These are the default format values from format_date(). |
|
1489 $default_formats = array( |
|
1490 'short' => 'm/d/Y - H:i', |
|
1491 'medium' => 'D, m/d/Y - H:i', |
|
1492 'long' => 'l, F j, Y - H:i', |
|
1493 ); |
|
1494 |
|
1495 // Clear the date format variables. |
|
1496 variable_del('date_format_short'); |
|
1497 variable_del('date_format_medium'); |
|
1498 variable_del('date_format_long'); |
|
1499 |
|
1500 $this->drupalGet('admin/config/regional/date-time'); |
|
1501 |
|
1502 foreach ($default_formats as $format_name => $format_value) { |
|
1503 $id = 'edit-date-format-' . $format_name; |
|
1504 // Check that the configuration fields match the default format. |
|
1505 $this->assertOptionSelected( |
|
1506 $id, |
|
1507 $format_value, |
|
1508 format_string('The @type format type matches the expected format @format.', |
|
1509 array( |
|
1510 '@type' => $format_name, |
|
1511 '@format' => $format_value, |
|
1512 ) |
|
1513 )); |
|
1514 } |
|
1515 } |
|
1516 } |
|
1517 |
|
1518 class PageTitleFiltering extends DrupalWebTestCase { |
|
1519 protected $content_user; |
|
1520 protected $saved_title; |
|
1521 |
|
1522 /** |
|
1523 * Implement getInfo(). |
|
1524 */ |
|
1525 public static function getInfo() { |
|
1526 return array( |
|
1527 'name' => 'HTML in page titles', |
|
1528 'description' => 'Tests correct handling or conversion by drupal_set_title() and drupal_get_title() and checks the correct escaping of site name and slogan.', |
|
1529 'group' => 'System' |
|
1530 ); |
|
1531 } |
|
1532 |
|
1533 /** |
|
1534 * Implement setUp(). |
|
1535 */ |
|
1536 function setUp() { |
|
1537 parent::setUp(); |
|
1538 |
|
1539 $this->content_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer themes', 'administer site configuration')); |
|
1540 $this->drupalLogin($this->content_user); |
|
1541 $this->saved_title = drupal_get_title(); |
|
1542 } |
|
1543 |
|
1544 /** |
|
1545 * Reset page title. |
|
1546 */ |
|
1547 function tearDown() { |
|
1548 // Restore the page title. |
|
1549 drupal_set_title($this->saved_title, PASS_THROUGH); |
|
1550 |
|
1551 parent::tearDown(); |
|
1552 } |
|
1553 |
|
1554 /** |
|
1555 * Tests the handling of HTML by drupal_set_title() and drupal_get_title() |
|
1556 */ |
|
1557 function testTitleTags() { |
|
1558 $title = "string with <em>HTML</em>"; |
|
1559 // drupal_set_title's $filter is CHECK_PLAIN by default, so the title should be |
|
1560 // returned with check_plain(). |
|
1561 drupal_set_title($title, CHECK_PLAIN); |
|
1562 $this->assertTrue(strpos(drupal_get_title(), '<em>') === FALSE, 'Tags in title converted to entities when $output is CHECK_PLAIN.'); |
|
1563 // drupal_set_title's $filter is passed as PASS_THROUGH, so the title should be |
|
1564 // returned with HTML. |
|
1565 drupal_set_title($title, PASS_THROUGH); |
|
1566 $this->assertTrue(strpos(drupal_get_title(), '<em>') !== FALSE, 'Tags in title are not converted to entities when $output is PASS_THROUGH.'); |
|
1567 // Generate node content. |
|
1568 $langcode = LANGUAGE_NONE; |
|
1569 $edit = array( |
|
1570 "title" => '!SimpleTest! ' . $title . $this->randomName(20), |
|
1571 "body[$langcode][0][value]" => '!SimpleTest! test body' . $this->randomName(200), |
|
1572 ); |
|
1573 // Create the node with HTML in the title. |
|
1574 $this->drupalPost('node/add/page', $edit, t('Save')); |
|
1575 |
|
1576 $node = $this->drupalGetNodeByTitle($edit["title"]); |
|
1577 $this->assertNotNull($node, 'Node created and found in database'); |
|
1578 $this->drupalGet("node/" . $node->nid); |
|
1579 $this->assertText(check_plain($edit["title"]), 'Check to make sure tags in the node title are converted.'); |
|
1580 } |
|
1581 /** |
|
1582 * Test if the title of the site is XSS proof. |
|
1583 */ |
|
1584 function testTitleXSS() { |
|
1585 // Set some title with JavaScript and HTML chars to escape. |
|
1586 $title = '</title><script type="text/javascript">alert("Title XSS!");</script> & < > " \' '; |
|
1587 $title_filtered = check_plain($title); |
|
1588 |
|
1589 $slogan = '<script type="text/javascript">alert("Slogan XSS!");</script>'; |
|
1590 $slogan_filtered = filter_xss_admin($slogan); |
|
1591 |
|
1592 // Activate needed appearance settings. |
|
1593 $edit = array( |
|
1594 'toggle_name' => TRUE, |
|
1595 'toggle_slogan' => TRUE, |
|
1596 'toggle_main_menu' => TRUE, |
|
1597 'toggle_secondary_menu' => TRUE, |
|
1598 ); |
|
1599 $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); |
|
1600 |
|
1601 // Set title and slogan. |
|
1602 $edit = array( |
|
1603 'site_name' => $title, |
|
1604 'site_slogan' => $slogan, |
|
1605 ); |
|
1606 $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration')); |
|
1607 |
|
1608 // Load frontpage. |
|
1609 $this->drupalGet(''); |
|
1610 |
|
1611 // Test the title. |
|
1612 $this->assertNoRaw($title, 'Check for the unfiltered version of the title.'); |
|
1613 // Adding </title> so we do not test the escaped version from drupal_set_title(). |
|
1614 $this->assertRaw($title_filtered . '</title>', 'Check for the filtered version of the title.'); |
|
1615 |
|
1616 // Test the slogan. |
|
1617 $this->assertNoRaw($slogan, 'Check for the unfiltered version of the slogan.'); |
|
1618 $this->assertRaw($slogan_filtered, 'Check for the filtered version of the slogan.'); |
|
1619 } |
|
1620 } |
|
1621 |
|
1622 /** |
|
1623 * Test front page functionality and administration. |
|
1624 */ |
|
1625 class FrontPageTestCase extends DrupalWebTestCase { |
|
1626 |
|
1627 public static function getInfo() { |
|
1628 return array( |
|
1629 'name' => 'Front page', |
|
1630 'description' => 'Tests front page functionality and administration.', |
|
1631 'group' => 'System', |
|
1632 ); |
|
1633 } |
|
1634 |
|
1635 function setUp() { |
|
1636 parent::setUp('system_test'); |
|
1637 |
|
1638 // Create admin user, log in admin user, and create one node. |
|
1639 $this->admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration')); |
|
1640 $this->drupalLogin($this->admin_user); |
|
1641 $this->node_path = "node/" . $this->drupalCreateNode(array('promote' => 1))->nid; |
|
1642 |
|
1643 // Enable front page logging in system_test.module. |
|
1644 variable_set('front_page_output', 1); |
|
1645 } |
|
1646 |
|
1647 /** |
|
1648 * Test front page functionality. |
|
1649 */ |
|
1650 function testDrupalIsFrontPage() { |
|
1651 $this->drupalGet(''); |
|
1652 $this->assertText(t('On front page.'), 'Path is the front page.'); |
|
1653 $this->drupalGet('node'); |
|
1654 $this->assertText(t('On front page.'), 'Path is the front page.'); |
|
1655 $this->drupalGet($this->node_path); |
|
1656 $this->assertNoText(t('On front page.'), 'Path is not the front page.'); |
|
1657 |
|
1658 // Change the front page to an invalid path. |
|
1659 $edit = array('site_frontpage' => 'kittens'); |
|
1660 $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration')); |
|
1661 $this->assertText(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $edit['site_frontpage']))); |
|
1662 |
|
1663 // Change the front page to a valid path. |
|
1664 $edit['site_frontpage'] = $this->node_path; |
|
1665 $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration')); |
|
1666 $this->assertText(t('The configuration options have been saved.'), 'The front page path has been saved.'); |
|
1667 |
|
1668 $this->drupalGet(''); |
|
1669 $this->assertText(t('On front page.'), 'Path is the front page.'); |
|
1670 $this->drupalGet('node'); |
|
1671 $this->assertNoText(t('On front page.'), 'Path is not the front page.'); |
|
1672 $this->drupalGet($this->node_path); |
|
1673 $this->assertText(t('On front page.'), 'Path is the front page.'); |
|
1674 } |
|
1675 } |
|
1676 |
|
1677 class SystemBlockTestCase extends DrupalWebTestCase { |
|
1678 protected $profile = 'testing'; |
|
1679 |
|
1680 public static function getInfo() { |
|
1681 return array( |
|
1682 'name' => 'Block functionality', |
|
1683 'description' => 'Configure and move powered-by block.', |
|
1684 'group' => 'System', |
|
1685 ); |
|
1686 } |
|
1687 |
|
1688 function setUp() { |
|
1689 parent::setUp('block'); |
|
1690 |
|
1691 // Create and login user |
|
1692 $admin_user = $this->drupalCreateUser(array('administer blocks', 'access administration pages')); |
|
1693 $this->drupalLogin($admin_user); |
|
1694 } |
|
1695 |
|
1696 /** |
|
1697 * Test displaying and hiding the powered-by and help blocks. |
|
1698 */ |
|
1699 function testSystemBlocks() { |
|
1700 // Set block title and some settings to confirm that the interface is available. |
|
1701 $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', array('title' => $this->randomName(8)), t('Save block')); |
|
1702 $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.')); |
|
1703 |
|
1704 // Set the powered-by block to the footer region. |
|
1705 $edit = array(); |
|
1706 $edit['blocks[system_powered-by][region]'] = 'footer'; |
|
1707 $edit['blocks[system_main][region]'] = 'content'; |
|
1708 $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); |
|
1709 $this->assertText(t('The block settings have been updated.'), t('Block successfully moved to footer region.')); |
|
1710 |
|
1711 // Confirm that the block is being displayed. |
|
1712 $this->drupalGet('node'); |
|
1713 $this->assertRaw('id="block-system-powered-by"', t('Block successfully being displayed on the page.')); |
|
1714 |
|
1715 // Set the block to the disabled region. |
|
1716 $edit = array(); |
|
1717 $edit['blocks[system_powered-by][region]'] = '-1'; |
|
1718 $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); |
|
1719 |
|
1720 // Confirm that the block is hidden. |
|
1721 $this->assertNoRaw('id="block-system-powered-by"', t('Block no longer appears on page.')); |
|
1722 |
|
1723 // For convenience of developers, set the block to its default settings. |
|
1724 $edit = array(); |
|
1725 $edit['blocks[system_powered-by][region]'] = 'footer'; |
|
1726 $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); |
|
1727 $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', array('title' => ''), t('Save block')); |
|
1728 |
|
1729 // Set the help block to the help region. |
|
1730 $edit = array(); |
|
1731 $edit['blocks[system_help][region]'] = 'help'; |
|
1732 $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); |
|
1733 |
|
1734 // Test displaying the help block with block caching enabled. |
|
1735 variable_set('block_cache', TRUE); |
|
1736 $this->drupalGet('admin/structure/block/add'); |
|
1737 $this->assertRaw(t('Use this page to create a new custom block.')); |
|
1738 $this->drupalGet('admin/index'); |
|
1739 $this->assertRaw(t('This page shows you all available administration tasks for each module.')); |
|
1740 } |
|
1741 } |
|
1742 |
|
1743 /** |
|
1744 * Test main content rendering fallback provided by system module. |
|
1745 */ |
|
1746 class SystemMainContentFallback extends DrupalWebTestCase { |
|
1747 protected $admin_user; |
|
1748 protected $web_user; |
|
1749 |
|
1750 public static function getInfo() { |
|
1751 return array( |
|
1752 'name' => 'Main content rendering fallback', |
|
1753 'description' => ' Test system module main content rendering fallback.', |
|
1754 'group' => 'System', |
|
1755 ); |
|
1756 } |
|
1757 |
|
1758 function setUp() { |
|
1759 parent::setUp('system_test'); |
|
1760 |
|
1761 // Create and login admin user. |
|
1762 $this->admin_user = $this->drupalCreateUser(array( |
|
1763 'access administration pages', |
|
1764 'administer site configuration', |
|
1765 'administer modules', |
|
1766 'administer blocks', |
|
1767 'administer nodes', |
|
1768 )); |
|
1769 $this->drupalLogin($this->admin_user); |
|
1770 |
|
1771 // Create a web user. |
|
1772 $this->web_user = $this->drupalCreateUser(array('access user profiles', 'access content')); |
|
1773 } |
|
1774 |
|
1775 /** |
|
1776 * Test availability of main content. |
|
1777 */ |
|
1778 function testMainContentFallback() { |
|
1779 $edit = array(); |
|
1780 // Disable the dashboard module, which depends on the block module. |
|
1781 $edit['modules[Core][dashboard][enable]'] = FALSE; |
|
1782 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
1783 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
1784 // Disable the block module. |
|
1785 $edit['modules[Core][block][enable]'] = FALSE; |
|
1786 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
1787 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
1788 module_list(TRUE); |
|
1789 $this->assertFalse(module_exists('block'), 'Block module disabled.'); |
|
1790 |
|
1791 // At this point, no region is filled and fallback should be triggered. |
|
1792 $this->drupalGet('admin/config/system/site-information'); |
|
1793 $this->assertField('site_name', 'Admin interface still available.'); |
|
1794 |
|
1795 // Fallback should not trigger when another module is handling content. |
|
1796 $this->drupalGet('system-test/main-content-handling'); |
|
1797 $this->assertRaw('id="system-test-content"', 'Content handled by another module'); |
|
1798 $this->assertText(t('Content to test main content fallback'), 'Main content still displayed.'); |
|
1799 |
|
1800 // Fallback should trigger when another module |
|
1801 // indicates that it is not handling the content. |
|
1802 $this->drupalGet('system-test/main-content-fallback'); |
|
1803 $this->assertText(t('Content to test main content fallback'), 'Main content fallback properly triggers.'); |
|
1804 |
|
1805 // Fallback should not trigger when another module is handling content. |
|
1806 // Note that this test ensures that no duplicate |
|
1807 // content gets created by the fallback. |
|
1808 $this->drupalGet('system-test/main-content-duplication'); |
|
1809 $this->assertNoText(t('Content to test main content fallback'), 'Main content not duplicated.'); |
|
1810 |
|
1811 // Request a user* page and see if it is displayed. |
|
1812 $this->drupalLogin($this->web_user); |
|
1813 $this->drupalGet('user/' . $this->web_user->uid . '/edit'); |
|
1814 $this->assertField('mail', 'User interface still available.'); |
|
1815 |
|
1816 // Enable the block module again. |
|
1817 $this->drupalLogin($this->admin_user); |
|
1818 $edit = array(); |
|
1819 $edit['modules[Core][block][enable]'] = 'block'; |
|
1820 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
1821 $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.'); |
|
1822 module_list(TRUE); |
|
1823 $this->assertTrue(module_exists('block'), 'Block module re-enabled.'); |
|
1824 } |
|
1825 } |
|
1826 |
|
1827 /** |
|
1828 * Tests for the theme interface functionality. |
|
1829 */ |
|
1830 class SystemThemeFunctionalTest extends DrupalWebTestCase { |
|
1831 public static function getInfo() { |
|
1832 return array( |
|
1833 'name' => 'Theme interface functionality', |
|
1834 'description' => 'Tests the theme interface functionality by enabling and switching themes, and using an administration theme.', |
|
1835 'group' => 'System', |
|
1836 ); |
|
1837 } |
|
1838 |
|
1839 function setUp() { |
|
1840 parent::setUp(); |
|
1841 |
|
1842 $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer themes', 'bypass node access', 'administer blocks')); |
|
1843 $this->drupalLogin($this->admin_user); |
|
1844 $this->node = $this->drupalCreateNode(); |
|
1845 } |
|
1846 |
|
1847 /** |
|
1848 * Test the theme settings form. |
|
1849 */ |
|
1850 function testThemeSettings() { |
|
1851 // Specify a filesystem path to be used for the logo. |
|
1852 $file = current($this->drupalGetTestFiles('image')); |
|
1853 $file_relative = strtr($file->uri, array('public:/' => variable_get('file_public_path', conf_path() . '/files'))); |
|
1854 $default_theme_path = 'themes/stark'; |
|
1855 |
|
1856 $supported_paths = array( |
|
1857 // Raw stream wrapper URI. |
|
1858 $file->uri => array( |
|
1859 'form' => file_uri_target($file->uri), |
|
1860 'src' => file_create_url($file->uri), |
|
1861 ), |
|
1862 // Relative path within the public filesystem. |
|
1863 file_uri_target($file->uri) => array( |
|
1864 'form' => file_uri_target($file->uri), |
|
1865 'src' => file_create_url($file->uri), |
|
1866 ), |
|
1867 // Relative path to a public file. |
|
1868 $file_relative => array( |
|
1869 'form' => $file_relative, |
|
1870 'src' => file_create_url($file->uri), |
|
1871 ), |
|
1872 // Relative path to an arbitrary file. |
|
1873 'misc/druplicon.png' => array( |
|
1874 'form' => 'misc/druplicon.png', |
|
1875 'src' => $GLOBALS['base_url'] . '/' . 'misc/druplicon.png', |
|
1876 ), |
|
1877 // Relative path to a file in a theme. |
|
1878 $default_theme_path . '/logo.png' => array( |
|
1879 'form' => $default_theme_path . '/logo.png', |
|
1880 'src' => $GLOBALS['base_url'] . '/' . $default_theme_path . '/logo.png', |
|
1881 ), |
|
1882 ); |
|
1883 foreach ($supported_paths as $input => $expected) { |
|
1884 $edit = array( |
|
1885 'default_logo' => FALSE, |
|
1886 'logo_path' => $input, |
|
1887 ); |
|
1888 $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); |
|
1889 $this->assertNoText('The custom logo path is invalid.'); |
|
1890 $this->assertFieldByName('logo_path', $expected['form']); |
|
1891 |
|
1892 // Verify the actual 'src' attribute of the logo being output. |
|
1893 $this->drupalGet(''); |
|
1894 $elements = $this->xpath('//*[@id=:id]/img', array(':id' => 'logo')); |
|
1895 $this->assertEqual((string) $elements[0]['src'], $expected['src']); |
|
1896 } |
|
1897 |
|
1898 $unsupported_paths = array( |
|
1899 // Stream wrapper URI to non-existing file. |
|
1900 'public://whatever.png', |
|
1901 'private://whatever.png', |
|
1902 'temporary://whatever.png', |
|
1903 // Bogus stream wrapper URIs. |
|
1904 'public:/whatever.png', |
|
1905 '://whatever.png', |
|
1906 ':whatever.png', |
|
1907 'public://', |
|
1908 // Relative path within the public filesystem to non-existing file. |
|
1909 'whatever.png', |
|
1910 // Relative path to non-existing file in public filesystem. |
|
1911 variable_get('file_public_path', conf_path() . '/files') . '/whatever.png', |
|
1912 // Semi-absolute path to non-existing file in public filesystem. |
|
1913 '/' . variable_get('file_public_path', conf_path() . '/files') . '/whatever.png', |
|
1914 // Relative path to arbitrary non-existing file. |
|
1915 'misc/whatever.png', |
|
1916 // Semi-absolute path to arbitrary non-existing file. |
|
1917 '/misc/whatever.png', |
|
1918 // Absolute paths to any local file (even if it exists). |
|
1919 drupal_realpath($file->uri), |
|
1920 ); |
|
1921 $this->drupalGet('admin/appearance/settings'); |
|
1922 foreach ($unsupported_paths as $path) { |
|
1923 $edit = array( |
|
1924 'default_logo' => FALSE, |
|
1925 'logo_path' => $path, |
|
1926 ); |
|
1927 $this->drupalPost(NULL, $edit, t('Save configuration')); |
|
1928 $this->assertText('The custom logo path is invalid.'); |
|
1929 } |
|
1930 |
|
1931 // Upload a file to use for the logo. |
|
1932 $edit = array( |
|
1933 'default_logo' => FALSE, |
|
1934 'logo_path' => '', |
|
1935 'files[logo_upload]' => drupal_realpath($file->uri), |
|
1936 ); |
|
1937 $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); |
|
1938 |
|
1939 $fields = $this->xpath($this->constructFieldXpath('name', 'logo_path')); |
|
1940 $uploaded_filename = 'public://' . $fields[0]['value']; |
|
1941 |
|
1942 $this->drupalGet(''); |
|
1943 $elements = $this->xpath('//*[@id=:id]/img', array(':id' => 'logo')); |
|
1944 $this->assertEqual($elements[0]['src'], file_create_url($uploaded_filename)); |
|
1945 } |
|
1946 |
|
1947 /** |
|
1948 * Test the administration theme functionality. |
|
1949 */ |
|
1950 function testAdministrationTheme() { |
|
1951 theme_enable(array('stark')); |
|
1952 variable_set('theme_default', 'stark'); |
|
1953 // Enable an administration theme and show it on the node admin pages. |
|
1954 $edit = array( |
|
1955 'admin_theme' => 'seven', |
|
1956 'node_admin_theme' => TRUE, |
|
1957 ); |
|
1958 $this->drupalPost('admin/appearance', $edit, t('Save configuration')); |
|
1959 |
|
1960 $this->drupalGet('admin/config'); |
|
1961 $this->assertRaw('themes/seven', 'Administration theme used on an administration page.'); |
|
1962 |
|
1963 $this->drupalGet('node/' . $this->node->nid); |
|
1964 $this->assertRaw('themes/stark', 'Site default theme used on node page.'); |
|
1965 |
|
1966 $this->drupalGet('node/add'); |
|
1967 $this->assertRaw('themes/seven', 'Administration theme used on the add content page.'); |
|
1968 |
|
1969 $this->drupalGet('node/' . $this->node->nid . '/edit'); |
|
1970 $this->assertRaw('themes/seven', 'Administration theme used on the edit content page.'); |
|
1971 |
|
1972 // Disable the admin theme on the node admin pages. |
|
1973 $edit = array( |
|
1974 'node_admin_theme' => FALSE, |
|
1975 ); |
|
1976 $this->drupalPost('admin/appearance', $edit, t('Save configuration')); |
|
1977 |
|
1978 $this->drupalGet('admin/config'); |
|
1979 $this->assertRaw('themes/seven', 'Administration theme used on an administration page.'); |
|
1980 |
|
1981 $this->drupalGet('node/add'); |
|
1982 $this->assertRaw('themes/stark', 'Site default theme used on the add content page.'); |
|
1983 |
|
1984 // Reset to the default theme settings. |
|
1985 variable_set('theme_default', 'bartik'); |
|
1986 $edit = array( |
|
1987 'admin_theme' => '0', |
|
1988 'node_admin_theme' => FALSE, |
|
1989 ); |
|
1990 $this->drupalPost('admin/appearance', $edit, t('Save configuration')); |
|
1991 |
|
1992 $this->drupalGet('admin'); |
|
1993 $this->assertRaw('themes/bartik', 'Site default theme used on administration page.'); |
|
1994 |
|
1995 $this->drupalGet('node/add'); |
|
1996 $this->assertRaw('themes/bartik', 'Site default theme used on the add content page.'); |
|
1997 } |
|
1998 |
|
1999 /** |
|
2000 * Test switching the default theme. |
|
2001 */ |
|
2002 function testSwitchDefaultTheme() { |
|
2003 // Enable "stark" and set it as the default theme. |
|
2004 theme_enable(array('stark')); |
|
2005 $this->drupalGet('admin/appearance'); |
|
2006 $this->clickLink(t('Set default'), 1); |
|
2007 $this->assertTrue(variable_get('theme_default', '') == 'stark', 'Site default theme switched successfully.'); |
|
2008 |
|
2009 // Test the default theme on the secondary links (blocks admin page). |
|
2010 $this->drupalGet('admin/structure/block'); |
|
2011 $this->assertText('Stark(' . t('active tab') . ')', 'Default local task on blocks admin page is the default theme.'); |
|
2012 // Switch back to Bartik and test again to test that the menu cache is cleared. |
|
2013 $this->drupalGet('admin/appearance'); |
|
2014 $this->clickLink(t('Set default'), 0); |
|
2015 $this->drupalGet('admin/structure/block'); |
|
2016 $this->assertText('Bartik(' . t('active tab') . ')', 'Default local task on blocks admin page has changed.'); |
|
2017 } |
|
2018 } |
|
2019 |
|
2020 |
|
2021 /** |
|
2022 * Test the basic queue functionality. |
|
2023 */ |
|
2024 class QueueTestCase extends DrupalWebTestCase { |
|
2025 public static function getInfo() { |
|
2026 return array( |
|
2027 'name' => 'Queue functionality', |
|
2028 'description' => 'Queues and dequeues a set of items to check the basic queue functionality.', |
|
2029 'group' => 'System', |
|
2030 ); |
|
2031 } |
|
2032 |
|
2033 /** |
|
2034 * Queues and dequeues a set of items to check the basic queue functionality. |
|
2035 */ |
|
2036 function testQueue() { |
|
2037 // Create two queues. |
|
2038 $queue1 = DrupalQueue::get($this->randomName()); |
|
2039 $queue1->createQueue(); |
|
2040 $queue2 = DrupalQueue::get($this->randomName()); |
|
2041 $queue2->createQueue(); |
|
2042 |
|
2043 // Create four items. |
|
2044 $data = array(); |
|
2045 for ($i = 0; $i < 4; $i++) { |
|
2046 $data[] = array($this->randomName() => $this->randomName()); |
|
2047 } |
|
2048 |
|
2049 // Queue items 1 and 2 in the queue1. |
|
2050 $queue1->createItem($data[0]); |
|
2051 $queue1->createItem($data[1]); |
|
2052 |
|
2053 // Retrieve two items from queue1. |
|
2054 $items = array(); |
|
2055 $new_items = array(); |
|
2056 |
|
2057 $items[] = $item = $queue1->claimItem(); |
|
2058 $new_items[] = $item->data; |
|
2059 |
|
2060 $items[] = $item = $queue1->claimItem(); |
|
2061 $new_items[] = $item->data; |
|
2062 |
|
2063 // First two dequeued items should match the first two items we queued. |
|
2064 $this->assertEqual($this->queueScore($data, $new_items), 2, 'Two items matched'); |
|
2065 |
|
2066 // Add two more items. |
|
2067 $queue1->createItem($data[2]); |
|
2068 $queue1->createItem($data[3]); |
|
2069 |
|
2070 $this->assertTrue($queue1->numberOfItems(), 'Queue 1 is not empty after adding items.'); |
|
2071 $this->assertFalse($queue2->numberOfItems(), 'Queue 2 is empty while Queue 1 has items'); |
|
2072 |
|
2073 $items[] = $item = $queue1->claimItem(); |
|
2074 $new_items[] = $item->data; |
|
2075 |
|
2076 $items[] = $item = $queue1->claimItem(); |
|
2077 $new_items[] = $item->data; |
|
2078 |
|
2079 // All dequeued items should match the items we queued exactly once, |
|
2080 // therefore the score must be exactly 4. |
|
2081 $this->assertEqual($this->queueScore($data, $new_items), 4, 'Four items matched'); |
|
2082 |
|
2083 // There should be no duplicate items. |
|
2084 $this->assertEqual($this->queueScore($new_items, $new_items), 4, 'Four items matched'); |
|
2085 |
|
2086 // Delete all items from queue1. |
|
2087 foreach ($items as $item) { |
|
2088 $queue1->deleteItem($item); |
|
2089 } |
|
2090 |
|
2091 // Check that both queues are empty. |
|
2092 $this->assertFalse($queue1->numberOfItems(), 'Queue 1 is empty'); |
|
2093 $this->assertFalse($queue2->numberOfItems(), 'Queue 2 is empty'); |
|
2094 } |
|
2095 |
|
2096 /** |
|
2097 * This function returns the number of equal items in two arrays. |
|
2098 */ |
|
2099 function queueScore($items, $new_items) { |
|
2100 $score = 0; |
|
2101 foreach ($items as $item) { |
|
2102 foreach ($new_items as $new_item) { |
|
2103 if ($item === $new_item) { |
|
2104 $score++; |
|
2105 } |
|
2106 } |
|
2107 } |
|
2108 return $score; |
|
2109 } |
|
2110 } |
|
2111 |
|
2112 /** |
|
2113 * Test token replacement in strings. |
|
2114 */ |
|
2115 class TokenReplaceTestCase extends DrupalWebTestCase { |
|
2116 public static function getInfo() { |
|
2117 return array( |
|
2118 'name' => 'Token replacement', |
|
2119 'description' => 'Generates text using placeholders for dummy content to check token replacement.', |
|
2120 'group' => 'System', |
|
2121 ); |
|
2122 } |
|
2123 |
|
2124 /** |
|
2125 * Creates a user and a node, then tests the tokens generated from them. |
|
2126 */ |
|
2127 function testTokenReplacement() { |
|
2128 // Create the initial objects. |
|
2129 $account = $this->drupalCreateUser(); |
|
2130 $node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
2131 $node->title = '<blink>Blinking Text</blink>'; |
|
2132 global $user, $language; |
|
2133 |
|
2134 $source = '[node:title]'; // Title of the node we passed in |
|
2135 $source .= '[node:author:name]'; // Node author's name |
|
2136 $source .= '[node:created:since]'; // Time since the node was created |
|
2137 $source .= '[current-user:name]'; // Current user's name |
|
2138 $source .= '[date:short]'; // Short date format of REQUEST_TIME |
|
2139 $source .= '[user:name]'; // No user passed in, should be untouched |
|
2140 $source .= '[bogus:token]'; // Non-existent token |
|
2141 |
|
2142 $target = check_plain($node->title); |
|
2143 $target .= check_plain($account->name); |
|
2144 $target .= format_interval(REQUEST_TIME - $node->created, 2, $language->language); |
|
2145 $target .= check_plain($user->name); |
|
2146 $target .= format_date(REQUEST_TIME, 'short', '', NULL, $language->language); |
|
2147 |
|
2148 // Test that the clear parameter cleans out non-existent tokens. |
|
2149 $result = token_replace($source, array('node' => $node), array('language' => $language, 'clear' => TRUE)); |
|
2150 $result = $this->assertEqual($target, $result, 'Valid tokens replaced while invalid tokens cleared out.'); |
|
2151 |
|
2152 // Test without using the clear parameter (non-existent token untouched). |
|
2153 $target .= '[user:name]'; |
|
2154 $target .= '[bogus:token]'; |
|
2155 $result = token_replace($source, array('node' => $node), array('language' => $language)); |
|
2156 $this->assertEqual($target, $result, 'Valid tokens replaced while invalid tokens ignored.'); |
|
2157 |
|
2158 // Check that the results of token_generate are sanitized properly. This does NOT |
|
2159 // test the cleanliness of every token -- just that the $sanitize flag is being |
|
2160 // passed properly through the call stack and being handled correctly by a 'known' |
|
2161 // token, [node:title]. |
|
2162 $raw_tokens = array('title' => '[node:title]'); |
|
2163 $generated = token_generate('node', $raw_tokens, array('node' => $node)); |
|
2164 $this->assertEqual($generated['[node:title]'], check_plain($node->title), 'Token sanitized.'); |
|
2165 |
|
2166 $generated = token_generate('node', $raw_tokens, array('node' => $node), array('sanitize' => FALSE)); |
|
2167 $this->assertEqual($generated['[node:title]'], $node->title, 'Unsanitized token generated properly.'); |
|
2168 |
|
2169 // Test token replacement when the string contains no tokens. |
|
2170 $this->assertEqual(token_replace('No tokens here.'), 'No tokens here.'); |
|
2171 } |
|
2172 |
|
2173 /** |
|
2174 * Test whether token-replacement works in various contexts. |
|
2175 */ |
|
2176 function testSystemTokenRecognition() { |
|
2177 global $language; |
|
2178 |
|
2179 // Generate prefixes and suffixes for the token context. |
|
2180 $tests = array( |
|
2181 array('prefix' => 'this is the ', 'suffix' => ' site'), |
|
2182 array('prefix' => 'this is the', 'suffix' => 'site'), |
|
2183 array('prefix' => '[', 'suffix' => ']'), |
|
2184 array('prefix' => '', 'suffix' => ']]]'), |
|
2185 array('prefix' => '[[[', 'suffix' => ''), |
|
2186 array('prefix' => ':[:', 'suffix' => '--]'), |
|
2187 array('prefix' => '-[-', 'suffix' => ':]:'), |
|
2188 array('prefix' => '[:', 'suffix' => ']'), |
|
2189 array('prefix' => '[site:', 'suffix' => ':name]'), |
|
2190 array('prefix' => '[site:', 'suffix' => ']'), |
|
2191 ); |
|
2192 |
|
2193 // Check if the token is recognized in each of the contexts. |
|
2194 foreach ($tests as $test) { |
|
2195 $input = $test['prefix'] . '[site:name]' . $test['suffix']; |
|
2196 $expected = $test['prefix'] . 'Drupal' . $test['suffix']; |
|
2197 $output = token_replace($input, array(), array('language' => $language)); |
|
2198 $this->assertTrue($output == $expected, format_string('Token recognized in string %string', array('%string' => $input))); |
|
2199 } |
|
2200 } |
|
2201 |
|
2202 /** |
|
2203 * Tests the generation of all system site information tokens. |
|
2204 */ |
|
2205 function testSystemSiteTokenReplacement() { |
|
2206 global $language; |
|
2207 $url_options = array( |
|
2208 'absolute' => TRUE, |
|
2209 'language' => $language, |
|
2210 ); |
|
2211 |
|
2212 // Set a few site variables. |
|
2213 variable_set('site_name', '<strong>Drupal<strong>'); |
|
2214 variable_set('site_slogan', '<blink>Slogan</blink>'); |
|
2215 |
|
2216 // Generate and test sanitized tokens. |
|
2217 $tests = array(); |
|
2218 $tests['[site:name]'] = check_plain(variable_get('site_name', 'Drupal')); |
|
2219 $tests['[site:slogan]'] = check_plain(variable_get('site_slogan', '')); |
|
2220 $tests['[site:mail]'] = 'simpletest@example.com'; |
|
2221 $tests['[site:url]'] = url('<front>', $url_options); |
|
2222 $tests['[site:url-brief]'] = preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options)); |
|
2223 $tests['[site:login-url]'] = url('user', $url_options); |
|
2224 |
|
2225 // Test to make sure that we generated something for each token. |
|
2226 $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); |
|
2227 |
|
2228 foreach ($tests as $input => $expected) { |
|
2229 $output = token_replace($input, array(), array('language' => $language)); |
|
2230 $this->assertEqual($output, $expected, format_string('Sanitized system site information token %token replaced.', array('%token' => $input))); |
|
2231 } |
|
2232 |
|
2233 // Generate and test unsanitized tokens. |
|
2234 $tests['[site:name]'] = variable_get('site_name', 'Drupal'); |
|
2235 $tests['[site:slogan]'] = variable_get('site_slogan', ''); |
|
2236 |
|
2237 foreach ($tests as $input => $expected) { |
|
2238 $output = token_replace($input, array(), array('language' => $language, 'sanitize' => FALSE)); |
|
2239 $this->assertEqual($output, $expected, format_string('Unsanitized system site information token %token replaced.', array('%token' => $input))); |
|
2240 } |
|
2241 } |
|
2242 |
|
2243 /** |
|
2244 * Tests the generation of all system date tokens. |
|
2245 */ |
|
2246 function testSystemDateTokenReplacement() { |
|
2247 global $language; |
|
2248 |
|
2249 // Set time to one hour before request. |
|
2250 $date = REQUEST_TIME - 3600; |
|
2251 |
|
2252 // Generate and test tokens. |
|
2253 $tests = array(); |
|
2254 $tests['[date:short]'] = format_date($date, 'short', '', NULL, $language->language); |
|
2255 $tests['[date:medium]'] = format_date($date, 'medium', '', NULL, $language->language); |
|
2256 $tests['[date:long]'] = format_date($date, 'long', '', NULL, $language->language); |
|
2257 $tests['[date:custom:m/j/Y]'] = format_date($date, 'custom', 'm/j/Y', NULL, $language->language); |
|
2258 $tests['[date:since]'] = format_interval((REQUEST_TIME - $date), 2, $language->language); |
|
2259 $tests['[date:raw]'] = filter_xss($date); |
|
2260 |
|
2261 // Test to make sure that we generated something for each token. |
|
2262 $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); |
|
2263 |
|
2264 foreach ($tests as $input => $expected) { |
|
2265 $output = token_replace($input, array('date' => $date), array('language' => $language)); |
|
2266 $this->assertEqual($output, $expected, format_string('Date token %token replaced.', array('%token' => $input))); |
|
2267 } |
|
2268 } |
|
2269 } |
|
2270 |
|
2271 class InfoFileParserTestCase extends DrupalUnitTestCase { |
|
2272 public static function getInfo() { |
|
2273 return array( |
|
2274 'name' => 'Info file format parser', |
|
2275 'description' => 'Tests proper parsing of a .info file formatted string.', |
|
2276 'group' => 'System', |
|
2277 ); |
|
2278 } |
|
2279 |
|
2280 /** |
|
2281 * Test drupal_parse_info_format(). |
|
2282 */ |
|
2283 function testDrupalParseInfoFormat() { |
|
2284 $config = ' |
|
2285 simple = Value |
|
2286 quoted = " Value" |
|
2287 multiline = "Value |
|
2288 Value" |
|
2289 array[] = Value1 |
|
2290 array[] = Value2 |
|
2291 array_assoc[a] = Value1 |
|
2292 array_assoc[b] = Value2 |
|
2293 array_deep[][][] = Value |
|
2294 array_deep_assoc[a][b][c] = Value |
|
2295 array_space[a b] = Value'; |
|
2296 |
|
2297 $expected = array( |
|
2298 'simple' => 'Value', |
|
2299 'quoted' => ' Value', |
|
2300 'multiline' => "Value\n Value", |
|
2301 'array' => array( |
|
2302 0 => 'Value1', |
|
2303 1 => 'Value2', |
|
2304 ), |
|
2305 'array_assoc' => array( |
|
2306 'a' => 'Value1', |
|
2307 'b' => 'Value2', |
|
2308 ), |
|
2309 'array_deep' => array( |
|
2310 0 => array( |
|
2311 0 => array( |
|
2312 0 => 'Value', |
|
2313 ), |
|
2314 ), |
|
2315 ), |
|
2316 'array_deep_assoc' => array( |
|
2317 'a' => array( |
|
2318 'b' => array( |
|
2319 'c' => 'Value', |
|
2320 ), |
|
2321 ), |
|
2322 ), |
|
2323 'array_space' => array( |
|
2324 'a b' => 'Value', |
|
2325 ), |
|
2326 ); |
|
2327 |
|
2328 $parsed = drupal_parse_info_format($config); |
|
2329 |
|
2330 $this->assertEqual($parsed['simple'], $expected['simple'], 'Set a simple value.'); |
|
2331 $this->assertEqual($parsed['quoted'], $expected['quoted'], 'Set a simple value in quotes.'); |
|
2332 $this->assertEqual($parsed['multiline'], $expected['multiline'], 'Set a multiline value.'); |
|
2333 $this->assertEqual($parsed['array'], $expected['array'], 'Set a simple array.'); |
|
2334 $this->assertEqual($parsed['array_assoc'], $expected['array_assoc'], 'Set an associative array.'); |
|
2335 $this->assertEqual($parsed['array_deep'], $expected['array_deep'], 'Set a nested array.'); |
|
2336 $this->assertEqual($parsed['array_deep_assoc'], $expected['array_deep_assoc'], 'Set a nested associative array.'); |
|
2337 $this->assertEqual($parsed['array_space'], $expected['array_space'], 'Set an array with a whitespace in the key.'); |
|
2338 $this->assertEqual($parsed, $expected, 'Entire parsed .info string and expected array are identical.'); |
|
2339 } |
|
2340 } |
|
2341 |
|
2342 /** |
|
2343 * Tests the effectiveness of hook_system_info_alter(). |
|
2344 */ |
|
2345 class SystemInfoAlterTestCase extends DrupalWebTestCase { |
|
2346 public static function getInfo() { |
|
2347 return array( |
|
2348 'name' => 'System info alter', |
|
2349 'description' => 'Tests the effectiveness of hook_system_info_alter().', |
|
2350 'group' => 'System', |
|
2351 ); |
|
2352 } |
|
2353 |
|
2354 /** |
|
2355 * Tests that {system}.info is rebuilt after a module that implements |
|
2356 * hook_system_info_alter() is enabled. Also tests if core *_list() functions |
|
2357 * return freshly altered info. |
|
2358 */ |
|
2359 function testSystemInfoAlter() { |
|
2360 // Enable our test module. Flush all caches, which we assert is the only |
|
2361 // thing necessary to use the rebuilt {system}.info. |
|
2362 module_enable(array('module_test'), FALSE); |
|
2363 drupal_flush_all_caches(); |
|
2364 $this->assertTrue(module_exists('module_test'), 'Test module is enabled.'); |
|
2365 |
|
2366 $info = $this->getSystemInfo('seven', 'theme'); |
|
2367 $this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was added to {system}.info.'); |
|
2368 $seven_regions = system_region_list('seven'); |
|
2369 $this->assertTrue(isset($seven_regions['test_region']), 'Altered theme info was returned by system_region_list().'); |
|
2370 $system_list_themes = system_list('theme'); |
|
2371 $info = $system_list_themes['seven']->info; |
|
2372 $this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was returned by system_list().'); |
|
2373 $list_themes = list_themes(); |
|
2374 $this->assertTrue(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was returned by list_themes().'); |
|
2375 |
|
2376 // Disable the module and verify that {system}.info is rebuilt without it. |
|
2377 module_disable(array('module_test'), FALSE); |
|
2378 drupal_flush_all_caches(); |
|
2379 $this->assertFalse(module_exists('module_test'), 'Test module is disabled.'); |
|
2380 |
|
2381 $info = $this->getSystemInfo('seven', 'theme'); |
|
2382 $this->assertFalse(isset($info['regions']['test_region']), 'Altered theme info was removed from {system}.info.'); |
|
2383 $seven_regions = system_region_list('seven'); |
|
2384 $this->assertFalse(isset($seven_regions['test_region']), 'Altered theme info was not returned by system_region_list().'); |
|
2385 $system_list_themes = system_list('theme'); |
|
2386 $info = $system_list_themes['seven']->info; |
|
2387 $this->assertFalse(isset($info['regions']['test_region']), 'Altered theme info was not returned by system_list().'); |
|
2388 $list_themes = list_themes(); |
|
2389 $this->assertFalse(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was not returned by list_themes().'); |
|
2390 } |
|
2391 |
|
2392 /** |
|
2393 * Returns the info array as it is stored in {system}. |
|
2394 * |
|
2395 * @param $name |
|
2396 * The name of the record in {system}. |
|
2397 * @param $type |
|
2398 * The type of record in {system}. |
|
2399 * |
|
2400 * @return |
|
2401 * Array of info, or FALSE if the record is not found. |
|
2402 */ |
|
2403 function getSystemInfo($name, $type) { |
|
2404 $raw_info = db_query("SELECT info FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField(); |
|
2405 return $raw_info ? unserialize($raw_info) : FALSE; |
|
2406 } |
|
2407 } |
|
2408 |
|
2409 /** |
|
2410 * Tests for the update system functionality. |
|
2411 */ |
|
2412 class UpdateScriptFunctionalTest extends DrupalWebTestCase { |
|
2413 private $update_url; |
|
2414 private $update_user; |
|
2415 |
|
2416 public static function getInfo() { |
|
2417 return array( |
|
2418 'name' => 'Update functionality', |
|
2419 'description' => 'Tests the update script access and functionality.', |
|
2420 'group' => 'System', |
|
2421 ); |
|
2422 } |
|
2423 |
|
2424 function setUp() { |
|
2425 parent::setUp('update_script_test'); |
|
2426 $this->update_url = $GLOBALS['base_url'] . '/update.php'; |
|
2427 $this->update_user = $this->drupalCreateUser(array('administer software updates')); |
|
2428 } |
|
2429 |
|
2430 /** |
|
2431 * Tests that there are no pending updates for the first test method. |
|
2432 */ |
|
2433 function testNoPendingUpdates() { |
|
2434 // Ensure that for the first test method in a class, there are no pending |
|
2435 // updates. This tests a drupal_get_schema_versions() bug that previously |
|
2436 // led to the wrong schema version being recorded for the initial install |
|
2437 // of a child site during automated testing. |
|
2438 $this->drupalLogin($this->update_user); |
|
2439 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2440 $this->drupalPost(NULL, array(), t('Continue')); |
|
2441 $this->assertText(t('No pending updates.'), 'End of update process was reached.'); |
|
2442 } |
|
2443 |
|
2444 /** |
|
2445 * Tests access to the update script. |
|
2446 */ |
|
2447 function testUpdateAccess() { |
|
2448 // Try accessing update.php without the proper permission. |
|
2449 $regular_user = $this->drupalCreateUser(); |
|
2450 $this->drupalLogin($regular_user); |
|
2451 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2452 $this->assertResponse(403); |
|
2453 |
|
2454 // Try accessing update.php as an anonymous user. |
|
2455 $this->drupalLogout(); |
|
2456 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2457 $this->assertResponse(403); |
|
2458 |
|
2459 // Access the update page with the proper permission. |
|
2460 $this->drupalLogin($this->update_user); |
|
2461 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2462 $this->assertResponse(200); |
|
2463 |
|
2464 // Access the update page as user 1. |
|
2465 $user1 = user_load(1); |
|
2466 $user1->pass_raw = user_password(); |
|
2467 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); |
|
2468 $user1->pass = user_hash_password(trim($user1->pass_raw)); |
|
2469 db_query("UPDATE {users} SET pass = :pass WHERE uid = :uid", array(':pass' => $user1->pass, ':uid' => $user1->uid)); |
|
2470 $this->drupalLogin($user1); |
|
2471 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2472 $this->assertResponse(200); |
|
2473 } |
|
2474 |
|
2475 /** |
|
2476 * Tests that requirements warnings and errors are correctly displayed. |
|
2477 */ |
|
2478 function testRequirements() { |
|
2479 $this->drupalLogin($this->update_user); |
|
2480 |
|
2481 // If there are no requirements warnings or errors, we expect to be able to |
|
2482 // go through the update process uninterrupted. |
|
2483 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2484 $this->drupalPost(NULL, array(), t('Continue')); |
|
2485 $this->assertText(t('No pending updates.'), 'End of update process was reached.'); |
|
2486 // Confirm that all caches were cleared. |
|
2487 $this->assertText(t('hook_flush_caches() invoked for update_script_test.module.'), 'Caches were cleared when there were no requirements warnings or errors.'); |
|
2488 |
|
2489 // If there is a requirements warning, we expect it to be initially |
|
2490 // displayed, but clicking the link to proceed should allow us to go |
|
2491 // through the rest of the update process uninterrupted. |
|
2492 |
|
2493 // First, run this test with pending updates to make sure they can be run |
|
2494 // successfully. |
|
2495 variable_set('update_script_test_requirement_type', REQUIREMENT_WARNING); |
|
2496 drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1); |
|
2497 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2498 $this->assertText('This is a requirements warning provided by the update_script_test module.'); |
|
2499 $this->clickLink('try again'); |
|
2500 $this->assertNoText('This is a requirements warning provided by the update_script_test module.'); |
|
2501 $this->drupalPost(NULL, array(), t('Continue')); |
|
2502 $this->drupalPost(NULL, array(), t('Apply pending updates')); |
|
2503 $this->assertText(t('The update_script_test_update_7000() update was executed successfully.'), 'End of update process was reached.'); |
|
2504 // Confirm that all caches were cleared. |
|
2505 $this->assertText(t('hook_flush_caches() invoked for update_script_test.module.'), 'Caches were cleared after resolving a requirements warning and applying updates.'); |
|
2506 |
|
2507 // Now try again without pending updates to make sure that works too. |
|
2508 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2509 $this->assertText('This is a requirements warning provided by the update_script_test module.'); |
|
2510 $this->clickLink('try again'); |
|
2511 $this->assertNoText('This is a requirements warning provided by the update_script_test module.'); |
|
2512 $this->drupalPost(NULL, array(), t('Continue')); |
|
2513 $this->assertText(t('No pending updates.'), 'End of update process was reached.'); |
|
2514 // Confirm that all caches were cleared. |
|
2515 $this->assertText(t('hook_flush_caches() invoked for update_script_test.module.'), 'Caches were cleared after applying updates and re-running the script.'); |
|
2516 |
|
2517 // If there is a requirements error, it should be displayed even after |
|
2518 // clicking the link to proceed (since the problem that triggered the error |
|
2519 // has not been fixed). |
|
2520 variable_set('update_script_test_requirement_type', REQUIREMENT_ERROR); |
|
2521 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2522 $this->assertText('This is a requirements error provided by the update_script_test module.'); |
|
2523 $this->clickLink('try again'); |
|
2524 $this->assertText('This is a requirements error provided by the update_script_test module.'); |
|
2525 |
|
2526 // Check if the optional 'value' key displays without a notice. |
|
2527 variable_set('update_script_test_requirement_type', REQUIREMENT_INFO); |
|
2528 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2529 $this->assertText('This is a requirements info provided by the update_script_test module.'); |
|
2530 $this->assertNoText('Notice: Undefined index: value in theme_status_report()'); |
|
2531 } |
|
2532 |
|
2533 /** |
|
2534 * Tests the effect of using the update script on the theme system. |
|
2535 */ |
|
2536 function testThemeSystem() { |
|
2537 // Since visiting update.php triggers a rebuild of the theme system from an |
|
2538 // unusual maintenance mode environment, we check that this rebuild did not |
|
2539 // put any incorrect information about the themes into the database. |
|
2540 $original_theme_data = db_query("SELECT * FROM {system} WHERE type = 'theme' ORDER BY name")->fetchAll(); |
|
2541 $this->drupalLogin($this->update_user); |
|
2542 $this->drupalGet($this->update_url, array('external' => TRUE)); |
|
2543 $final_theme_data = db_query("SELECT * FROM {system} WHERE type = 'theme' ORDER BY name")->fetchAll(); |
|
2544 $this->assertEqual($original_theme_data, $final_theme_data, 'Visiting update.php does not alter the information about themes stored in the database.'); |
|
2545 } |
|
2546 |
|
2547 /** |
|
2548 * Tests update.php when there are no updates to apply. |
|
2549 */ |
|
2550 function testNoUpdateFunctionality() { |
|
2551 // Click through update.php with 'administer software updates' permission. |
|
2552 $this->drupalLogin($this->update_user); |
|
2553 $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE)); |
|
2554 $this->assertText(t('No pending updates.')); |
|
2555 $this->assertNoLink('Administration pages'); |
|
2556 $this->clickLink('Front page'); |
|
2557 $this->assertResponse(200); |
|
2558 |
|
2559 // Click through update.php with 'access administration pages' permission. |
|
2560 $admin_user = $this->drupalCreateUser(array('administer software updates', 'access administration pages')); |
|
2561 $this->drupalLogin($admin_user); |
|
2562 $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE)); |
|
2563 $this->assertText(t('No pending updates.')); |
|
2564 $this->clickLink('Administration pages'); |
|
2565 $this->assertResponse(200); |
|
2566 } |
|
2567 |
|
2568 /** |
|
2569 * Tests update.php after performing a successful update. |
|
2570 */ |
|
2571 function testSuccessfulUpdateFunctionality() { |
|
2572 drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1); |
|
2573 // Click through update.php with 'administer software updates' permission. |
|
2574 $this->drupalLogin($this->update_user); |
|
2575 $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE)); |
|
2576 $this->drupalPost(NULL, array(), t('Apply pending updates')); |
|
2577 $this->assertText('Updates were attempted.'); |
|
2578 $this->assertLink('site'); |
|
2579 $this->assertNoLink('Administration pages'); |
|
2580 $this->assertNoLink('logged'); |
|
2581 $this->clickLink('Front page'); |
|
2582 $this->assertResponse(200); |
|
2583 |
|
2584 drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1); |
|
2585 // Click through update.php with 'access administration pages' and |
|
2586 // 'access site reports' permissions. |
|
2587 $admin_user = $this->drupalCreateUser(array('administer software updates', 'access administration pages', 'access site reports')); |
|
2588 $this->drupalLogin($admin_user); |
|
2589 $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE)); |
|
2590 $this->drupalPost(NULL, array(), t('Apply pending updates')); |
|
2591 $this->assertText('Updates were attempted.'); |
|
2592 $this->assertLink('logged'); |
|
2593 $this->clickLink('Administration pages'); |
|
2594 $this->assertResponse(200); |
|
2595 } |
|
2596 } |
|
2597 |
|
2598 /** |
|
2599 * Functional tests for the flood control mechanism. |
|
2600 */ |
|
2601 class FloodFunctionalTest extends DrupalWebTestCase { |
|
2602 public static function getInfo() { |
|
2603 return array( |
|
2604 'name' => 'Flood control mechanism', |
|
2605 'description' => 'Functional tests for the flood control mechanism.', |
|
2606 'group' => 'System', |
|
2607 ); |
|
2608 } |
|
2609 |
|
2610 /** |
|
2611 * Test flood control mechanism clean-up. |
|
2612 */ |
|
2613 function testCleanUp() { |
|
2614 $threshold = 1; |
|
2615 $window_expired = -1; |
|
2616 $name = 'flood_test_cleanup'; |
|
2617 |
|
2618 // Register expired event. |
|
2619 flood_register_event($name, $window_expired); |
|
2620 // Verify event is not allowed. |
|
2621 $this->assertFalse(flood_is_allowed($name, $threshold)); |
|
2622 // Run cron and verify event is now allowed. |
|
2623 $this->cronRun(); |
|
2624 $this->assertTrue(flood_is_allowed($name, $threshold)); |
|
2625 |
|
2626 // Register unexpired event. |
|
2627 flood_register_event($name); |
|
2628 // Verify event is not allowed. |
|
2629 $this->assertFalse(flood_is_allowed($name, $threshold)); |
|
2630 // Run cron and verify event is still not allowed. |
|
2631 $this->cronRun(); |
|
2632 $this->assertFalse(flood_is_allowed($name, $threshold)); |
|
2633 } |
|
2634 } |
|
2635 |
|
2636 /** |
|
2637 * Test HTTP file downloading capability. |
|
2638 */ |
|
2639 class RetrieveFileTestCase extends DrupalWebTestCase { |
|
2640 public static function getInfo() { |
|
2641 return array( |
|
2642 'name' => 'HTTP file retrieval', |
|
2643 'description' => 'Checks HTTP file fetching and error handling.', |
|
2644 'group' => 'System', |
|
2645 ); |
|
2646 } |
|
2647 |
|
2648 /** |
|
2649 * Invokes system_retrieve_file() in several scenarios. |
|
2650 */ |
|
2651 function testFileRetrieving() { |
|
2652 // Test 404 handling by trying to fetch a randomly named file. |
|
2653 drupal_mkdir($sourcedir = 'public://' . $this->randomName()); |
|
2654 $filename = 'Файл для тестирования ' . $this->randomName(); |
|
2655 $url = file_create_url($sourcedir . '/' . $filename); |
|
2656 $retrieved_file = system_retrieve_file($url); |
|
2657 $this->assertFalse($retrieved_file, 'Non-existent file not fetched.'); |
|
2658 |
|
2659 // Actually create that file, download it via HTTP and test the returned path. |
|
2660 file_put_contents($sourcedir . '/' . $filename, 'testing'); |
|
2661 $retrieved_file = system_retrieve_file($url); |
|
2662 |
|
2663 // URLs could not contains characters outside the ASCII set so $filename |
|
2664 // has to be encoded. |
|
2665 $encoded_filename = rawurlencode($filename); |
|
2666 |
|
2667 $this->assertEqual($retrieved_file, 'public://' . $encoded_filename, 'Sane path for downloaded file returned (public:// scheme).'); |
|
2668 $this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (public:// scheme).'); |
|
2669 $this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (public:// scheme).'); |
|
2670 file_unmanaged_delete($retrieved_file); |
|
2671 |
|
2672 // Test downloading file to a different location. |
|
2673 drupal_mkdir($targetdir = 'temporary://' . $this->randomName()); |
|
2674 $retrieved_file = system_retrieve_file($url, $targetdir); |
|
2675 $this->assertEqual($retrieved_file, "$targetdir/$encoded_filename", 'Sane path for downloaded file returned (temporary:// scheme).'); |
|
2676 $this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (temporary:// scheme).'); |
|
2677 $this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (temporary:// scheme).'); |
|
2678 file_unmanaged_delete($retrieved_file); |
|
2679 |
|
2680 file_unmanaged_delete_recursive($sourcedir); |
|
2681 file_unmanaged_delete_recursive($targetdir); |
|
2682 } |
|
2683 } |
|
2684 |
|
2685 /** |
|
2686 * Functional tests shutdown functions. |
|
2687 */ |
|
2688 class ShutdownFunctionsTest extends DrupalWebTestCase { |
|
2689 public static function getInfo() { |
|
2690 return array( |
|
2691 'name' => 'Shutdown functions', |
|
2692 'description' => 'Functional tests for shutdown functions', |
|
2693 'group' => 'System', |
|
2694 ); |
|
2695 } |
|
2696 |
|
2697 function setUp() { |
|
2698 parent::setUp('system_test'); |
|
2699 } |
|
2700 |
|
2701 /** |
|
2702 * Test shutdown functions. |
|
2703 */ |
|
2704 function testShutdownFunctions() { |
|
2705 $arg1 = $this->randomName(); |
|
2706 $arg2 = $this->randomName(); |
|
2707 $this->drupalGet('system-test/shutdown-functions/' . $arg1 . '/' . $arg2); |
|
2708 $this->assertText(t('First shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2))); |
|
2709 $this->assertText(t('Second shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2))); |
|
2710 |
|
2711 // Make sure exceptions displayed through _drupal_render_exception_safe() |
|
2712 // are correctly escaped. |
|
2713 $this->assertRaw('Drupal is &lt;blink&gt;awesome&lt;/blink&gt;.'); |
|
2714 } |
|
2715 } |
|
2716 |
|
2717 /** |
|
2718 * Tests administrative overview pages. |
|
2719 */ |
|
2720 class SystemAdminTestCase extends DrupalWebTestCase { |
|
2721 public static function getInfo() { |
|
2722 return array( |
|
2723 'name' => 'Administrative pages', |
|
2724 'description' => 'Tests output on administrative pages and compact mode functionality.', |
|
2725 'group' => 'System', |
|
2726 ); |
|
2727 } |
|
2728 |
|
2729 function setUp() { |
|
2730 // testAdminPages() requires Locale module. |
|
2731 parent::setUp(array('locale')); |
|
2732 |
|
2733 // Create an administrator with all permissions, as well as a regular user |
|
2734 // who can only access administration pages and perform some Locale module |
|
2735 // administrative tasks, but not all of them. |
|
2736 $this->admin_user = $this->drupalCreateUser(array_keys(module_invoke_all('permission'))); |
|
2737 $this->web_user = $this->drupalCreateUser(array( |
|
2738 'access administration pages', |
|
2739 'translate interface', |
|
2740 )); |
|
2741 $this->drupalLogin($this->admin_user); |
|
2742 } |
|
2743 |
|
2744 /** |
|
2745 * Tests output on administrative listing pages. |
|
2746 */ |
|
2747 function testAdminPages() { |
|
2748 // Go to Administration. |
|
2749 $this->drupalGet('admin'); |
|
2750 |
|
2751 // Verify that all visible, top-level administration links are listed on |
|
2752 // the main administration page. |
|
2753 foreach (menu_get_router() as $path => $item) { |
|
2754 if (strpos($path, 'admin/') === 0 && ($item['type'] & MENU_VISIBLE_IN_TREE) && $item['_number_parts'] == 2) { |
|
2755 $this->assertLink($item['title']); |
|
2756 $this->assertLinkByHref($path); |
|
2757 $this->assertText($item['description']); |
|
2758 } |
|
2759 } |
|
2760 |
|
2761 // For each administrative listing page on which the Locale module appears, |
|
2762 // verify that there are links to the module's primary configuration pages, |
|
2763 // but no links to its individual sub-configuration pages. Also verify that |
|
2764 // a user with access to only some Locale module administration pages only |
|
2765 // sees links to the pages they have access to. |
|
2766 $admin_list_pages = array( |
|
2767 'admin/index', |
|
2768 'admin/config', |
|
2769 'admin/config/regional', |
|
2770 ); |
|
2771 |
|
2772 foreach ($admin_list_pages as $page) { |
|
2773 // For the administrator, verify that there are links to Locale's primary |
|
2774 // configuration pages, but no links to individual sub-configuration |
|
2775 // pages. |
|
2776 $this->drupalLogin($this->admin_user); |
|
2777 $this->drupalGet($page); |
|
2778 $this->assertLinkByHref('admin/config'); |
|
2779 $this->assertLinkByHref('admin/config/regional/settings'); |
|
2780 $this->assertLinkByHref('admin/config/regional/date-time'); |
|
2781 $this->assertLinkByHref('admin/config/regional/language'); |
|
2782 $this->assertNoLinkByHref('admin/config/regional/language/configure/session'); |
|
2783 $this->assertNoLinkByHref('admin/config/regional/language/configure/url'); |
|
2784 $this->assertLinkByHref('admin/config/regional/translate'); |
|
2785 // On admin/index only, the administrator should also see a "Configure |
|
2786 // permissions" link for the Locale module. |
|
2787 if ($page == 'admin/index') { |
|
2788 $this->assertLinkByHref("admin/people/permissions#module-locale"); |
|
2789 } |
|
2790 |
|
2791 // For a less privileged user, verify that there are no links to Locale's |
|
2792 // primary configuration pages, but a link to the translate page exists. |
|
2793 $this->drupalLogin($this->web_user); |
|
2794 $this->drupalGet($page); |
|
2795 $this->assertLinkByHref('admin/config'); |
|
2796 $this->assertNoLinkByHref('admin/config/regional/settings'); |
|
2797 $this->assertNoLinkByHref('admin/config/regional/date-time'); |
|
2798 $this->assertNoLinkByHref('admin/config/regional/language'); |
|
2799 $this->assertNoLinkByHref('admin/config/regional/language/configure/session'); |
|
2800 $this->assertNoLinkByHref('admin/config/regional/language/configure/url'); |
|
2801 $this->assertLinkByHref('admin/config/regional/translate'); |
|
2802 // This user cannot configure permissions, so even on admin/index should |
|
2803 // not see a "Configure permissions" link for the Locale module. |
|
2804 if ($page == 'admin/index') { |
|
2805 $this->assertNoLinkByHref("admin/people/permissions#module-locale"); |
|
2806 } |
|
2807 } |
|
2808 } |
|
2809 |
|
2810 /** |
|
2811 * Test compact mode. |
|
2812 */ |
|
2813 function testCompactMode() { |
|
2814 $this->drupalGet('admin/compact/on'); |
|
2815 $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode turns on.'); |
|
2816 $this->drupalGet('admin/compact/on'); |
|
2817 $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode remains on after a repeat call.'); |
|
2818 $this->drupalGet(''); |
|
2819 $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode persists on new requests.'); |
|
2820 |
|
2821 $this->drupalGet('admin/compact/off'); |
|
2822 $this->assertEqual($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'deleted', 'Compact mode turns off.'); |
|
2823 $this->drupalGet('admin/compact/off'); |
|
2824 $this->assertEqual($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'deleted', 'Compact mode remains off after a repeat call.'); |
|
2825 $this->drupalGet(''); |
|
2826 $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode persists on new requests.'); |
|
2827 } |
|
2828 } |
|
2829 |
|
2830 /** |
|
2831 * Tests authorize.php and related hooks. |
|
2832 */ |
|
2833 class SystemAuthorizeCase extends DrupalWebTestCase { |
|
2834 public static function getInfo() { |
|
2835 return array( |
|
2836 'name' => 'Authorize API', |
|
2837 'description' => 'Tests the authorize.php script and related API.', |
|
2838 'group' => 'System', |
|
2839 ); |
|
2840 } |
|
2841 |
|
2842 function setUp() { |
|
2843 parent::setUp(array('system_test')); |
|
2844 |
|
2845 variable_set('allow_authorize_operations', TRUE); |
|
2846 |
|
2847 // Create an administrator user. |
|
2848 $this->admin_user = $this->drupalCreateUser(array('administer software updates')); |
|
2849 $this->drupalLogin($this->admin_user); |
|
2850 } |
|
2851 |
|
2852 /** |
|
2853 * Helper function to initialize authorize.php and load it via drupalGet(). |
|
2854 * |
|
2855 * Initializing authorize.php needs to happen in the child Drupal |
|
2856 * installation, not the parent. So, we visit a menu callback provided by |
|
2857 * system_test.module which calls system_authorized_init() to initialize the |
|
2858 * $_SESSION inside the test site, not the framework site. This callback |
|
2859 * redirects to authorize.php when it's done initializing. |
|
2860 * |
|
2861 * @see system_authorized_init(). |
|
2862 */ |
|
2863 function drupalGetAuthorizePHP($page_title = 'system-test-auth') { |
|
2864 $this->drupalGet('system-test/authorize-init/' . $page_title); |
|
2865 } |
|
2866 |
|
2867 /** |
|
2868 * Tests the FileTransfer hooks |
|
2869 */ |
|
2870 function testFileTransferHooks() { |
|
2871 $page_title = $this->randomName(16); |
|
2872 $this->drupalGetAuthorizePHP($page_title); |
|
2873 $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title)), 'authorize.php page title is correct.'); |
|
2874 $this->assertNoText('It appears you have reached this page in error.'); |
|
2875 $this->assertText('To continue, provide your server connection details'); |
|
2876 // Make sure we see the new connection method added by system_test. |
|
2877 $this->assertRaw('System Test FileTransfer'); |
|
2878 // Make sure the settings form callback works. |
|
2879 $this->assertText('System Test Username'); |
|
2880 } |
|
2881 } |
|
2882 |
|
2883 /** |
|
2884 * Test the handling of requests containing 'index.php'. |
|
2885 */ |
|
2886 class SystemIndexPhpTest extends DrupalWebTestCase { |
|
2887 public static function getInfo() { |
|
2888 return array( |
|
2889 'name' => 'Index.php handling', |
|
2890 'description' => "Test the handling of requests containing 'index.php'.", |
|
2891 'group' => 'System', |
|
2892 ); |
|
2893 } |
|
2894 |
|
2895 function setUp() { |
|
2896 parent::setUp(); |
|
2897 } |
|
2898 |
|
2899 /** |
|
2900 * Test index.php handling. |
|
2901 */ |
|
2902 function testIndexPhpHandling() { |
|
2903 $index_php = $GLOBALS['base_url'] . '/index.php'; |
|
2904 |
|
2905 $this->drupalGet($index_php, array('external' => TRUE)); |
|
2906 $this->assertResponse(200, 'Make sure index.php returns a valid page.'); |
|
2907 |
|
2908 $this->drupalGet($index_php, array('external' => TRUE, 'query' => array('q' => 'user'))); |
|
2909 $this->assertResponse(200, 'Make sure index.php?q=user returns a valid page.'); |
|
2910 |
|
2911 $this->drupalGet($index_php .'/user', array('external' => TRUE)); |
|
2912 $this->assertResponse(404, "Make sure index.php/user returns a 'page not found'."); |
|
2913 } |
|
2914 } |
|
2915 |
|
2916 /** |
|
2917 * Test token replacement in strings. |
|
2918 */ |
|
2919 class TokenScanTest extends DrupalWebTestCase { |
|
2920 |
|
2921 public static function getInfo() { |
|
2922 return array( |
|
2923 'name' => 'Token scanning', |
|
2924 'description' => 'Scan token-like patterns in a dummy text to check token scanning.', |
|
2925 'group' => 'System', |
|
2926 ); |
|
2927 } |
|
2928 |
|
2929 /** |
|
2930 * Scans dummy text, then tests the output. |
|
2931 */ |
|
2932 function testTokenScan() { |
|
2933 // Define text with valid and not valid, fake and existing token-like |
|
2934 // strings. |
|
2935 $text = 'First a [valid:simple], but dummy token, and a dummy [valid:token with: spaces].'; |
|
2936 $text .= 'Then a [not valid:token].'; |
|
2937 $text .= 'Last an existing token: [node:author:name].'; |
|
2938 $token_wannabes = token_scan($text); |
|
2939 |
|
2940 $this->assertTrue(isset($token_wannabes['valid']['simple']), 'A simple valid token has been matched.'); |
|
2941 $this->assertTrue(isset($token_wannabes['valid']['token with: spaces']), 'A valid token with space characters in the token name has been matched.'); |
|
2942 $this->assertFalse(isset($token_wannabes['not valid']), 'An invalid token with spaces in the token type has not been matched.'); |
|
2943 $this->assertTrue(isset($token_wannabes['node']), 'An existing valid token has been matched.'); |
|
2944 } |
|
2945 } |
|
2946 |
|
2947 /** |
|
2948 * Test case for drupal_valid_token(). |
|
2949 */ |
|
2950 class SystemValidTokenTest extends DrupalUnitTestCase { |
|
2951 |
|
2952 /** |
|
2953 * Flag to indicate whether PHP error reportings should be asserted. |
|
2954 * |
|
2955 * @var bool |
|
2956 */ |
|
2957 protected $assertErrors = TRUE; |
|
2958 |
|
2959 public static function getInfo() { |
|
2960 return array( |
|
2961 'name' => 'Token validation', |
|
2962 'description' => 'Test the security token validation.', |
|
2963 'group' => 'System', |
|
2964 ); |
|
2965 } |
|
2966 |
|
2967 /** |
|
2968 * Tests invalid invocations of drupal_valid_token() that must return FALSE. |
|
2969 */ |
|
2970 public function testTokenValidation() { |
|
2971 // The following checks will throw PHP notices, so we disable error |
|
2972 // assertions. |
|
2973 $this->assertErrors = FALSE; |
|
2974 $this->assertFalse(drupal_valid_token(NULL, new stdClass()), 'Token NULL, value object returns FALSE.'); |
|
2975 $this->assertFalse(drupal_valid_token(0, array()), 'Token 0, value array returns FALSE.'); |
|
2976 $this->assertFalse(drupal_valid_token('', array()), "Token '', value array returns FALSE."); |
|
2977 $this->assertFalse('' === drupal_get_token(array()), 'Token generation does not return an empty string on invalid parameters.'); |
|
2978 $this->assertErrors = TRUE; |
|
2979 |
|
2980 $this->assertFalse(drupal_valid_token(TRUE, 'foo'), 'Token TRUE, value foo returns FALSE.'); |
|
2981 $this->assertFalse(drupal_valid_token(0, 'foo'), 'Token 0, value foo returns FALSE.'); |
|
2982 } |
|
2983 |
|
2984 /** |
|
2985 * Overrides DrupalTestCase::errorHandler(). |
|
2986 */ |
|
2987 public function errorHandler($severity, $message, $file = NULL, $line = NULL) { |
|
2988 if ($this->assertErrors) { |
|
2989 return parent::errorHandler($severity, $message, $file, $line); |
|
2990 } |
|
2991 return TRUE; |
|
2992 } |
|
2993 } |
|
2994 |
|
2995 /** |
|
2996 * Tests drupal_set_message() and related functions. |
|
2997 */ |
|
2998 class DrupalSetMessageTest extends DrupalWebTestCase { |
|
2999 |
|
3000 public static function getInfo() { |
|
3001 return array( |
|
3002 'name' => 'Messages', |
|
3003 'description' => 'Tests that messages can be displayed using drupal_set_message().', |
|
3004 'group' => 'System', |
|
3005 ); |
|
3006 } |
|
3007 |
|
3008 function setUp() { |
|
3009 parent::setUp('system_test'); |
|
3010 } |
|
3011 |
|
3012 /** |
|
3013 * Tests setting messages and removing one before it is displayed. |
|
3014 */ |
|
3015 function testSetRemoveMessages() { |
|
3016 // The page at system-test/drupal-set-message sets two messages and then |
|
3017 // removes the first before it is displayed. |
|
3018 $this->drupalGet('system-test/drupal-set-message'); |
|
3019 $this->assertNoText('First message (removed).'); |
|
3020 $this->assertText('Second message (not removed).'); |
|
3021 } |
|
3022 } |
|
3023 |
|
3024 /** |
|
3025 * Tests confirm form destinations. |
|
3026 */ |
|
3027 class ConfirmFormTest extends DrupalWebTestCase { |
|
3028 protected $admin_user; |
|
3029 |
|
3030 public static function getInfo() { |
|
3031 return array( |
|
3032 'name' => 'Confirm form', |
|
3033 'description' => 'Tests that the confirm form does not use external destinations.', |
|
3034 'group' => 'System', |
|
3035 ); |
|
3036 } |
|
3037 |
|
3038 function setUp() { |
|
3039 parent::setUp(); |
|
3040 |
|
3041 $this->admin_user = $this->drupalCreateUser(array('administer users')); |
|
3042 $this->drupalLogin($this->admin_user); |
|
3043 } |
|
3044 |
|
3045 /** |
|
3046 * Tests that the confirm form does not use external destinations. |
|
3047 */ |
|
3048 function testConfirmForm() { |
|
3049 $this->drupalGet('user/1/cancel'); |
|
3050 $this->assertCancelLinkUrl(url('user/1')); |
|
3051 $this->drupalGet('user/1/cancel', array('query' => array('destination' => 'node'))); |
|
3052 $this->assertCancelLinkUrl(url('node')); |
|
3053 $this->drupalGet('user/1/cancel', array('query' => array('destination' => 'http://example.com'))); |
|
3054 $this->assertCancelLinkUrl(url('user/1')); |
|
3055 } |
|
3056 |
|
3057 /** |
|
3058 * Asserts that a cancel link is present pointing to the provided URL. |
|
3059 */ |
|
3060 function assertCancelLinkUrl($url, $message = '', $group = 'Other') { |
|
3061 $links = $this->xpath('//a[normalize-space(text())=:label and @href=:url]', array(':label' => t('Cancel'), ':url' => $url)); |
|
3062 $message = ($message ? $message : format_string('Cancel link with url %url found.', array('%url' => $url))); |
|
3063 return $this->assertTrue(isset($links[0]), $message, $group); |
|
3064 } |
|
3065 } |