|
1 <?php |
|
2 |
|
3 class BootstrapIPAddressTestCase extends DrupalWebTestCase { |
|
4 |
|
5 public static function getInfo() { |
|
6 return array( |
|
7 'name' => 'IP address and HTTP_HOST test', |
|
8 'description' => 'Get the IP address from the current visitor from the server variables, check hostname validation.', |
|
9 'group' => 'Bootstrap' |
|
10 ); |
|
11 } |
|
12 |
|
13 function setUp() { |
|
14 $this->oldserver = $_SERVER; |
|
15 |
|
16 $this->remote_ip = '127.0.0.1'; |
|
17 $this->proxy_ip = '127.0.0.2'; |
|
18 $this->proxy2_ip = '127.0.0.3'; |
|
19 $this->forwarded_ip = '127.0.0.4'; |
|
20 $this->cluster_ip = '127.0.0.5'; |
|
21 $this->untrusted_ip = '0.0.0.0'; |
|
22 |
|
23 drupal_static_reset('ip_address'); |
|
24 |
|
25 $_SERVER['REMOTE_ADDR'] = $this->remote_ip; |
|
26 unset($_SERVER['HTTP_X_FORWARDED_FOR']); |
|
27 unset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']); |
|
28 |
|
29 parent::setUp(); |
|
30 } |
|
31 |
|
32 function tearDown() { |
|
33 $_SERVER = $this->oldserver; |
|
34 drupal_static_reset('ip_address'); |
|
35 parent::tearDown(); |
|
36 } |
|
37 |
|
38 /** |
|
39 * test IP Address and hostname |
|
40 */ |
|
41 function testIPAddressHost() { |
|
42 // Test the normal IP address. |
|
43 $this->assertTrue( |
|
44 ip_address() == $this->remote_ip, |
|
45 'Got remote IP address.' |
|
46 ); |
|
47 |
|
48 // Proxy forwarding on but no proxy addresses defined. |
|
49 variable_set('reverse_proxy', 1); |
|
50 $this->assertTrue( |
|
51 ip_address() == $this->remote_ip, |
|
52 'Proxy forwarding without trusted proxies got remote IP address.' |
|
53 ); |
|
54 |
|
55 // Proxy forwarding on and proxy address not trusted. |
|
56 variable_set('reverse_proxy_addresses', array($this->proxy_ip, $this->proxy2_ip)); |
|
57 drupal_static_reset('ip_address'); |
|
58 $_SERVER['REMOTE_ADDR'] = $this->untrusted_ip; |
|
59 $this->assertTrue( |
|
60 ip_address() == $this->untrusted_ip, |
|
61 'Proxy forwarding with untrusted proxy got remote IP address.' |
|
62 ); |
|
63 |
|
64 // Proxy forwarding on and proxy address trusted. |
|
65 $_SERVER['REMOTE_ADDR'] = $this->proxy_ip; |
|
66 $_SERVER['HTTP_X_FORWARDED_FOR'] = $this->forwarded_ip; |
|
67 drupal_static_reset('ip_address'); |
|
68 $this->assertTrue( |
|
69 ip_address() == $this->forwarded_ip, |
|
70 'Proxy forwarding with trusted proxy got forwarded IP address.' |
|
71 ); |
|
72 |
|
73 // Proxy forwarding on and proxy address trusted and visiting from proxy. |
|
74 $_SERVER['REMOTE_ADDR'] = $this->proxy_ip; |
|
75 $_SERVER['HTTP_X_FORWARDED_FOR'] = $this->proxy_ip; |
|
76 drupal_static_reset('ip_address'); |
|
77 $this->assertTrue( |
|
78 ip_address() == $this->proxy_ip, |
|
79 'Visiting from trusted proxy got proxy IP address.' |
|
80 ); |
|
81 |
|
82 // Multi-tier architecture with comma separated values in header. |
|
83 $_SERVER['REMOTE_ADDR'] = $this->proxy_ip; |
|
84 $_SERVER['HTTP_X_FORWARDED_FOR'] = implode(', ', array($this->untrusted_ip, $this->forwarded_ip, $this->proxy2_ip)); |
|
85 drupal_static_reset('ip_address'); |
|
86 $this->assertTrue( |
|
87 ip_address() == $this->forwarded_ip, |
|
88 'Proxy forwarding with trusted 2-tier proxy got forwarded IP address.' |
|
89 ); |
|
90 |
|
91 // Custom client-IP header. |
|
92 variable_set('reverse_proxy_header', 'HTTP_X_CLUSTER_CLIENT_IP'); |
|
93 $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] = $this->cluster_ip; |
|
94 drupal_static_reset('ip_address'); |
|
95 $this->assertTrue( |
|
96 ip_address() == $this->cluster_ip, |
|
97 'Cluster environment got cluster client IP.' |
|
98 ); |
|
99 |
|
100 // Verifies that drupal_valid_http_host() prevents invalid characters. |
|
101 $this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), 'HTTP_HOST with / is invalid'); |
|
102 $this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid'); |
|
103 $this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with < is invalid'); |
|
104 $this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid'); |
|
105 // Verifies that host names are shorter than 1000 characters. |
|
106 $this->assertFalse(drupal_valid_http_host(str_repeat('x', 1001)), 'HTTP_HOST with more than 1000 characters is invalid.'); |
|
107 $this->assertFalse(drupal_valid_http_host(str_repeat('.', 101)), 'HTTP_HOST with more than 100 subdomains is invalid.'); |
|
108 $this->assertFalse(drupal_valid_http_host(str_repeat(':', 101)), 'HTTP_HOST with more than 100 portseparators is invalid.'); |
|
109 |
|
110 // IPv6 loopback address |
|
111 $this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid'); |
|
112 } |
|
113 } |
|
114 |
|
115 class BootstrapPageCacheTestCase extends DrupalWebTestCase { |
|
116 |
|
117 public static function getInfo() { |
|
118 return array( |
|
119 'name' => 'Page cache test', |
|
120 'description' => 'Enable the page cache and test it with various HTTP requests.', |
|
121 'group' => 'Bootstrap' |
|
122 ); |
|
123 } |
|
124 |
|
125 function setUp() { |
|
126 parent::setUp('system_test'); |
|
127 } |
|
128 |
|
129 /** |
|
130 * Test support for requests containing If-Modified-Since and If-None-Match headers. |
|
131 */ |
|
132 function testConditionalRequests() { |
|
133 variable_set('cache', 1); |
|
134 |
|
135 // Fill the cache. |
|
136 $this->drupalGet(''); |
|
137 |
|
138 $this->drupalHead(''); |
|
139 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); |
|
140 $etag = $this->drupalGetHeader('ETag'); |
|
141 $last_modified = $this->drupalGetHeader('Last-Modified'); |
|
142 |
|
143 $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag)); |
|
144 $this->assertResponse(304, 'Conditional request returned 304 Not Modified.'); |
|
145 |
|
146 $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC822, strtotime($last_modified)), 'If-None-Match: ' . $etag)); |
|
147 $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.'); |
|
148 |
|
149 $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC850, strtotime($last_modified)), 'If-None-Match: ' . $etag)); |
|
150 $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.'); |
|
151 |
|
152 $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified)); |
|
153 $this->assertResponse(200, 'Conditional request without If-None-Match returned 200 OK.'); |
|
154 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); |
|
155 |
|
156 $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC7231, strtotime($last_modified) + 1), 'If-None-Match: ' . $etag)); |
|
157 $this->assertResponse(200, 'Conditional request with new a If-Modified-Since date newer than Last-Modified returned 200 OK.'); |
|
158 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); |
|
159 |
|
160 $user = $this->drupalCreateUser(); |
|
161 $this->drupalLogin($user); |
|
162 $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag)); |
|
163 $this->assertResponse(200, 'Conditional request returned 200 OK for authenticated user.'); |
|
164 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Absence of Page was not cached.'); |
|
165 $this->assertFalse($this->drupalGetHeader('ETag'), 'ETag HTTP headers are not present for logged in users.'); |
|
166 $this->assertFalse($this->drupalGetHeader('Last-Modified'), 'Last-Modified HTTP headers are not present for logged in users.'); |
|
167 } |
|
168 |
|
169 /** |
|
170 * Test cache headers. |
|
171 */ |
|
172 function testPageCache() { |
|
173 variable_set('cache', 1); |
|
174 |
|
175 // Fill the cache. |
|
176 $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); |
|
177 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.'); |
|
178 $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary header was sent.'); |
|
179 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.'); |
|
180 $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); |
|
181 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); |
|
182 |
|
183 // Check cache. |
|
184 $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); |
|
185 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); |
|
186 $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary: Cookie header was sent.'); |
|
187 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.'); |
|
188 $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); |
|
189 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); |
|
190 |
|
191 // Check replacing default headers. |
|
192 $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT'))); |
|
193 $this->assertEqual($this->drupalGetHeader('Expires'), 'Fri, 19 Nov 2008 05:00:00 GMT', 'Default header was replaced.'); |
|
194 $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Vary', 'value' => 'User-Agent'))); |
|
195 $this->assertEqual($this->drupalGetHeader('Vary'), 'User-Agent,Accept-Encoding', 'Default header was replaced.'); |
|
196 |
|
197 // Check that authenticated users bypass the cache. |
|
198 $user = $this->drupalCreateUser(); |
|
199 $this->drupalLogin($user); |
|
200 $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); |
|
201 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.'); |
|
202 $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.'); |
|
203 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate', 'Cache-Control header was sent.'); |
|
204 $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); |
|
205 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); |
|
206 |
|
207 } |
|
208 |
|
209 /** |
|
210 * Test page compression. |
|
211 * |
|
212 * The test should pass even if zlib.output_compression is enabled in php.ini, |
|
213 * .htaccess or similar, or if compression is done outside PHP, e.g. by the |
|
214 * mod_deflate Apache module. |
|
215 */ |
|
216 function testPageCompression() { |
|
217 variable_set('cache', 1); |
|
218 |
|
219 // Fill the cache and verify that output is compressed. |
|
220 $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate')); |
|
221 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.'); |
|
222 $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8))); |
|
223 $this->assertRaw('</html>', 'Page was gzip compressed.'); |
|
224 |
|
225 // Verify that cached output is compressed. |
|
226 $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate')); |
|
227 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); |
|
228 $this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', 'A Content-Encoding header was sent.'); |
|
229 $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8))); |
|
230 $this->assertRaw('</html>', 'Page was gzip compressed.'); |
|
231 |
|
232 // Verify that a client without compression support gets an uncompressed page. |
|
233 $this->drupalGet(''); |
|
234 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); |
|
235 $this->assertFalse($this->drupalGetHeader('Content-Encoding'), 'A Content-Encoding header was not sent.'); |
|
236 $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.'); |
|
237 $this->assertRaw('</html>', 'Page was not compressed.'); |
|
238 |
|
239 // Disable compression mode. |
|
240 variable_set('page_compression', FALSE); |
|
241 |
|
242 // Verify if cached page is still available for a client with compression support. |
|
243 $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate')); |
|
244 $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8))); |
|
245 $this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support enabled).'); |
|
246 |
|
247 // Verify if cached page is still available for a client without compression support. |
|
248 $this->drupalGet(''); |
|
249 $this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support disabled).'); |
|
250 } |
|
251 } |
|
252 |
|
253 class BootstrapVariableTestCase extends DrupalWebTestCase { |
|
254 |
|
255 function setUp() { |
|
256 parent::setUp('system_test'); |
|
257 } |
|
258 |
|
259 public static function getInfo() { |
|
260 return array( |
|
261 'name' => 'Variable test', |
|
262 'description' => 'Make sure the variable system functions correctly.', |
|
263 'group' => 'Bootstrap' |
|
264 ); |
|
265 } |
|
266 |
|
267 /** |
|
268 * testVariable |
|
269 */ |
|
270 function testVariable() { |
|
271 // Setting and retrieving values. |
|
272 $variable = $this->randomName(); |
|
273 variable_set('simpletest_bootstrap_variable_test', $variable); |
|
274 $this->assertIdentical($variable, variable_get('simpletest_bootstrap_variable_test'), 'Setting and retrieving values'); |
|
275 |
|
276 // Make sure the variable persists across multiple requests. |
|
277 $this->drupalGet('system-test/variable-get'); |
|
278 $this->assertText($variable, 'Variable persists across multiple requests'); |
|
279 |
|
280 // Deleting variables. |
|
281 $default_value = $this->randomName(); |
|
282 variable_del('simpletest_bootstrap_variable_test'); |
|
283 $variable = variable_get('simpletest_bootstrap_variable_test', $default_value); |
|
284 $this->assertIdentical($variable, $default_value, 'Deleting variables'); |
|
285 } |
|
286 |
|
287 /** |
|
288 * Makes sure that the default variable parameter is passed through okay. |
|
289 */ |
|
290 function testVariableDefaults() { |
|
291 // Tests passing nothing through to the default. |
|
292 $this->assertIdentical(NULL, variable_get('simpletest_bootstrap_variable_test'), 'Variables are correctly defaulting to NULL.'); |
|
293 |
|
294 // Tests passing 5 to the default parameter. |
|
295 $this->assertIdentical(5, variable_get('simpletest_bootstrap_variable_test', 5), 'The default variable parameter is passed through correctly.'); |
|
296 } |
|
297 |
|
298 } |
|
299 |
|
300 /** |
|
301 * Tests the auto-loading behavior of the code registry. |
|
302 */ |
|
303 class BootstrapAutoloadTestCase extends DrupalWebTestCase { |
|
304 |
|
305 public static function getInfo() { |
|
306 return array( |
|
307 'name' => 'Code registry', |
|
308 'description' => 'Test that the code registry functions correctly.', |
|
309 'group' => 'Bootstrap', |
|
310 ); |
|
311 } |
|
312 |
|
313 function setUp() { |
|
314 parent::setUp('drupal_autoload_test'); |
|
315 } |
|
316 |
|
317 /** |
|
318 * Tests that autoloader name matching is not case sensitive. |
|
319 */ |
|
320 function testAutoloadCase() { |
|
321 // Test interface autoloader. |
|
322 $this->assertTrue(drupal_autoload_interface('drupalautoloadtestinterface'), 'drupal_autoload_interface() recognizes <em>DrupalAutoloadTestInterface</em> in lower case.'); |
|
323 // Test class autoloader. |
|
324 $this->assertTrue(drupal_autoload_class('drupalautoloadtestclass'), 'drupal_autoload_class() recognizes <em>DrupalAutoloadTestClass</em> in lower case.'); |
|
325 // Test trait autoloader. |
|
326 if (version_compare(PHP_VERSION, '5.4') >= 0) { |
|
327 $this->assertTrue(drupal_autoload_trait('drupalautoloadtesttrait'), 'drupal_autoload_trait() recognizes <em>DrupalAutoloadTestTrait</em> in lower case.'); |
|
328 } |
|
329 } |
|
330 |
|
331 } |
|
332 |
|
333 /** |
|
334 * Test hook_boot() and hook_exit(). |
|
335 */ |
|
336 class HookBootExitTestCase extends DrupalWebTestCase { |
|
337 |
|
338 public static function getInfo() { |
|
339 return array( |
|
340 'name' => 'Boot and exit hook invocation', |
|
341 'description' => 'Test that hook_boot() and hook_exit() are called correctly.', |
|
342 'group' => 'Bootstrap', |
|
343 ); |
|
344 } |
|
345 |
|
346 function setUp() { |
|
347 parent::setUp('system_test', 'dblog'); |
|
348 } |
|
349 |
|
350 /** |
|
351 * Test calling of hook_boot() and hook_exit(). |
|
352 */ |
|
353 function testHookBootExit() { |
|
354 // Test with cache disabled. Boot and exit should always fire. |
|
355 variable_set('cache', 0); |
|
356 $this->drupalGet(''); |
|
357 $calls = 1; |
|
358 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with disabled cache.')); |
|
359 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with disabled cache.')); |
|
360 |
|
361 // Test with normal cache. Boot and exit should be called. |
|
362 variable_set('cache', 1); |
|
363 $this->drupalGet(''); |
|
364 $calls++; |
|
365 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with normal cache.')); |
|
366 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with normal cache.')); |
|
367 |
|
368 // Boot and exit should not fire since the page is cached. |
|
369 variable_set('page_cache_invoke_hooks', FALSE); |
|
370 $this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.')); |
|
371 $this->drupalGet(''); |
|
372 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot not called with aggressive cache and a cached page.')); |
|
373 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit not called with aggressive cache and a cached page.')); |
|
374 |
|
375 // Test with page cache cleared, boot and exit should be called. |
|
376 $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.')); |
|
377 $this->drupalGet(''); |
|
378 $calls++; |
|
379 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with aggressive cache and no cached page.')); |
|
380 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with aggressive cache and no cached page.')); |
|
381 } |
|
382 } |
|
383 |
|
384 /** |
|
385 * Test drupal_get_filename()'s availability. |
|
386 */ |
|
387 class BootstrapGetFilenameTestCase extends DrupalUnitTestCase { |
|
388 |
|
389 public static function getInfo() { |
|
390 return array( |
|
391 'name' => 'Get filename test (without the system table)', |
|
392 'description' => 'Test that drupal_get_filename() works correctly when the database is not available.', |
|
393 'group' => 'Bootstrap', |
|
394 ); |
|
395 } |
|
396 |
|
397 /** |
|
398 * The last file-related error message triggered by the filename test. |
|
399 * |
|
400 * Used by BootstrapGetFilenameTestCase::testDrupalGetFilename(). |
|
401 */ |
|
402 protected $getFilenameTestTriggeredError; |
|
403 |
|
404 /** |
|
405 * Test that drupal_get_filename() works correctly when the file is not found in the database. |
|
406 */ |
|
407 function testDrupalGetFilename() { |
|
408 // Reset the static cache so we can test the "db is not active" code of |
|
409 // drupal_get_filename(). |
|
410 drupal_static_reset('drupal_get_filename'); |
|
411 |
|
412 // Retrieving the location of a module. |
|
413 $this->assertIdentical(drupal_get_filename('module', 'php'), 'modules/php/php.module', t('Retrieve module location.')); |
|
414 |
|
415 // Retrieving the location of a theme. |
|
416 $this->assertIdentical(drupal_get_filename('theme', 'stark'), 'themes/stark/stark.info', t('Retrieve theme location.')); |
|
417 |
|
418 // Retrieving the location of a theme engine. |
|
419 $this->assertIdentical(drupal_get_filename('theme_engine', 'phptemplate'), 'themes/engines/phptemplate/phptemplate.engine', t('Retrieve theme engine location.')); |
|
420 |
|
421 // Retrieving the location of a profile. Profiles are a special case with |
|
422 // a fixed location and naming. |
|
423 $this->assertIdentical(drupal_get_filename('profile', 'standard'), 'profiles/standard/standard.profile', t('Retrieve install profile location.')); |
|
424 |
|
425 // When a file is not found in the database cache, drupal_get_filename() |
|
426 // searches several locations on the filesystem, including the DRUPAL_ROOT |
|
427 // directory. We use the '.script' extension below because this is a |
|
428 // non-existent filetype that will definitely not exist in the database. |
|
429 // Since there is already a scripts directory, drupal_get_filename() will |
|
430 // automatically check there for 'script' files, just as it does for (e.g.) |
|
431 // 'module' files in modules. |
|
432 $this->assertIdentical(drupal_get_filename('script', 'test'), 'scripts/test.script', t('Retrieve test script location.')); |
|
433 |
|
434 // When searching for a module that does not exist, drupal_get_filename() |
|
435 // should return NULL and trigger an appropriate error message. |
|
436 $this->getFilenameTestTriggeredError = NULL; |
|
437 set_error_handler(array($this, 'fileNotFoundErrorHandler')); |
|
438 $non_existing_module = $this->randomName(); |
|
439 $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that does not exist returns NULL.'); |
|
440 $this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) === 0, 'Searching for an item that does not exist triggers the correct error.'); |
|
441 restore_error_handler(); |
|
442 |
|
443 // Check that the result is stored in the file system scan cache. |
|
444 $file_scans = _drupal_file_scan_cache(); |
|
445 $this->assertIdentical($file_scans['module'][$non_existing_module], FALSE, 'Searching for a module that does not exist creates a record in the missing and moved files static variable.'); |
|
446 |
|
447 // Performing the search again in the same request still should not find |
|
448 // the file, but the error message should not be repeated (therefore we do |
|
449 // not override the error handler here). |
|
450 $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that does not exist returns NULL during the second search.'); |
|
451 } |
|
452 |
|
453 /** |
|
454 * Skips handling of "file not found" errors. |
|
455 */ |
|
456 public function fileNotFoundErrorHandler($error_level, $message, $filename, $line, $context) { |
|
457 // Skip error handling if this is a "file not found" error. |
|
458 if (strpos($message, 'is missing from the file system:') !== FALSE || strpos($message, 'has moved within the file system:') !== FALSE) { |
|
459 $this->getFilenameTestTriggeredError = $message; |
|
460 return; |
|
461 } |
|
462 _drupal_error_handler($error_level, $message, $filename, $line, $context); |
|
463 } |
|
464 } |
|
465 |
|
466 /** |
|
467 * Test drupal_get_filename() in the context of a full Drupal installation. |
|
468 */ |
|
469 class BootstrapGetFilenameWebTestCase extends DrupalWebTestCase { |
|
470 |
|
471 public static function getInfo() { |
|
472 return array( |
|
473 'name' => 'Get filename test (full installation)', |
|
474 'description' => 'Test that drupal_get_filename() works correctly in the context of a full Drupal installation.', |
|
475 'group' => 'Bootstrap', |
|
476 ); |
|
477 } |
|
478 |
|
479 function setUp() { |
|
480 parent::setUp('system_test'); |
|
481 } |
|
482 |
|
483 /** |
|
484 * The last file-related error message triggered by the filename test. |
|
485 * |
|
486 * Used by BootstrapGetFilenameWebTestCase::testDrupalGetFilename(). |
|
487 */ |
|
488 protected $getFilenameTestTriggeredError; |
|
489 |
|
490 /** |
|
491 * Test that drupal_get_filename() works correctly with a full Drupal site. |
|
492 */ |
|
493 function testDrupalGetFilename() { |
|
494 // Search for a module that exists in the file system and the {system} |
|
495 // table and make sure that it is found. |
|
496 $this->assertIdentical(drupal_get_filename('module', 'node'), 'modules/node/node.module', 'Module found at expected location.'); |
|
497 |
|
498 // Search for a module that does not exist in either the file system or the |
|
499 // {system} table. Make sure that an appropriate error is triggered and |
|
500 // that the module winds up in the static and persistent cache. |
|
501 $this->getFilenameTestTriggeredError = NULL; |
|
502 set_error_handler(array($this, 'fileNotFoundErrorHandler')); |
|
503 $non_existing_module = $this->randomName(); |
|
504 $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that does not exist returns NULL.'); |
|
505 $this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) === 0, 'Searching for a module that does not exist triggers the correct error.'); |
|
506 restore_error_handler(); |
|
507 $file_scans = _drupal_file_scan_cache(); |
|
508 $this->assertIdentical($file_scans['module'][$non_existing_module], FALSE, 'Searching for a module that does not exist creates a record in the missing and moved files static variable.'); |
|
509 drupal_file_scan_write_cache(); |
|
510 $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap'); |
|
511 $this->assertIdentical($cache->data['module'][$non_existing_module], FALSE, 'Searching for a module that does not exist creates a record in the missing and moved files persistent cache.'); |
|
512 |
|
513 // Simulate moving a module to a location that does not match the location |
|
514 // in the {system} table and perform similar tests as above. |
|
515 db_update('system') |
|
516 ->fields(array('filename' => 'modules/simpletest/tests/fake_location/module_test.module')) |
|
517 ->condition('name', 'module_test') |
|
518 ->condition('type', 'module') |
|
519 ->execute(); |
|
520 $this->getFilenameTestTriggeredError = NULL; |
|
521 set_error_handler(array($this, 'fileNotFoundErrorHandler')); |
|
522 $this->assertIdentical(drupal_get_filename('module', 'module_test'), 'modules/simpletest/tests/module_test.module', 'Searching for a module that has moved finds the module at its new location.'); |
|
523 $this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module has moved within the file system: %name', array('%name' => 'module_test'))) === 0, 'Searching for a module that has moved triggers the correct error.'); |
|
524 restore_error_handler(); |
|
525 $file_scans = _drupal_file_scan_cache(); |
|
526 $this->assertIdentical($file_scans['module']['module_test'], 'modules/simpletest/tests/module_test.module', 'Searching for a module that has moved creates a record in the missing and moved files static variable.'); |
|
527 drupal_file_scan_write_cache(); |
|
528 $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap'); |
|
529 $this->assertIdentical($cache->data['module']['module_test'], 'modules/simpletest/tests/module_test.module', 'Searching for a module that has moved creates a record in the missing and moved files persistent cache.'); |
|
530 |
|
531 // Simulate a module that exists in the {system} table but does not exist |
|
532 // in the file system and perform similar tests as above. |
|
533 $non_existing_module = $this->randomName(); |
|
534 db_update('system') |
|
535 ->fields(array('name' => $non_existing_module)) |
|
536 ->condition('name', 'module_test') |
|
537 ->condition('type', 'module') |
|
538 ->execute(); |
|
539 $this->getFilenameTestTriggeredError = NULL; |
|
540 set_error_handler(array($this, 'fileNotFoundErrorHandler')); |
|
541 $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that exists in the system table but not in the file system returns NULL.'); |
|
542 $this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) === 0, 'Searching for a module that exists in the system table but not in the file system triggers the correct error.'); |
|
543 restore_error_handler(); |
|
544 $file_scans = _drupal_file_scan_cache(); |
|
545 $this->assertIdentical($file_scans['module'][$non_existing_module], FALSE, 'Searching for a module that exists in the system table but not in the file system creates a record in the missing and moved files static variable.'); |
|
546 drupal_file_scan_write_cache(); |
|
547 $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap'); |
|
548 $this->assertIdentical($cache->data['module'][$non_existing_module], FALSE, 'Searching for a module that exists in the system table but not in the file system creates a record in the missing and moved files persistent cache.'); |
|
549 |
|
550 // Simulate a module that exists in the file system but not in the {system} |
|
551 // table and perform similar tests as above. |
|
552 db_delete('system') |
|
553 ->condition('name', 'common_test') |
|
554 ->condition('type', 'module') |
|
555 ->execute(); |
|
556 system_list_reset(); |
|
557 $this->getFilenameTestTriggeredError = NULL; |
|
558 set_error_handler(array($this, 'fileNotFoundErrorHandler')); |
|
559 $this->assertIdentical(drupal_get_filename('module', 'common_test'), 'modules/simpletest/tests/common_test.module', 'Searching for a module that does not exist in the system table finds the module at its actual location.'); |
|
560 $this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module has moved within the file system: %name', array('%name' => 'common_test'))) === 0, 'Searching for a module that does not exist in the system table triggers the correct error.'); |
|
561 restore_error_handler(); |
|
562 $file_scans = _drupal_file_scan_cache(); |
|
563 $this->assertIdentical($file_scans['module']['common_test'], 'modules/simpletest/tests/common_test.module', 'Searching for a module that does not exist in the system table creates a record in the missing and moved files static variable.'); |
|
564 drupal_file_scan_write_cache(); |
|
565 $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap'); |
|
566 $this->assertIdentical($cache->data['module']['common_test'], 'modules/simpletest/tests/common_test.module', 'Searching for a module that does not exist in the system table creates a record in the missing and moved files persistent cache.'); |
|
567 } |
|
568 |
|
569 /** |
|
570 * Skips handling of "file not found" errors. |
|
571 */ |
|
572 public function fileNotFoundErrorHandler($error_level, $message, $filename, $line, $context) { |
|
573 // Skip error handling if this is a "file not found" error. |
|
574 if (strpos($message, 'is missing from the file system:') !== FALSE || strpos($message, 'has moved within the file system:') !== FALSE) { |
|
575 $this->getFilenameTestTriggeredError = $message; |
|
576 return; |
|
577 } |
|
578 _drupal_error_handler($error_level, $message, $filename, $line, $context); |
|
579 } |
|
580 |
|
581 /** |
|
582 * Test that watchdog messages about missing files are correctly recorded. |
|
583 */ |
|
584 public function testWatchdog() { |
|
585 // Search for a module that does not exist in either the file system or the |
|
586 // {system} table. Make sure that an appropriate warning is recorded in the |
|
587 // logs. |
|
588 $non_existing_module = $this->randomName(); |
|
589 $query_parameters = array( |
|
590 ':type' => 'php', |
|
591 ':severity' => WATCHDOG_WARNING, |
|
592 ); |
|
593 $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND severity = :severity', $query_parameters)->fetchField(), 0, 'No warning message appears in the logs before searching for a module that does not exist.'); |
|
594 // Trigger the drupal_get_filename() call. This must be done via a request |
|
595 // to a separate URL since the watchdog() will happen in a shutdown |
|
596 // function, and so that SimpleTest can be told to ignore (and not fail as |
|
597 // a result of) the expected PHP warnings generated during this process. |
|
598 variable_set('system_test_drupal_get_filename_test_module_name', $non_existing_module); |
|
599 $this->drupalGet('system-test/drupal-get-filename'); |
|
600 $message_variables = db_query('SELECT variables FROM {watchdog} WHERE type = :type AND severity = :severity', $query_parameters)->fetchCol(); |
|
601 $this->assertEqual(count($message_variables), 1, 'A single warning message appears in the logs after searching for a module that does not exist.'); |
|
602 $variables = reset($message_variables); |
|
603 $variables = unserialize($variables); |
|
604 $this->assertTrue(isset($variables['!message']) && strpos($variables['!message'], format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) !== FALSE, 'The warning message that appears in the logs after searching for a module that does not exist contains the expected text.'); |
|
605 } |
|
606 |
|
607 /** |
|
608 * Test that drupal_get_filename() does not break recursive rebuilds. |
|
609 */ |
|
610 public function testRecursiveRebuilds() { |
|
611 // Ensure that the drupal_get_filename() call due to a missing module does |
|
612 // not break the data returned by an attempted recursive rebuild. The code |
|
613 // path which is tested is as follows: |
|
614 // - Call drupal_get_schema(). |
|
615 // - Within a hook_schema() implementation, trigger a drupal_get_filename() |
|
616 // search for a nonexistent module. |
|
617 // - In the watchdog() call that results from that, trigger |
|
618 // drupal_get_schema() again. |
|
619 // Without some kind of recursion protection, this could cause the second |
|
620 // drupal_get_schema() call to return incomplete results. This test ensures |
|
621 // that does not happen. |
|
622 $non_existing_module = $this->randomName(); |
|
623 variable_set('system_test_drupal_get_filename_test_module_name', $non_existing_module); |
|
624 $this->drupalGet('system-test/drupal-get-filename-with-schema-rebuild'); |
|
625 $original_drupal_get_schema_tables = variable_get('system_test_drupal_get_filename_with_schema_rebuild_original_tables'); |
|
626 $final_drupal_get_schema_tables = variable_get('system_test_drupal_get_filename_with_schema_rebuild_final_tables'); |
|
627 $this->assertTrue(!empty($original_drupal_get_schema_tables)); |
|
628 $this->assertTrue(!empty($final_drupal_get_schema_tables)); |
|
629 $this->assertEqual($original_drupal_get_schema_tables, $final_drupal_get_schema_tables); |
|
630 } |
|
631 } |
|
632 |
|
633 class BootstrapTimerTestCase extends DrupalUnitTestCase { |
|
634 |
|
635 public static function getInfo() { |
|
636 return array( |
|
637 'name' => 'Timer test', |
|
638 'description' => 'Test that timer_read() works both when a timer is running and when a timer is stopped.', |
|
639 'group' => 'Bootstrap', |
|
640 ); |
|
641 } |
|
642 |
|
643 /** |
|
644 * Test timer_read() to ensure it properly accumulates time when the timer |
|
645 * started and stopped multiple times. |
|
646 * @return |
|
647 */ |
|
648 function testTimer() { |
|
649 timer_start('test'); |
|
650 sleep(1); |
|
651 $this->assertTrue(timer_read('test') >= 1000, 'Timer measured 1 second of sleeping while running.'); |
|
652 sleep(1); |
|
653 timer_stop('test'); |
|
654 $this->assertTrue(timer_read('test') >= 2000, 'Timer measured 2 seconds of sleeping after being stopped.'); |
|
655 timer_start('test'); |
|
656 sleep(1); |
|
657 $this->assertTrue(timer_read('test') >= 3000, 'Timer measured 3 seconds of sleeping after being restarted.'); |
|
658 sleep(1); |
|
659 $timer = timer_stop('test'); |
|
660 $this->assertTrue(timer_read('test') >= 4000, 'Timer measured 4 seconds of sleeping after being stopped for a second time.'); |
|
661 $this->assertEqual($timer['count'], 2, 'Timer counted 2 instances of being started.'); |
|
662 } |
|
663 } |
|
664 |
|
665 /** |
|
666 * Test that resetting static variables works. |
|
667 */ |
|
668 class BootstrapResettableStaticTestCase extends DrupalUnitTestCase { |
|
669 |
|
670 public static function getInfo() { |
|
671 return array( |
|
672 'name' => 'Resettable static variables test', |
|
673 'description' => 'Test that drupal_static() and drupal_static_reset() work.', |
|
674 'group' => 'Bootstrap', |
|
675 ); |
|
676 } |
|
677 |
|
678 /** |
|
679 * Test that a variable reference returned by drupal_static() gets reset when |
|
680 * drupal_static_reset() is called. |
|
681 */ |
|
682 function testDrupalStatic() { |
|
683 $name = __CLASS__ . '_' . __METHOD__; |
|
684 $var = &drupal_static($name, 'foo'); |
|
685 $this->assertEqual($var, 'foo', 'Variable returned by drupal_static() was set to its default.'); |
|
686 |
|
687 // Call the specific reset and the global reset each twice to ensure that |
|
688 // multiple resets can be issued without odd side effects. |
|
689 $var = 'bar'; |
|
690 drupal_static_reset($name); |
|
691 $this->assertEqual($var, 'foo', 'Variable was reset after first invocation of name-specific reset.'); |
|
692 $var = 'bar'; |
|
693 drupal_static_reset($name); |
|
694 $this->assertEqual($var, 'foo', 'Variable was reset after second invocation of name-specific reset.'); |
|
695 $var = 'bar'; |
|
696 drupal_static_reset(); |
|
697 $this->assertEqual($var, 'foo', 'Variable was reset after first invocation of global reset.'); |
|
698 $var = 'bar'; |
|
699 drupal_static_reset(); |
|
700 $this->assertEqual($var, 'foo', 'Variable was reset after second invocation of global reset.'); |
|
701 } |
|
702 } |
|
703 |
|
704 /** |
|
705 * Test miscellaneous functions in bootstrap.inc. |
|
706 */ |
|
707 class BootstrapMiscTestCase extends DrupalUnitTestCase { |
|
708 |
|
709 public static function getInfo() { |
|
710 return array( |
|
711 'name' => 'Miscellaneous bootstrap unit tests', |
|
712 'description' => 'Test miscellaneous functions in bootstrap.inc.', |
|
713 'group' => 'Bootstrap', |
|
714 ); |
|
715 } |
|
716 |
|
717 /** |
|
718 * Test miscellaneous functions in bootstrap.inc. |
|
719 */ |
|
720 function testMisc() { |
|
721 // Test drupal_array_merge_deep(). |
|
722 $link_options_1 = array('fragment' => 'x', 'attributes' => array('title' => 'X', 'class' => array('a', 'b')), 'language' => 'en'); |
|
723 $link_options_2 = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('c', 'd')), 'html' => TRUE); |
|
724 $expected = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('a', 'b', 'c', 'd')), 'language' => 'en', 'html' => TRUE); |
|
725 $this->assertIdentical(drupal_array_merge_deep($link_options_1, $link_options_2), $expected, 'drupal_array_merge_deep() returned a properly merged array.'); |
|
726 } |
|
727 |
|
728 /** |
|
729 * Tests that the drupal_check_memory_limit() function works as expected. |
|
730 */ |
|
731 function testCheckMemoryLimit() { |
|
732 $memory_limit = ini_get('memory_limit'); |
|
733 // Test that a very reasonable amount of memory is available. |
|
734 $this->assertTrue(drupal_check_memory_limit('30MB'), '30MB of memory tested available.'); |
|
735 |
|
736 // Get the available memory and multiply it by two to make it unreasonably |
|
737 // high. |
|
738 $twice_avail_memory = ($memory_limit * 2) . 'MB'; |
|
739 |
|
740 // The function should always return true if the memory limit is set to -1. |
|
741 $this->assertTrue(drupal_check_memory_limit($twice_avail_memory, -1), 'drupal_check_memory_limit() returns TRUE when a limit of -1 (none) is supplied'); |
|
742 |
|
743 // Test that even though we have 30MB of memory available - the function |
|
744 // returns FALSE when given an upper limit for how much memory can be used. |
|
745 $this->assertFalse(drupal_check_memory_limit('30MB', '16MB'), 'drupal_check_memory_limit() returns FALSE with a 16MB upper limit on a 30MB requirement.'); |
|
746 |
|
747 // Test that an equal amount of memory to the amount requested returns TRUE. |
|
748 $this->assertTrue(drupal_check_memory_limit('30MB', '30MB'), 'drupal_check_memory_limit() returns TRUE when requesting 30MB on a 30MB requirement.'); |
|
749 } |
|
750 } |
|
751 |
|
752 /** |
|
753 * Tests for overriding server variables via the API. |
|
754 */ |
|
755 class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase { |
|
756 public static function getInfo() { |
|
757 return array( |
|
758 'name' => 'Overriding server variables', |
|
759 'description' => 'Test that drupal_override_server_variables() works correctly.', |
|
760 'group' => 'Bootstrap', |
|
761 ); |
|
762 } |
|
763 |
|
764 /** |
|
765 * Test providing a direct URL to to drupal_override_server_variables(). |
|
766 */ |
|
767 function testDrupalOverrideServerVariablesProvidedURL() { |
|
768 $tests = array( |
|
769 'http://example.com' => array( |
|
770 'HTTP_HOST' => 'example.com', |
|
771 'SCRIPT_NAME' => isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL, |
|
772 ), |
|
773 'http://example.com/index.php' => array( |
|
774 'HTTP_HOST' => 'example.com', |
|
775 'SCRIPT_NAME' => '/index.php', |
|
776 ), |
|
777 'http://example.com/subdirectory/index.php' => array( |
|
778 'HTTP_HOST' => 'example.com', |
|
779 'SCRIPT_NAME' => '/subdirectory/index.php', |
|
780 ), |
|
781 ); |
|
782 foreach ($tests as $url => $expected_server_values) { |
|
783 // Remember the original value of $_SERVER, since the function call below |
|
784 // will modify it. |
|
785 $original_server = $_SERVER; |
|
786 // Call drupal_override_server_variables() and ensure that all expected |
|
787 // $_SERVER variables were modified correctly. |
|
788 drupal_override_server_variables(array('url' => $url)); |
|
789 foreach ($expected_server_values as $key => $value) { |
|
790 $this->assertIdentical($_SERVER[$key], $value); |
|
791 } |
|
792 // Restore the original value of $_SERVER. |
|
793 $_SERVER = $original_server; |
|
794 } |
|
795 } |
|
796 } |
|
797 |
|
798 /** |
|
799 * Tests for $_GET['destination'] and $_REQUEST['destination'] validation. |
|
800 */ |
|
801 class BootstrapDestinationTestCase extends DrupalWebTestCase { |
|
802 |
|
803 public static function getInfo() { |
|
804 return array( |
|
805 'name' => 'URL destination validation', |
|
806 'description' => 'Test that $_GET[\'destination\'] and $_REQUEST[\'destination\'] cannot contain external URLs.', |
|
807 'group' => 'Bootstrap', |
|
808 ); |
|
809 } |
|
810 |
|
811 function setUp() { |
|
812 parent::setUp('system_test'); |
|
813 } |
|
814 |
|
815 /** |
|
816 * Tests that $_GET/$_REQUEST['destination'] only contain internal URLs. |
|
817 * |
|
818 * @see _drupal_bootstrap_variables() |
|
819 * @see system_test_get_destination() |
|
820 * @see system_test_request_destination() |
|
821 */ |
|
822 public function testDestination() { |
|
823 $test_cases = array( |
|
824 array( |
|
825 'input' => 'node', |
|
826 'output' => 'node', |
|
827 'message' => "Standard internal example node path is present in the 'destination' parameter.", |
|
828 ), |
|
829 array( |
|
830 'input' => '/example.com', |
|
831 'output' => '/example.com', |
|
832 'message' => 'Internal path with one leading slash is allowed.', |
|
833 ), |
|
834 array( |
|
835 'input' => '//example.com/test', |
|
836 'output' => '', |
|
837 'message' => 'External URL without scheme is not allowed.', |
|
838 ), |
|
839 array( |
|
840 'input' => 'example:test', |
|
841 'output' => 'example:test', |
|
842 'message' => 'Internal URL using a colon is allowed.', |
|
843 ), |
|
844 array( |
|
845 'input' => 'http://example.com', |
|
846 'output' => '', |
|
847 'message' => 'External URL is not allowed.', |
|
848 ), |
|
849 array( |
|
850 'input' => 'javascript:alert(0)', |
|
851 'output' => 'javascript:alert(0)', |
|
852 'message' => 'Javascript URL is allowed because it is treated as an internal URL.', |
|
853 ), |
|
854 ); |
|
855 foreach ($test_cases as $test_case) { |
|
856 // Test $_GET['destination']. |
|
857 $this->drupalGet('system-test/get-destination', array('query' => array('destination' => $test_case['input']))); |
|
858 $this->assertIdentical($test_case['output'], $this->drupalGetContent(), $test_case['message']); |
|
859 // Test $_REQUEST['destination']. There's no form to submit to, so |
|
860 // drupalPost() won't work here; this just tests a direct $_POST request |
|
861 // instead. |
|
862 $curl_parameters = array( |
|
863 CURLOPT_URL => $this->getAbsoluteUrl('system-test/request-destination'), |
|
864 CURLOPT_POST => TRUE, |
|
865 CURLOPT_POSTFIELDS => 'destination=' . urlencode($test_case['input']), |
|
866 CURLOPT_HTTPHEADER => array(), |
|
867 ); |
|
868 $post_output = $this->curlExec($curl_parameters); |
|
869 $this->assertIdentical($test_case['output'], $post_output, $test_case['message']); |
|
870 } |
|
871 |
|
872 // Make sure that 404 pages do not populate $_GET['destination'] with |
|
873 // external URLs. |
|
874 variable_set('site_404', 'system-test/get-destination'); |
|
875 $this->drupalGet('http://example.com', array('external' => FALSE)); |
|
876 $this->assertIdentical('', $this->drupalGetContent(), 'External URL is not allowed on 404 pages.'); |
|
877 } |
|
878 } |