Projet

Général

Profil

Paste
Télécharger (28,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / simpletest / tests / bootstrap.test @ 1afa1695

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
    // Multi-tier architecture with comma separated values in header.
74
    $_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
75
    $_SERVER['HTTP_X_FORWARDED_FOR'] = implode(', ', array($this->untrusted_ip, $this->forwarded_ip, $this->proxy2_ip));
76
    drupal_static_reset('ip_address');
77
    $this->assertTrue(
78
      ip_address() == $this->forwarded_ip,
79
      'Proxy forwarding with trusted 2-tier proxy got forwarded IP address.'
80
    );
81

    
82
    // Custom client-IP header.
83
    variable_set('reverse_proxy_header', 'HTTP_X_CLUSTER_CLIENT_IP');
84
    $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] = $this->cluster_ip;
85
    drupal_static_reset('ip_address');
86
    $this->assertTrue(
87
      ip_address() == $this->cluster_ip,
88
      'Cluster environment got cluster client IP.'
89
    );
90

    
91
    // Verifies that drupal_valid_http_host() prevents invalid characters.
92
    $this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), 'HTTP_HOST with / is invalid');
93
    $this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid');
94
    $this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with &lt; is invalid');
95
    $this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid');
96
    // Verifies that host names are shorter than 1000 characters.
97
    $this->assertFalse(drupal_valid_http_host(str_repeat('x', 1001)), 'HTTP_HOST with more than 1000 characters is invalid.');
98
    $this->assertFalse(drupal_valid_http_host(str_repeat('.', 101)), 'HTTP_HOST with more than 100 subdomains is invalid.');
99
    $this->assertFalse(drupal_valid_http_host(str_repeat(':', 101)), 'HTTP_HOST with more than 100 portseparators is invalid.');
100

    
101
    // IPv6 loopback address
102
    $this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid');
103
  }
104
}
105

    
106
class BootstrapPageCacheTestCase extends DrupalWebTestCase {
107

    
108
  public static function getInfo() {
109
    return array(
110
      'name' => 'Page cache test',
111
      'description' => 'Enable the page cache and test it with various HTTP requests.',
112
      'group' => 'Bootstrap'
113
    );
114
  }
115

    
116
  function setUp() {
117
    parent::setUp('system_test');
118
  }
119

    
120
  /**
121
   * Test support for requests containing If-Modified-Since and If-None-Match headers.
122
   */
123
  function testConditionalRequests() {
124
    variable_set('cache', 1);
125

    
126
    // Fill the cache.
127
    $this->drupalGet('');
128

    
129
    $this->drupalHead('');
130
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
131
    $etag = $this->drupalGetHeader('ETag');
132
    $last_modified = $this->drupalGetHeader('Last-Modified');
133

    
134
    $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
135
    $this->assertResponse(304, 'Conditional request returned 304 Not Modified.');
136

    
137
    $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC822, strtotime($last_modified)), 'If-None-Match: ' . $etag));
138
    $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
139

    
140
    $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC850, strtotime($last_modified)), 'If-None-Match: ' . $etag));
141
    $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
142

    
143
    $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified));
144
    $this->assertResponse(200, 'Conditional request without If-None-Match returned 200 OK.');
145
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
146

    
147
    $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC7231, strtotime($last_modified) + 1), 'If-None-Match: ' . $etag));
148
    $this->assertResponse(200, 'Conditional request with new a If-Modified-Since date newer than Last-Modified returned 200 OK.');
149
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
150

    
151
    $user = $this->drupalCreateUser();
152
    $this->drupalLogin($user);
153
    $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
154
    $this->assertResponse(200, 'Conditional request returned 200 OK for authenticated user.');
155
    $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Absense of Page was not cached.');
156
    $this->assertFalse($this->drupalGetHeader('ETag'), 'ETag HTTP headers are not present for logged in users.');
157
    $this->assertFalse($this->drupalGetHeader('Last-Modified'), 'Last-Modified HTTP headers are not present for logged in users.');
158
  }
