source, array('absolute' => TRUE) + $redirect->source_options); $redirect_url = url($redirect->redirect, array('absolute' => TRUE) + $redirect->redirect_options); $this->drupalGet($source_url); $this->assertEqual($this->getUrl(), $redirect_url, t('Page %source was redirected to %redirect.', array('%source' => $source_url, '%redirect' => $redirect_url))); // Reload the redirect. if (!empty($redirect->rid)) { return redirect_load($redirect->rid); } } protected function assertNoRedirect($redirect) { $source_url = url($redirect->source, array('absolute' => TRUE) + $redirect->source_options); $this->drupalGet($source_url); $this->assertEqual($this->getUrl(), $source_url, t('Page %url was not redirected.', array('%url' => $source_url))); } /** * Add an URL redirection * * @param $source * A source path. * @param $redirect * A redirect path. */ protected function addRedirect($source_path, $redirect_path, array $redirect = array()) { $source_parsed = redirect_parse_url($source_path); $redirect['source'] = $source_parsed['url']; if (isset($source_parsed['query'])) { $redirect['source_options']['query'] = $source_parsed['query']; } $redirect_parsed = redirect_parse_url($redirect_path); $redirect['redirect'] = $redirect_parsed['url']; if (isset($redirect_parsed['query'])) { $redirect['redirect_options']['query'] = $redirect_parsed['query']; } if (isset($redirect_parsed['fragment'])) { $redirect['redirect_options']['fragment'] = $redirect_parsed['fragment']; } $redirect_object = new stdClass(); redirect_object_prepare($redirect_object, $redirect); redirect_save($redirect_object); return $redirect_object; } protected function assertPageCached($url, array $options = array()) { $options['absolute'] = TRUE; $url = url($url, $options); $cache = cache_get($url, 'cache_page'); $this->assertTrue($cache, t('Page %url was cached.', array('%url' => $url))); return $cache; } protected function assertPageNotCached($url, array $options = array()) { $options['absolute'] = TRUE; $url = url($url, $options); $cache = cache_get($url, 'cache_page'); $this->assertFalse($cache, t('Page %url was not cached.', array('%url' => $url))); } protected function assertHeader($name, $expected, $headers = NULL) { if (!isset($headers)) { $headers = $this->drupalGetHeaders(); $name = strtolower($name); } return $this->assertIdentical($headers[$name], $expected); } } class RedirectUnitTest extends RedirectTestHelper { public static function getInfo() { return array( 'name' => 'Redirect unit tests', 'description' => 'Test basic functions and functionality.', 'group' => 'Redirect', ); } /** * Test the redirect_compare_array_recursive() function. */ function testCompareArrayRecursive() { $haystack = array('a' => 'aa', 'b' => 'bb', 'c' => array('c1' => 'cc1', 'c2' => 'cc2')); $cases = array( array('query' => array('a' => 'aa', 'b' => 'invalid'), 'result' => FALSE), array('query' => array('b' => 'bb', 'b' => 'bb'), 'result' => TRUE), array('query' => array('b' => 'bb', 'c' => 'invalid'), 'result' => FALSE), array('query' => array('b' => 'bb', 'c' => array()), 'result' => TRUE), array('query' => array('b' => 'bb', 'c' => array('invalid')), 'result' => FALSE), array('query' => array('b' => 'bb', 'c' => array('c2' => 'invalid')), 'result' => FALSE), array('query' => array('b' => 'bb', 'c' => array('c2' => 'cc2')), 'result' => TRUE), ); foreach ($cases as $index => $case) { $this->assertEqual($case['result'], redirect_compare_array_recursive($case['query'], $haystack)); } } /** * Test redirect_sort_recursive(). */ function testSortRecursive() { $test_cases = array( array( 'input' => array('b' => 'aa', 'c' => array('c2' => 'aa', 'c1' => 'aa'), 'a' => 'aa'), 'expected' => array('a' => 'aa', 'b' => 'aa', 'c' => array('c1' => 'aa', 'c2' => 'aa')), 'callback' => 'ksort', ), ); foreach ($test_cases as $index => $test_case) { $output = $test_case['input']; redirect_sort_recursive($output, $test_case['callback']); $this->assertIdentical($output, $test_case['expected']); } } /** * Test redirect_parse_url(). */ function testParseURL() { //$test_cases = array( // array( // 'input' => array('b' => 'aa', 'c' => array('c2' => 'aa', 'c1' => 'aa'), 'a' => 'aa'), // 'expected' => array('a' => 'aa', 'b' => 'aa', 'c' => array('c1' => 'aa', 'c2' => 'aa')), // ), //); //foreach ($test_cases as $index => $test_case) { // $output = redirect_parse_url($test_case['input']); // $this->assertIdentical($output, $test_case['expected']); //} } } class RedirectFunctionalTest extends RedirectTestHelper { private $admin_user; public static function getInfo() { return array( 'name' => 'Redirect functional tests', 'description' => 'Test interface functionality.', 'group' => 'Redirect', ); } function setUp(array $modules = array()) { parent::setUp($modules); $this->admin_user = $this->drupalCreateUser(array('administer redirects', 'access site reports', 'access content', 'create article content', 'edit any article content', 'create url aliases')); $this->drupalLogin($this->admin_user); } function test404Interface() { // Check that 404 pages do get add redirect links for admin users. $this->drupalGet('invalid-path1'); $this->drupalGet('invalid-path2'); $this->assertLink('Add URL redirect from this page to another location'); // Check that 403 pages do not get the add redirect link at all. $this->drupalGet('admin/config/system/actions'); $this->assertNoLink('Add URL redirect from this page to another location'); $this->drupalGet('admin/reports/page-not-found'); $this->clickLink('Fix 404 pages with URL redirects'); // Check that normal users do not see the add redirect link on 404 pages. $this->drupalLogout(); $this->drupalGet('invalid-path3'); $this->assertNoLink('Add an URL redirect from this page to another location'); } function testPageCache() { // Set up cache variables. variable_set('cache', 1); $edit = array( 'redirect_page_cache' => TRUE, 'redirect_purge_inactive' => 604800, ); $this->drupalPost('admin/config/search/redirect/settings', $edit, 'Save configuration'); $this->assertText('The configuration options have been saved.'); $this->drupalLogout(); // Add a new redirect. $redirect = $this->addRedirect('redirect', 'node'); $this->assertEqual($redirect->access, 0); $this->assertEqual($redirect->count, 0); $this->assertPageNotCached('redirect'); // Perform the redirect and check that last_used $redirect = $this->assertRedirect($redirect); $this->assertEqual($redirect->count, 1); $this->assertTrue($redirect->access > 0); $cache = $this->assertPageCached('redirect'); $this->assertHeader('Location', url('node', array('absolute' => TRUE)), $cache->data['headers']); $this->assertHeader('X-Redirect-ID', $redirect->rid, $cache->data['headers']); // Set a redirect to not used in a while and disable running bootstrap // hooks during cache page serve. Running cron to remove inactive redirects // should not remove since they cannot be tracked. $redirect->access = 1; redirect_save($redirect); variable_set('page_cache_invoke_hooks', FALSE); $this->cronRun(); $this->assertRedirect($redirect); $redirect->access = 1; redirect_save($redirect); variable_set('page_cache_invoke_hooks', TRUE); $this->cronRun(); $this->assertNoRedirect($redirect); } function testPathChangeRedirects() { // Create an initial article node with a path alias. $node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias'))); // Change the node's alias will create an automatic redirect from 'first-alias' to the node. $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save')); $this->drupalGet('first-alias'); $this->assertText($node->title); $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'first-alias'), t('Save')); $this->assertResponse(200, "Changing node's alias back to 'first-alias' does not break page load with a circular redirect."); $this->assertNoText('Infinite redirect loop prevented.'); $this->drupalGet('second-alias'); $this->assertText($node->title); $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save')); $this->assertResponse(200, "Changing node's alias back to 'second-alias' does not break page load with a circular redirect."); $this->assertNoText('Infinite redirect loop prevented.'); // Check that first-alias redirect has been re-enabled. $this->drupalGet('first-alias'); $this->assertText($node->title); } function testPathAddOverwriteRedirects() { // Create an initial article node with a path alias. $first_node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias'))); // Change the node's alias will create an automatic redirect from 'first-alias' to the node. $this->drupalPost("node/{$first_node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save')); // Now create a second article node with the same alias as the redirect // created above. $second_node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias'))); // Visit the path 'first-alias' which should be an alias for $second_node. $this->drupalGet('first-alias'); $this->assertNoText($first_node->title, 'Adding a new path alias that matches an existing redirect disables the redirect.'); $this->assertText($second_node->title, 'Adding a new path alias that matches an existing redirect disables the redirect.'); } function testDisableEnableRedirect() { // Add a new redirect. $redirect = $this->addRedirect('redirect', 'node'); // Check that it is enabled. $this->assertEqual($redirect->status, 1); // Disable the redirect. $edit = array('status' => FALSE); $this->drupalPost("admin/config/search/redirect/edit/{$redirect->rid}", $edit, t('Save')); $redirect = redirect_load($redirect->rid); // Check that it has been disabled. $this->assertEqual($redirect->status, 0); $this->drupalGet("admin/config/search/redirect/edit/{$redirect->rid}"); $this->assertNoFieldChecked('edit-status', 'status is unchecked'); $this->assertNoRedirect($redirect); // Re-enable the redirect. $edit = array('status' => 1); $this->drupalPost("admin/config/search/redirect/edit/{$redirect->rid}", $edit, t('Save')); $this->assertRedirect($redirect); } }