assertTrue($link && $link['access'] && $link['status'], t('Link found in sitemap.')); return $link; } /** * Assert that a link is not found in the sitemap. * * @param $conditions * An array of values/conditions to match keyed by field name. */ protected function assertNotInSitemap($conditions) { $link = xmlsitemap_load_link($conditions); $this->assertTrue(!$link || !$link['access'] || !$link['status'], t('Link not found in sitemap.')); return $link; } protected function assertLinkValues($link, array $values) { foreach ($values as $key => $value) { if ($value === NULL || $link[$key] === NULL) { // For nullable fields, always check for identical values (===). $this->assertIdentical($link[$key], $value, t('Identical values for link field @key.', array('@key' => $key))); } else { // Otherwise check simple equality (==). $this->assertEqual($link[$key], $value, t('Equal values for link field @key.', array('@key' => $key))); } } } protected function addSitemapLink(array $link = array()) { static $last_id = 1; $link += array( 'type' => 'simpletest', 'id' => $last_id, 'loc' => $this->randomName(), ); $last_id = $link['id'] + 1; xmlsitemap_save_link($link); return $link; } /** * Regenerate the sitemap by setting the regenerate flag and running cron. */ protected function regenerateSitemap() { variable_set('xmlsitemap_regenerate_needed', TRUE); variable_set('xmlsitemap_generated_last', REQUEST_TIME - xmlsitemap_var('minimum_lifetime') - 30); drupal_cron_run(); } /** * Check the files directory is created (massive fails if not done). */ protected function checkFilesDirectory() { $path = file_create_path(xmlsitemap_var('path')); file_check_directory($path, FILE_CREATE_DIRECTORY); } protected function assertXMLSitemapProblems($problem_text = FALSE) { $this->drupalGet('admin/settings/xmlsitemap'); $this->assertText(t('One or more problems were detected with your sitemap configuration. Please check the status report for more information.')); if ($problem_text) { $this->clickLink(t('status report')); $this->assertText($problem_text); } } protected function assertNoXMLSitemapProblems() { $this->drupalGet('admin/settings/xmlsitemap'); $this->assertNoText(t('One or more problems were detected with your sitemap configuration. Please check the status report for more information.')); } //protected function saveSettings($url, array $settings) { // $this->drupalPost($url, $settings, t('Save configuration')); // $this->assertText(t('The configuration options have been saved.')); //} private function getWatchdogMessage(array $conditions) { static $watchdog_schema; if (!isset($watchdog_schema)) { $watchdog_schema = drupal_get_schema('watchdog'); } $args = array(); foreach ($conditions as $field => $value) { $conditions[$field] = $field . ' = ' . db_type_placeholder($watchdog_schema['fields'][$field]['type']); $args[] = ($field == 'variables' && is_array($value)) ? serialize($value) : $value; } return db_result(db_query_range("SELECT 1 FROM {watchdog} WHERE " . implode(' AND ', $conditions), $args, 0, 1)); } protected function assertWatchdogMessage(array $conditions, $message = 'Watchdog message found.') { $this->assertTrue($this->getWatchdogMessage($conditions), $message); } protected function assertNoWatchdogMessage(array $conditions, $message = 'Watchdog message not found.') { $this->assertFalse($this->getWatchdogMessage($conditions), $message); } protected function assertSitemapLink($conditions) { $link = xmlsitemap_load_link($conditions); $this->assertTrue($link); return $link; } protected function assertNotSitemapLink($conditions) { $link = xmlsitemap_load_link($conditions); $this->assertFalse($link); return $link; } } class XMLSitemapUnitTest extends XMLSitemapTestHelper { public static function getInfo() { return array( 'name' => 'XML sitemap unit tests', 'description' => 'Unit tests for the XML sitemap module.', 'group' => 'XML sitemap', ); } function setUp() { parent::setUp('xmlsitemap'); } /** * Tests for xmlsitemap_get_changefreq(). */ function testGetChangefreq() { // The test values. $values = array( 0, mt_rand(1, XMLSITEMAP_FREQUENCY_ALWAYS), mt_rand(XMLSITEMAP_FREQUENCY_ALWAYS + 1, XMLSITEMAP_FREQUENCY_HOURLY), mt_rand(XMLSITEMAP_FREQUENCY_HOURLY + 1, XMLSITEMAP_FREQUENCY_DAILY), mt_rand(XMLSITEMAP_FREQUENCY_DAILY + 1, XMLSITEMAP_FREQUENCY_WEEKLY), mt_rand(XMLSITEMAP_FREQUENCY_WEEKLY + 1, XMLSITEMAP_FREQUENCY_MONTHLY), mt_rand(XMLSITEMAP_FREQUENCY_MONTHLY + 1, XMLSITEMAP_FREQUENCY_YEARLY), mt_rand(XMLSITEMAP_FREQUENCY_YEARLY + 1, mt_getrandmax()), ); // The expected values. $expected = array( FALSE, 'always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never', ); foreach ($values as $i => $value) { $actual = xmlsitemap_get_changefreq($value); $this->assertIdentical($actual, $expected[$i]); } } /** * Tests for xmlsitemap_get_chunk_count(). */ function testGetChunkCount() { // Set a low chunk size for testing. variable_set('xmlsitemap_chunk_size', 4); // Make the total number of links just equal to the chunk size. $count = db_result(db_query("SELECT COUNT(id) FROM {xmlsitemap}")); for ($i = $count; $i < 4; $i++) { $this->addSitemapLink(); $this->assertEqual(xmlsitemap_get_chunk_count(TRUE), 1); } $this->assertEqual(db_result(db_query("SELECT COUNT(id) FROM {xmlsitemap}")), 4); // Add a disabled link, should not change the chunk count. $this->addSitemapLink(array('status' => FALSE)); $this->assertEqual(xmlsitemap_get_chunk_count(TRUE), 1); // Add a visible link, should finally bump up the chunk count. $this->addSitemapLink(); $this->assertEqual(xmlsitemap_get_chunk_count(TRUE), 2); // Change all links to disabled. The chunk count should be 1 not 0. db_query("UPDATE {xmlsitemap} SET status = 0"); $this->assertEqual(xmlsitemap_get_chunk_count(TRUE), 1); $this->assertEqual(xmlsitemap_get_link_count(), 0); // Delete all links. The chunk count should be 1 not 0. db_query("DELETE FROM {xmlsitemap}"); $this->assertEqual(db_result(db_query("SELECT COUNT(id) FROM {xmlsitemap}")), 0); $this->assertEqual(xmlsitemap_get_chunk_count(TRUE), 1); } //function testGetChunkFile() { //} // //function testGetChunkSize() { //} // //function testGetLinkCount() { //} /** * Tests for xmlsitemap_calculate_changereq(). */ function testCalculateChangefreq() { // The test values. $values = array( array(), array(REQUEST_TIME), array(REQUEST_TIME, REQUEST_TIME - 200), array(REQUEST_TIME - 200, REQUEST_TIME, REQUEST_TIME - 600), ); // Expected values. $expected = array(0, 0, 200, 300); foreach ($values as $i => $value) { $actual = xmlsitemap_calculate_changefreq($value); $this->assertEqual($actual, $expected[$i]); } } /** * Test for xmlsitemap_recalculate_changefreq(). */ function testRecalculateChangefreq() { // The starting test value. $value = array('lastmod' => REQUEST_TIME - 1000, 'changefreq' => 0, 'changecount' => 0); // Expected values. $expecteds = array( array('lastmod' => REQUEST_TIME, 'changefreq' => 1000, 'changecount' => 1), array('lastmod' => REQUEST_TIME, 'changefreq' => 500, 'changecount' => 2), array('lastmod' => REQUEST_TIME, 'changefreq' => 333, 'changecount' => 3), ); foreach ($expecteds as $expected) { xmlsitemap_recalculate_changefreq($value); $this->assertEqual($value, $expected); } } /** * Tests for xmlsitemap_switch_user and xmlsitemap_restore_user(). */ function testSwitchUser() { global $user; $original_user = $user; $new_user = $this->drupalCreateUser(); xmlsitemap_switch_user($new_user); $this->assertEqual($user->uid, $new_user->uid, t('Switched to new user.')); xmlsitemap_switch_user(); $this->assertEqual($user->uid, $original_user->uid, t('Restored original user.')); xmlsitemap_switch_user(0); $this->assertEqual($user->uid, 0, t('Switched to anonymous user.')); xmlsitemap_restore_user(); $this->assertEqual($user->uid, $original_user->uid, t('Restored original user.')); } //function testWriteRecord() { //} // //function testLoadLink() { //} /** * Tests for xmlsitemap_save_link(). */ function testSaveLink() { $this->assertFalse(xmlsitemap_var('regenerate_needed')); $link = array('type' => 'testing', 'id' => 1, 'loc' => 'testing', 'status' => 1); xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['status'] = 0; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 0.5; $link['loc'] = 'new_location'; $link['status'] = 1; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 0.0; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 0.1; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 1.0; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 1; xmlsitemap_save_link($link); $this->assertFalse(xmlsitemap_var('regenerate_needed')); $link['priority'] = 0; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 0.5; xmlsitemap_save_link($link); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $link['priority'] = 0.5; $link['priority_override'] = 0; $link['status'] = 1; xmlsitemap_save_link($link); $this->assertFalse(xmlsitemap_var('regenerate_needed')); } /** * Tests for xmlsitemap_delete_link(). */ function testDeleteLink() { // Add our testing data. $link1 = $this->addSitemapLink(array('loc' => 'testing1', 'status' => 0)); $link2 = $this->addSitemapLink(array('loc' => 'testing1', 'status' => 1)); $link3 = $this->addSitemapLink(array('status' => 0)); variable_set('xmlsitemap_regenerate_needed', FALSE); $this->assertFalse(xmlsitemap_var('regenerate_needed')); // Test delete multiple links. // Test that the regenerate flag is set when visible links are deleted. $num = xmlsitemap_delete_link(array('loc' => 'testing1')); $this->assertEqual($num, 2); $this->assertFalse(xmlsitemap_load_link(array('type' => $link1['type'], 'id' => $link1['id']))); $this->assertFalse(xmlsitemap_load_link(array('type' => $link2['type'], 'id' => $link2['id']))); $this->assertTrue(xmlsitemap_load_link(array('type' => $link3['type'], 'id' => $link3['id']))); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $num = xmlsitemap_delete_link(array('type' => $link3['type'], 'id' => $link3['id'])); $this->assertEqual($num, 1); $this->assertFalse(xmlsitemap_load_link(array('type' => $link3['type'], 'id' => $link3['id']))); $this->assertFalse(xmlsitemap_var('regenerate_needed')); } /** * Tests for xmlsitemap_update_links(). */ function testUpdateLinks() { // Add our testing data. $link1 = $this->addSitemapLink(array('loc' => 'testing1')); $link2 = $this->addSitemapLink(array('loc' => 'testing1')); $link3 = $this->addSitemapLink(array('loc' => 'testing2')); variable_set('xmlsitemap_regenerate_needed', FALSE); $this->assertFalse(xmlsitemap_var('regenerate_needed')); $return = xmlsitemap_update_links(array('status' => FALSE), array('loc' => 'testing1')); $this->assertEqual($return, 2); $this->assertNotInSitemap(array('type' => $link1['type'], 'id' => $link1['id'])); $this->assertNotInSitemap(array('type' => $link2['type'], 'id' => $link2['id'])); $this->assertInSitemap(array('type' => $link3['type'], 'id' => $link3['id'])); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $return = xmlsitemap_update_links(array('loc' => 'testing2', 'status' => NULL), array('loc' => 'testing1', 'status' => FALSE)); $this->assertEqual($return, 2); $this->assertFalse(xmlsitemap_var('regenerate_needed')); $return = xmlsitemap_update_links(array('priority' => 0.5), array('priority' => NULL)); $this->assertEqual($return, 3); $this->assertTrue(xmlsitemap_var('regenerate_needed')); variable_set('xmlsitemap_regenerate_needed', FALSE); $return = xmlsitemap_update_links(array('status' => NULL), array('priority' => 1.1)); $this->assertEqual($return, 0); $this->assertFalse(xmlsitemap_var('regenerate_needed')); } } class XMLSitemapFunctionalTest extends XMLSitemapTestHelper { protected $admin_user; public static function getInfo() { return array( 'name' => 'XML sitemap interface tests', 'description' => 'Functional tests for the XML sitemap module.', 'group' => 'XML sitemap', ); } function setUp() { parent::setUp('xmlsitemap', 'path'); $this->admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration', 'administer xmlsitemap')); $this->drupalLogin($this->admin_user); $this->checkFilesDirectory(); } /** * Test the sitemap file caching. */ function testSitemapCaching() { $this->drupalGet('sitemap.xml'); $this->assertResponse(200); $etag = $this->drupalGetHeader('etag'); $last_modified = $this->drupalGetHeader('last-modified'); $this->assertTrue($etag, t('Etag header found.')); $this->assertTrue($last_modified, t('Last-modified header found.')); $this->drupalGet('sitemap.xml', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag)); $this->assertResponse(304); } /** * Test that the sitemap will not be genereated before the lifetime expires. */ function testMinimumLifetime() { // Ensure the sitemap has been generated already. $this->regenerateSitemap(); //$this->drupalGet('sitemap.xml'); $edit = array('xmlsitemap_minimum_lifetime' => 300); $this->drupalPost('admin/settings/xmlsitemap', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.')); xmlsitemap_save_link(array('type' => 'testing', 'id' => 1, 'loc' => 'lifetime-test')); drupal_cron_run(); $this->drupalGet('sitemap.xml'); $this->assertNoRaw('lifetime-test'); variable_set('xmlsitemap_generated_last', REQUEST_TIME - 300); drupal_cron_run(); $this->drupalGet('sitemap.xml'); $this->assertRaw('lifetime-test'); xmlsitemap_delete_link(array('type' => 'testing', 'id' => 1)); drupal_cron_run(); $this->drupalGet('sitemap.xml'); $this->assertRaw('lifetime-test'); $this->regenerateSitemap(); $this->drupalGet('sitemap.xml'); $this->assertNoRaw('lifetime-test'); } /** * Test base URL functionality. */ function testBaseURL() { $edit = array('xmlsitemap_base_url' => ''); $this->drupalPost('admin/settings/xmlsitemap', $edit, t('Save configuration')); $this->assertText(t('Base URL field is required.')); $edit = array('xmlsitemap_base_url' => 'invalid'); $this->drupalPost('admin/settings/xmlsitemap', $edit, t('Save configuration')); $this->assertText(t('Invalid base URL.')); $edit = array('xmlsitemap_base_url' => 'http://example.com/ '); $this->drupalPost('admin/settings/xmlsitemap', $edit, t('Save configuration')); $this->assertText(t('Invalid base URL.')); $edit = array('xmlsitemap_base_url' => 'http://example.com/'); $this->drupalPost('admin/settings/xmlsitemap', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.')); $this->drupalGet('sitemap.xml'); $this->assertRaw('http://example.com/'); } /** * Test that configuration problems are reported properly in the status report. */ function testStatusReport() { // Test the rebuild flag. variable_set('xmlsitemap_rebuild_needed', TRUE); $this->assertXMLSitemapProblems(t('The XML sitemap data is out of sync and needs to be completely rebuilt.')); $this->clickLink(t('completely rebuilt')); $this->assertResponse(200); variable_set('xmlsitemap_rebuild_needed', FALSE); $this->assertNoXMLSitemapProblems(); // Test the regenerate flag (and cron hasn't run in a while). variable_set('xmlsitemap_regenerate_needed', TRUE); variable_set('xmlsitemap_generated_last', REQUEST_TIME - variable_get('cron_threshold_warning', 172800) - 10); $this->assertXMLSitemapProblems(t('The XML cached files are out of date and need to be regenerated. You can run cron manually to regenerate the sitemap files.')); $this->clickLink(t('run cron manually')); $this->assertResponse(200); $this->assertNoXMLSitemapProblems(); // Test anonymous users access to sitemap.xml. $anon_permissions = db_result(db_query("SELECT perm FROM {permission} WHERE rid = %d", DRUPAL_ANONYMOUS_RID)); db_query("UPDATE {permission} SET perm = '' WHERE rid = %d", DRUPAL_ANONYMOUS_RID); $this->assertXMLSitemapProblems(t('Search engines (anonymous users) cannot currently access your XML sitemap. Please assign the "access content" permission the the anonymous user role.')); db_query("UPDATE {permission} SET perm = '%s' WHERE rid = %d", $anon_permissions, DRUPAL_ANONYMOUS_RID); $this->assertNoXMLSitemapProblems(); // Test chunk count > 1000. // Test directory not writable. } } class XMLSitemapRobotsTxtIntegrationTest extends XMLSitemapTestHelper { public static function getInfo() { return array( 'name' => 'XML sitemap robots.txt', 'description' => 'Integration tests for the XML sitemap and robots.txt module.', 'group' => 'XML sitemap', 'dependencies' => array('robotstxt'), ); } function setUp() { parent::setUp('xmlsitemap', 'robotstxt'); } function testRobotsTxt() { // Request the un-clean robots.txt path so this will work in case there is // still the robots.txt file in the root directory. $this->drupalGet('', array('query' => 'q=robots.txt')); $this->assertRaw('Sitemap: ' . url('sitemap.xml', array('absolute' => TRUE))); } }