159

    
160
  /**
161
   * Test cache headers.
162
   */
163
  function testPageCache() {
164
    variable_set('cache', 1);
165

    
166
    // Fill the cache.
167
    $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
168
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
169
    $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary header was sent.');
170
    $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.');
171
    $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
172
    $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
173

    
174
    // Check cache.
175
    $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
176
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
177
    $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary: Cookie header was sent.');
178
    $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.');
179
    $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
180
    $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
181

    
182
    // Check replacing default headers.
183
    $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT')));
184
    $this->assertEqual($this->drupalGetHeader('Expires'), 'Fri, 19 Nov 2008 05:00:00 GMT', 'Default header was replaced.');
185
    $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Vary', 'value' => 'User-Agent')));
186
    $this->assertEqual($this->drupalGetHeader('Vary'), 'User-Agent,Accept-Encoding', 'Default header was replaced.');
187

    
188
    // Check that authenticated users bypass the cache.
189
    $user = $this->drupalCreateUser();
190
    $this->drupalLogin($user);
191
    $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
192
    $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.');
193
    $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
194
    $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', 'Cache-Control header was sent.');
195
    $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
196
    $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
197

    
198
  }
199

    
200
  /**
201
   * Test page compression.
202
   *
203
   * The test should pass even if zlib.output_compression is enabled in php.ini,
204
   * .htaccess or similar, or if compression is done outside PHP, e.g. by the
205
   * mod_deflate Apache module.
206
   */
207
  function testPageCompression() {
208
    variable_set('cache', 1);
209

    
210
    // Fill the cache and verify that output is compressed.
211
    $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
212
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
213
    $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
214
    $this->assertRaw('</html>', 'Page was gzip compressed.');
215

    
216
    // Verify that cached output is compressed.
217
    $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
218
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
219
    $this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', 'A Content-Encoding header was sent.');
220
    $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
221
    $this->assertRaw('</html>', 'Page was gzip compressed.');
222

    
223
    // Verify that a client without compression support gets an uncompressed page.
224
    $this->drupalGet('');
225
    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
226
    $this->assertFalse($this->drupalGetHeader('Content-Encoding'), 'A Content-Encoding header was not sent.');
227
    $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.');
228
    $this->assertRaw('</html>', 'Page was not compressed.');
229

    
230
    // Disable compression mode.
231
    variable_set('page_compression', FALSE);
232

    
233
    // Verify if cached page is still available for a client with compression support.
234
    $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
235
    $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
236
    $this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support enabled).');
237

    
238
    // Verify if cached page is still available for a client without compression support.
239
    $this->drupalGet('');
240
    $this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support disabled).');
241
  }
242
}
243

    
244
class BootstrapVariableTestCase extends DrupalWebTestCase {
245

    
246
  function setUp() {
247
    parent::setUp('system_test');
248
  }
249

    
250
  public static function getInfo() {
251
    return array(
252
      'name' => 'Variable test',
253
      'description' => 'Make sure the variable system functions correctly.',
254
      'group' => 'Bootstrap'
255
    );
256
  }
257

    
258
  /**
259
   * testVariable
260
   */
261
  function testVariable() {
262
    // Setting and retrieving values.
263
    $variable = $this->randomName();
264
    variable_set('simpletest_bootstrap_variable_test', $variable);
265
    $this->assertIdentical($variable, variable_get('simpletest_bootstrap_variable_test'), 'Setting and retrieving values');
266

    
267
    // Make sure the variable persists across multiple requests.
268
    $this->drupalGet('system-test/variable-get');
269
    $this->assertText($variable, 'Variable persists across multiple requests');
270

    
271
    // Deleting variables.
272
    $default_value = $this->randomName();
273
    variable_del('simpletest_bootstrap_variable_test');
274
    $variable = variable_get('simpletest_bootstrap_variable_test', $default_value);
275
    $this->assertIdentical($variable, $default_value, 'Deleting variables');
276
  }
277

    
278
  /**
279
   * Makes sure that the default variable parameter is passed through okay.
280
   */
281
  function testVariableDefaults() {
282
    // Tests passing nothing through to the default.
283
    $this->assertIdentical(NULL, variable_get('simpletest_bootstrap_variable_test'), 'Variables are correctly defaulting to NULL.');
284

    
285
    // Tests passing 5 to the default parameter.
286
    $this->assertIdentical(5, variable_get('simpletest_bootstrap_variable_test', 5), 'The default variable parameter is passed through correctly.');
287
  }
288

    
289
}
290

    
291
/**
292
 * Tests the auto-loading behavior of the code registry.
293
 */
