redirect.test 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <?php
  2. /**
  3. * @file
  4. * Unit tests for the redirect module.
  5. */
  6. class RedirectTestHelper extends DrupalWebTestCase {
  7. function setUp(array $modules = array()) {
  8. array_unshift($modules, 'redirect');
  9. parent::setUp($modules);
  10. }
  11. protected function assertRedirect($redirect) {
  12. $source_url = url($redirect->source, array('absolute' => TRUE) + $redirect->source_options);
  13. $redirect_url = url($redirect->redirect, array('absolute' => TRUE) + $redirect->redirect_options);
  14. $this->drupalGet($source_url);
  15. $this->assertEqual($this->getUrl(), $redirect_url, t('Page %source was redirected to %redirect.', array('%source' => $source_url, '%redirect' => $redirect_url)));
  16. // Reload the redirect.
  17. if (!empty($redirect->rid)) {
  18. return redirect_load($redirect->rid);
  19. }
  20. }
  21. protected function assertNoRedirect($redirect) {
  22. $source_url = url($redirect->source, array('absolute' => TRUE) + $redirect->source_options);
  23. $this->drupalGet($source_url);
  24. $this->assertEqual($this->getUrl(), $source_url, t('Page %url was not redirected.', array('%url' => $source_url)));
  25. }
  26. /**
  27. * Add an URL redirection
  28. *
  29. * @param $source
  30. * A source path.
  31. * @param $redirect
  32. * A redirect path.
  33. */
  34. protected function addRedirect($source_path, $redirect_path, array $redirect = array()) {
  35. $source_parsed = redirect_parse_url($source_path);
  36. $redirect['source'] = $source_parsed['url'];
  37. if (isset($source_parsed['query'])) {
  38. $redirect['source_options']['query'] = $source_parsed['query'];
  39. }
  40. $redirect_parsed = redirect_parse_url($redirect_path);
  41. $redirect['redirect'] = $redirect_parsed['url'];
  42. if (isset($redirect_parsed['query'])) {
  43. $redirect['redirect_options']['query'] = $redirect_parsed['query'];
  44. }
  45. if (isset($redirect_parsed['fragment'])) {
  46. $redirect['redirect_options']['fragment'] = $redirect_parsed['fragment'];
  47. }
  48. $redirect_object = new stdClass();
  49. redirect_object_prepare($redirect_object, $redirect);
  50. redirect_save($redirect_object);
  51. return $redirect_object;
  52. }
  53. protected function assertPageCached($url, array $options = array()) {
  54. $options['absolute'] = TRUE;
  55. $url = url($url, $options);
  56. $cache = cache_get($url, 'cache_page');
  57. $this->assertTrue($cache, t('Page %url was cached.', array('%url' => $url)));
  58. return $cache;
  59. }
  60. protected function assertPageNotCached($url, array $options = array()) {
  61. $options['absolute'] = TRUE;
  62. $url = url($url, $options);
  63. $cache = cache_get($url, 'cache_page');
  64. $this->assertFalse($cache, t('Page %url was not cached.', array('%url' => $url)));
  65. }
  66. protected function assertHeader($name, $expected, $headers = NULL) {
  67. if (!isset($headers)) {
  68. $headers = $this->drupalGetHeaders();
  69. $name = strtolower($name);
  70. }
  71. return $this->assertIdentical($headers[$name], $expected);
  72. }
  73. }
  74. class RedirectUnitTest extends RedirectTestHelper {
  75. public static function getInfo() {
  76. return array(
  77. 'name' => 'Redirect unit tests',
  78. 'description' => 'Test basic functions and functionality.',
  79. 'group' => 'Redirect',
  80. );
  81. }
  82. /**
  83. * Test the redirect_compare_array_recursive() function.
  84. */
  85. function testCompareArrayRecursive() {
  86. $haystack = array('a' => 'aa', 'b' => 'bb', 'c' => array('c1' => 'cc1', 'c2' => 'cc2'));
  87. $cases = array(
  88. array('query' => array('a' => 'aa', 'b' => 'invalid'), 'result' => FALSE),
  89. array('query' => array('b' => 'bb', 'b' => 'bb'), 'result' => TRUE),
  90. array('query' => array('b' => 'bb', 'c' => 'invalid'), 'result' => FALSE),
  91. array('query' => array('b' => 'bb', 'c' => array()), 'result' => TRUE),
  92. array('query' => array('b' => 'bb', 'c' => array('invalid')), 'result' => FALSE),
  93. array('query' => array('b' => 'bb', 'c' => array('c2' => 'invalid')), 'result' => FALSE),
  94. array('query' => array('b' => 'bb', 'c' => array('c2' => 'cc2')), 'result' => TRUE),
  95. );
  96. foreach ($cases as $index => $case) {
  97. $this->assertEqual($case['result'], redirect_compare_array_recursive($case['query'], $haystack));
  98. }
  99. }
  100. /**
  101. * Test redirect_sort_recursive().
  102. */
  103. function testSortRecursive() {
  104. $test_cases = array(
  105. array(
  106. 'input' => array('b' => 'aa', 'c' => array('c2' => 'aa', 'c1' => 'aa'), 'a' => 'aa'),
  107. 'expected' => array('a' => 'aa', 'b' => 'aa', 'c' => array('c1' => 'aa', 'c2' => 'aa')),
  108. 'callback' => 'ksort',
  109. ),
  110. );
  111. foreach ($test_cases as $index => $test_case) {
  112. $output = $test_case['input'];
  113. redirect_sort_recursive($output, $test_case['callback']);
  114. $this->assertIdentical($output, $test_case['expected']);
  115. }
  116. }
  117. /**
  118. * Test redirect_parse_url().
  119. */
  120. function testParseURL() {
  121. //$test_cases = array(
  122. // array(
  123. // 'input' => array('b' => 'aa', 'c' => array('c2' => 'aa', 'c1' => 'aa'), 'a' => 'aa'),
  124. // 'expected' => array('a' => 'aa', 'b' => 'aa', 'c' => array('c1' => 'aa', 'c2' => 'aa')),
  125. // ),
  126. //);
  127. //foreach ($test_cases as $index => $test_case) {
  128. // $output = redirect_parse_url($test_case['input']);
  129. // $this->assertIdentical($output, $test_case['expected']);
  130. //}
  131. }
  132. }
  133. class RedirectFunctionalTest extends RedirectTestHelper {
  134. private $admin_user;
  135. public static function getInfo() {
  136. return array(
  137. 'name' => 'Redirect functional tests',
  138. 'description' => 'Test interface functionality.',
  139. 'group' => 'Redirect',
  140. );
  141. }
  142. function setUp(array $modules = array()) {
  143. parent::setUp($modules);
  144. $this->admin_user = $this->drupalCreateUser(array('administer redirects', 'access site reports', 'access content', 'create article content', 'edit any article content', 'create url aliases'));
  145. $this->drupalLogin($this->admin_user);
  146. }
  147. function test404Interface() {
  148. // Check that 404 pages do get add redirect links for admin users.
  149. $this->drupalGet('invalid-path1');
  150. $this->drupalGet('invalid-path2');
  151. $this->assertLink('Add URL redirect from this page to another location');
  152. // Check that 403 pages do not get the add redirect link at all.
  153. $this->drupalGet('admin/config/system/actions');
  154. $this->assertNoLink('Add URL redirect from this page to another location');
  155. $this->drupalGet('admin/reports/page-not-found');
  156. $this->clickLink('Fix 404 pages with URL redirects');
  157. // Check that normal users do not see the add redirect link on 404 pages.
  158. $this->drupalLogout();
  159. $this->drupalGet('invalid-path3');
  160. $this->assertNoLink('Add an URL redirect from this page to another location');
  161. }
  162. function testPageCache() {
  163. // Set up cache variables.
  164. variable_set('cache', 1);
  165. $edit = array(
  166. 'redirect_page_cache' => TRUE,
  167. 'redirect_purge_inactive' => 604800,
  168. );
  169. $this->drupalPost('admin/config/search/redirect/settings', $edit, 'Save configuration');
  170. $this->assertText('The configuration options have been saved.');
  171. $this->drupalLogout();
  172. // Add a new redirect.
  173. $redirect = $this->addRedirect('redirect', 'node');
  174. $this->assertEqual($redirect->access, 0);
  175. $this->assertEqual($redirect->count, 0);
  176. $this->assertPageNotCached('redirect');
  177. // Perform the redirect and check that last_used
  178. $redirect = $this->assertRedirect($redirect);
  179. $this->assertEqual($redirect->count, 1);
  180. $this->assertTrue($redirect->access > 0);
  181. $cache = $this->assertPageCached('redirect');
  182. $this->assertHeader('Location', url('node', array('absolute' => TRUE)), $cache->data['headers']);
  183. $this->assertHeader('X-Redirect-ID', $redirect->rid, $cache->data['headers']);
  184. // Set a redirect to not used in a while and disable running bootstrap
  185. // hooks during cache page serve. Running cron to remove inactive redirects
  186. // should not remove since they cannot be tracked.
  187. $redirect->access = 1;
  188. redirect_save($redirect);
  189. variable_set('page_cache_invoke_hooks', FALSE);
  190. $this->cronRun();
  191. $this->assertRedirect($redirect);
  192. $redirect->access = 1;
  193. redirect_save($redirect);
  194. variable_set('page_cache_invoke_hooks', TRUE);
  195. $this->cronRun();
  196. $this->assertNoRedirect($redirect);
  197. }
  198. function testPathChangeRedirects() {
  199. // Create an initial article node with a path alias.
  200. $node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias')));
  201. // Change the node's alias will create an automatic redirect from 'first-alias' to the node.
  202. $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save'));
  203. $this->drupalGet('first-alias');
  204. $this->assertText($node->title);
  205. $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'first-alias'), t('Save'));
  206. $this->assertResponse(200, "Changing node's alias back to 'first-alias' does not break page load with a circular redirect.");
  207. $this->assertNoText('Infinite redirect loop prevented.');
  208. $this->drupalGet('second-alias');
  209. $this->assertText($node->title);
  210. $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save'));
  211. $this->assertResponse(200, "Changing node's alias back to 'second-alias' does not break page load with a circular redirect.");
  212. $this->assertNoText('Infinite redirect loop prevented.');
  213. // Check that first-alias redirect has been re-enabled.
  214. $this->drupalGet('first-alias');
  215. $this->assertText($node->title);
  216. }
  217. function testPathAddOverwriteRedirects() {
  218. // Create an initial article node with a path alias.
  219. $first_node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias')));
  220. // Change the node's alias will create an automatic redirect from 'first-alias' to the node.
  221. $this->drupalPost("node/{$first_node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save'));
  222. // Now create a second article node with the same alias as the redirect
  223. // created above.
  224. $second_node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias')));
  225. // Visit the path 'first-alias' which should be an alias for $second_node.
  226. $this->drupalGet('first-alias');
  227. $this->assertNoText($first_node->title, 'Adding a new path alias that matches an existing redirect disables the redirect.');
  228. $this->assertText($second_node->title, 'Adding a new path alias that matches an existing redirect disables the redirect.');
  229. }
  230. function testDisableEnableRedirect() {
  231. // Add a new redirect.
  232. $redirect = $this->addRedirect('redirect', 'node');
  233. // Check that it is enabled.
  234. $this->assertEqual($redirect->status, 1);
  235. // Disable the redirect.
  236. $edit = array('status' => FALSE);
  237. $this->drupalPost("admin/config/search/redirect/edit/{$redirect->rid}", $edit, t('Save'));
  238. $redirect = redirect_load($redirect->rid);
  239. // Check that it has been disabled.
  240. $this->assertEqual($redirect->status, 0);
  241. $this->drupalGet("admin/config/search/redirect/edit/{$redirect->rid}");
  242. $this->assertNoFieldChecked('edit-status', 'status is unchecked');
  243. $this->assertNoRedirect($redirect);
  244. // Re-enable the redirect.
  245. $edit = array('status' => 1);
  246. $this->drupalPost("admin/config/search/redirect/edit/{$redirect->rid}", $edit, t('Save'));
  247. $this->assertRedirect($redirect);
  248. }
  249. }