294
class BootstrapAutoloadTestCase extends DrupalWebTestCase {
295

    
296
  public static function getInfo() {
297
    return array(
298
      'name' => 'Code registry',
299
      'description' => 'Test that the code registry functions correctly.',
300
      'group' => 'Bootstrap',
301
    );
302
  }
303

    
304
  function setUp() {
305
    parent::setUp('drupal_autoload_test');
306
  }
307

    
308
  /**
309
   * Tests that autoloader name matching is not case sensitive.
310
   */
311
  function testAutoloadCase() {
312
    // Test interface autoloader.
313
    $this->assertTrue(drupal_autoload_interface('drupalautoloadtestinterface'), 'drupal_autoload_interface() recognizes <em>DrupalAutoloadTestInterface</em> in lower case.');
314
    // Test class autoloader.
315
    $this->assertTrue(drupal_autoload_class('drupalautoloadtestclass'), 'drupal_autoload_class() recognizes <em>DrupalAutoloadTestClass</em> in lower case.');
316
  }
317

    
318
}
319

    
320
/**
321
 * Test hook_boot() and hook_exit().
322
 */
323
class HookBootExitTestCase extends DrupalWebTestCase {
324

    
325
  public static function getInfo() {
326
    return array(
327
      'name' => 'Boot and exit hook invocation',
328
      'description' => 'Test that hook_boot() and hook_exit() are called correctly.',
329
      'group' => 'Bootstrap',
330
    );
331
  }
332

    
333
  function setUp() {
334
    parent::setUp('system_test', 'dblog');
335
  }
336

    
337
  /**
338
   * Test calling of hook_boot() and hook_exit().
339
   */
340
  function testHookBootExit() {
341
    // Test with cache disabled. Boot and exit should always fire.
342
    variable_set('cache', 0);
343
    $this->drupalGet('');
344
    $calls = 1;
345
    $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.'));
346
    $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.'));
347

    
348
    // Test with normal cache. Boot and exit should be called.
349
    variable_set('cache', 1);
350
    $this->drupalGet('');
351
    $calls++;
352
    $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.'));
353
    $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.'));
354

    
355
    // Boot and exit should not fire since the page is cached.
356
    variable_set('page_cache_invoke_hooks', FALSE);
357
    $this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
358
    $this->drupalGet('');
359
    $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.'));
360
    $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.'));
361

    
362
    // Test with page cache cleared, boot and exit should be called.
363
    $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
364
    $this->drupalGet('');
365
    $calls++;
366
    $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.'));
367
    $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.'));
368
  }
369
}
370

    
371
/**
372
 * Test drupal_get_filename()'s availability.
373
 */
374
class BootstrapGetFilenameTestCase extends DrupalUnitTestCase {
375

    
376
  public static function getInfo() {
377
    return array(
378
      'name' => 'Get filename test',
379
      'description' => 'Test that drupal_get_filename() works correctly when the file is not found in the database.',
380
      'group' => 'Bootstrap',
381
    );
382
  }
383

    
384
  /**
385
   * Test that drupal_get_filename() works correctly when the file is not found in the database.
386
   */
387
  function testDrupalGetFilename() {
388
    // Reset the static cache so we can test the "db is not active" code of
389
    // drupal_get_filename().
390
    drupal_static_reset('drupal_get_filename');
391

    
392
    // Retrieving the location of a module.
393
    $this->assertIdentical(drupal_get_filename('module', 'php'), 'modules/php/php.module', t('Retrieve module location.'));
394

    
395
    // Retrieving the location of a theme.
396
    $this->assertIdentical(drupal_get_filename('theme', 'stark'), 'themes/stark/stark.info', t('Retrieve theme location.'));
397

    
398
    // Retrieving the location of a theme engine.
399
    $this->assertIdentical(drupal_get_filename('theme_engine', 'phptemplate'), 'themes/engines/phptemplate/phptemplate.engine', t('Retrieve theme engine location.'));
400

    
401
    // Retrieving the location of a profile. Profiles are a special case with
402
    // a fixed location and naming.
403
    $this->assertIdentical(drupal_get_filename('profile', 'standard'), 'profiles/standard/standard.profile', t('Retrieve install profile location.'));
404

    
405
    // When a file is not found in the database cache, drupal_get_filename()
406
    // searches several locations on the filesystem, including the DRUPAL_ROOT
407
    // directory. We use the '.script' extension below because this is a
408
    // non-existent filetype that will definitely not exist in the database.
409
    // Since there is already a scripts directory, drupal_get_filename() will
410
    // automatically check there for 'script' files, just as it does for (e.g.)
411
    // 'module' files in modules.
412
    $this->assertIdentical(drupal_get_filename('script', 'test'), 'scripts/test.script', t('Retrieve test script location.'));
413
  }
414
}
415

    
416
class BootstrapTimerTestCase extends DrupalUnitTestCase {
417

    
418
  public static function getInfo() {
419
    return array(
420
      'name' => 'Timer test',
421
      'description' => 'Test that timer_read() works both when a timer is running and when a timer is stopped.',
422
      'group' => 'Bootstrap',
423
    );
424
  }
425

    
426
  /**
427
   * Test timer_read() to ensure it properly accumulates time when the timer
428
   * started and stopped multiple times.
429
   * @return
430
   */
431
  function testTimer() {
432
    timer_start('test');
433
    sleep(1);
434
    $this->assertTrue(timer_read('test') >= 1000, 'Timer measured 1 second of sleeping while running.');
435
    sleep(1);
436
    timer_stop('test');
437
    $this->assertTrue(timer_read('test') >= 2000, 'Timer measured 2 seconds of sleeping after being stopped.');
438
    timer_start('test');
439
    sleep(1);
440
    $this->assertTrue(timer_read('test') >= 3000, 'Timer measured 3 seconds of sleeping after being restarted.');
441
    sleep(1);
442
    $timer = timer_stop('test');
443
    $this->assertTrue(timer_read('test') >= 4000, 'Timer measured 4 seconds of sleeping after being stopped for a second time.');
444
    $this->assertEqual($timer['count'], 2, 'Timer counted 2 instances of being started.');
445
  }
446
}
447

    
448
/**
449
 * Test that resetting static variables works.
450
 */
451
class BootstrapResettableStaticTestCase extends DrupalUnitTestCase {
452

    
453
  public static function getInfo() {
454
    return array(
455
      'name' => 'Resettable static variables test',
456
      'description' => 'Test that drupal_static() and drupal_static_reset() work.',
457
      'group' => 'Bootstrap',
458
    );
459
  }
460

    
461
  /**
462
   * Test that a variable reference returned by drupal_static() gets reset when
463
   * drupal_static_reset() is called.
464
   */
465
  function testDrupalStatic() {
466
    $name = __CLASS__ . '_' . __METHOD__;
467
    $var = &drupal_static($name, 'foo');
468
    $this->assertEqual($var, 'foo', 'Variable returned by drupal_static() was set to its default.');
469

    
470
    // Call the specific reset and the global reset each twice to ensure that
471
    // multiple resets can be issued without odd side effects.
472
    $var = 'bar';
473
    drupal_static_reset($name);
474
    $this->assertEqual($var, 'foo', 'Variable was reset after first invocation of name-specific reset.');
475
    $var = 'bar';
476
    drupal_static_reset($name);
477
    $this->assertEqual($var, 'foo', 'Variable was reset after second invocation of name-specific reset.');
478
    $var = 'bar';
479
    drupal_static_reset();
480
    $this->assertEqual($var, 'foo', 'Variable was reset after first invocation of global reset.');
481
    $var = 'bar';
482
    drupal_static_reset();
483
    $this->assertEqual($var, 'foo', 'Variable was reset after second invocation of global reset.');
484
  }
485
}
486

    
487
/**
488
 * Test miscellaneous functions in bootstrap.inc.
489
 */
490
class BootstrapMiscTestCase extends DrupalUnitTestCase {
491

    
492
  public static function getInfo() {
493
    return array(
494
      'name' => 'Miscellaneous bootstrap unit tests',
495
      'description' => 'Test miscellaneous functions in bootstrap.inc.',
496
      'group' => 'Bootstrap',
497
    );
498
  }
499

    
500
  /**
501
   * Test miscellaneous functions in bootstrap.inc.
502
   */
503
  function testMisc() {
504
    // Test drupal_array_merge_deep().
505
    $link_options_1 = array('fragment' => 'x', 'attributes' => array('title' => 'X', 'class' => array('a', 'b')), 'language' => 'en');
506
    $link_options_2 = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('c', 'd')), 'html' => TRUE);
507
    $expected = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('a', 'b', 'c', 'd')), 'language' => 'en', 'html' => TRUE);
508
    $this->assertIdentical(drupal_array_merge_deep($link_options_1, $link_options_2), $expected, 'drupal_array_merge_deep() returned a properly merged array.');
509
  }
510

    
511
  /**
512
   * Tests that the drupal_check_memory_limit() function works as expected.
513
   */
514
  function testCheckMemoryLimit() {
515
    $memory_limit = ini_get('memory_limit');
516
    // Test that a very reasonable amount of memory is available.
517
    $this->assertTrue(drupal_check_memory_limit('30MB'), '30MB of memory tested available.');
518

    
519
    // Get the available memory and multiply it by two to make it unreasonably
520
    // high.
521
    $twice_avail_memory = ($memory_limit * 2) . 'MB';
522

    
523
    // The function should always return true if the memory limit is set to -1.
524
    $this->assertTrue(drupal_check_memory_limit($twice_avail_memory, -1), 'drupal_check_memory_limit() returns TRUE when a limit of -1 (none) is supplied');
525

    
526
    // Test that even though we have 30MB of memory available - the function
527
    // returns FALSE when given an upper limit for how much memory can be used.
528
    $this->assertFalse(drupal_check_memory_limit('30MB', '16MB'), 'drupal_check_memory_limit() returns FALSE with a 16MB upper limit on a 30MB requirement.');
529

    
530
    // Test that an equal amount of memory to the amount requested returns TRUE.
531
    $this->assertTrue(drupal_check_memory_limit('30MB', '30MB'), 'drupal_check_memory_limit() returns TRUE when requesting 30MB on a 30MB requirement.');
532
  }
533
}
534

    
535
/**
536
 * Tests for overriding server variables via the API.
537
 */
538
class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase {
539
  public static function getInfo() {
540
    return array(
541
      'name' => 'Overriding server variables',
542
      'description' => 'Test that drupal_override_server_variables() works correctly.',
543
      'group' => 'Bootstrap',
544
    );
545
  }
546

    
547
  /**
548
   * Test providing a direct URL to to drupal_override_server_variables().
549
   */
550
  function testDrupalOverrideServerVariablesProvidedURL() {
551
    $tests = array(
552
      'http://example.com' => array(
553
        'HTTP_HOST' => 'example.com',
554
        'SCRIPT_NAME' => isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL,
555
      ),
556
      'http://example.com/index.php' => array(
557
        'HTTP_HOST' => 'example.com',
558
        'SCRIPT_NAME' => '/index.php',
559
      ),
560
      'http://example.com/subdirectory/index.php' => array(
561
        'HTTP_HOST' => 'example.com',
562
        'SCRIPT_NAME' => '/subdirectory/index.php',
563
      ),
564
    );
565
    foreach ($tests as $url => $expected_server_values) {
566
      // Remember the original value of $_SERVER, since the function call below
567
      // will modify it.
568
      $original_server = $_SERVER;
569
      // Call drupal_override_server_variables() and ensure that all expected
570
      // $_SERVER variables were modified correctly.
571
      drupal_override_server_variables(array('url' => $url));
572
      foreach ($expected_server_values as $key => $value) {
573
        $this->assertIdentical($_SERVER[$key], $value);
574
      }
575
      // Restore the original value of $_SERVER.
576
      $_SERVER = $original_server;
577
    }
578
  }
579
}
580

    
581
/**
582
 * Tests for $_GET['destination'] and $_REQUEST['destination'] validation.
583
 */
584
class BootstrapDestinationTestCase extends DrupalWebTestCase {
585

    
586
  public static function getInfo() {
587
    return array(
588
      'name' => 'URL destination validation',
589
      'description' => 'Test that $_GET[\'destination\'] and $_REQUEST[\'destination\'] cannot contain external URLs.',
590
      'group' => 'Bootstrap',
591
    );
592
  }
593

    
594
  function setUp() {
595
    parent::setUp('system_test');
596
  }
597

    
598
  /**
599
   * Tests that $_GET/$_REQUEST['destination'] only contain internal URLs.
600
   *
601
   * @see _drupal_bootstrap_variables()
602
   * @see system_test_get_destination()
603
   * @see system_test_request_destination()
604
   */
605
  public function testDestination() {
606
    $test_cases = array(
607
      array(
608
        'input' => 'node',
609
        'output' => 'node',
610
        'message' => "Standard internal example node path is present in the 'destination' parameter.",
611
      ),
612
      array(
613
        'input' => '/example.com',
614
        'output' => '/example.com',
615
        'message' => 'Internal path with one leading slash is allowed.',
616
      ),
617
      array(
618
        'input' => '//example.com/test',
619
        'output' => '',
620
        'message' => 'External URL without scheme is not allowed.',
621
      ),
622
      array(
623
        'input' => 'example:test',
624
        'output' => 'example:test',
625
        'message' => 'Internal URL using a colon is allowed.',
626
      ),
627
      array(
628
        'input' => 'http://example.com',
629
        'output' => '',
630
        'message' => 'External URL is not allowed.',
631
      ),
632
      array(
633
        'input' => 'javascript:alert(0)',
634
        'output' => 'javascript:alert(0)',
635
        'message' => 'Javascript URL is allowed because it is treated as an internal URL.',
636
      ),
637
    );
638
    foreach ($test_cases as $test_case) {
639
      // Test $_GET['destination'].
640
      $this->drupalGet('system-test/get-destination', array('query' => array('destination' => $test_case['input'])));
641
      $this->assertIdentical($test_case['output'], $this->drupalGetContent(), $test_case['message']);
642
      // Test $_REQUEST['destination']. There's no form to submit to, so
643
      // drupalPost() won't work here; this just tests a direct $_POST request
644
      // instead.
645
      $curl_parameters = array(
646
        CURLOPT_URL => $this->getAbsoluteUrl('system-test/request-destination'),
647
        CURLOPT_POST => TRUE,
648
        CURLOPT_POSTFIELDS => 'destination=' . urlencode($test_case['input']),
649
        CURLOPT_HTTPHEADER => array(),
650
      );
651
      $post_output = $this->curlExec($curl_parameters);
652
      $this->assertIdentical($test_case['output'], $post_output, $test_case['message']);
653
    }
654

    
655
    // Make sure that 404 pages do not populate $_GET['destination'] with
656
    // external URLs.
657
    variable_set('site_404', 'system-test/get-destination');
658
    $this->drupalGet('http://example.com', array('external' => FALSE));
659
    $this->assertIdentical('', $this->drupalGetContent(), 'External URL is not allowed on 404 pages.');
660
  }
661
}