diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php new file mode 100644 index 0000000000000000000000000000000000000000..86b446aa6355d0ff9782c11f7f1df558d76d78aa --- /dev/null +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php @@ -0,0 +1,197 @@ +<?php + +/** + * @file + * Definition of Drupal\statistics\Tests\StatisticsAdminTest. + */ + +namespace Drupal\statistics\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Tests the statistics administration screen. + */ +class StatisticsAdminTest extends WebTestBase { + + /** + * A user that has permission to administer and access statistics. + * + * @var object|FALSE + * + * A fully loaded user object, or FALSE if user creation failed. + */ + protected $privileged_user; + + /** + * A page node for which to check access statistics. + * + * @var object + */ + protected $test_node; + + public static function getInfo() { + return array( + 'name' => 'Test statistics admin.', + 'description' => 'Tests the statistics admin.', + 'group' => 'Statistics' + ); + } + + function setUp() { + parent::setUp(array('node', 'statistics')); + + // Create Basic page node type. + if ($this->profile != 'standard') { + $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); + } + $this->privileged_user = $this->drupalCreateUser(array('access statistics', 'administer statistics', 'view post access counter', 'create page content')); + $this->drupalLogin($this->privileged_user); + $this->test_node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->privileged_user->uid)); + } + + /** + * Verifies that the statistics settings page works. + */ + function testStatisticsSettings() { + $this->assertFalse(variable_get('statistics_enable_access_log', 0), t('Access log is disabled by default.')); + $this->assertFalse(variable_get('statistics_count_content_views', 0), t('Count content view log is disabled by default.')); + + $this->drupalGet('admin/reports/pages'); + $this->assertRaw(t('No statistics available.'), t('Verifying text shown when no statistics is available.')); + + // Enable access log and counter on content view. + $edit['statistics_enable_access_log'] = 1; + $edit['statistics_count_content_views'] = 1; + $this->drupalPost('admin/config/system/statistics', $edit, t('Save configuration')); + $this->assertTrue(variable_get('statistics_enable_access_log'), t('Access log is enabled.')); + $this->assertTrue(variable_get('statistics_count_content_views'), t('Count content view log is enabled.')); + + // Hit the node. + $this->drupalGet('node/' . $this->test_node->nid); + // Manually calling statistics.php, simulating ajax behavior. + $nid = $this->test_node->nid; + $post = http_build_query(array('nid' => $nid)); + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + global $base_url; + $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + + $this->drupalGet('admin/reports/pages'); + $this->assertText('node/1', t('Test node found.')); + + // Hit the node again (the counter is incremented after the hit, so + // "1 view" will actually be shown when the node is hit the second time). + $this->drupalGet('node/' . $this->test_node->nid); + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $this->assertText('1 view', t('Node is viewed once.')); + + $this->drupalGet('node/' . $this->test_node->nid); + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $this->assertText('2 views', t('Node is viewed 2 times.')); + } + + /** + * Tests that when a node is deleted, the node counter is deleted too. + */ + function testDeleteNode() { + variable_set('statistics_count_content_views', 1); + + $this->drupalGet('node/' . $this->test_node->nid); + // Manually calling statistics.php, simulating ajax behavior. + $nid = $this->test_node->nid; + $post = http_build_query(array('nid' => $nid)); + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + global $base_url; + $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + + $result = db_select('node_counter', 'n') + ->fields('n', array('nid')) + ->condition('n.nid', $this->test_node->nid) + ->execute() + ->fetchAssoc(); + $this->assertEqual($result['nid'], $this->test_node->nid, 'Verifying that the node counter is incremented.'); + + node_delete($this->test_node->nid); + + $result = db_select('node_counter', 'n') + ->fields('n', array('nid')) + ->condition('n.nid', $this->test_node->nid) + ->execute() + ->fetchAssoc(); + $this->assertFalse($result, 'Verifying that the node counter is deleted.'); + } + + /** + * Tests that accesslog reflects when a user is deleted. + */ + function testDeleteUser() { + variable_set('statistics_enable_access_log', 1); + + variable_set('user_cancel_method', 'user_cancel_delete'); + $this->drupalLogout($this->privileged_user); + $account = $this->drupalCreateUser(array('access content', 'cancel account')); + $this->drupalLogin($account); + $this->drupalGet('node/' . $this->test_node->nid); + + $account = user_load($account->uid, TRUE); + + $this->drupalGet('user/' . $account->uid . '/edit'); + $this->drupalPost(NULL, NULL, t('Cancel account')); + + $timestamp = time(); + $this->drupalPost(NULL, NULL, t('Cancel account')); + // Confirm account cancellation request. + $mails = $this->drupalGetMails(); + $mail = end($mails); + preg_match('@http.+?(user/\d+/cancel/confirm/\d+/[^\s]+)@', $mail['body'], $matches); + $path = $matches[1]; + $this->drupalGet($path); + $this->assertFalse(user_load($account->uid, TRUE), t('User is not found in the database.')); + + $this->drupalGet('admin/reports/visitors'); + $this->assertNoText($account->name, t('Did not find user in visitor statistics.')); + } + + /** + * Tests that cron clears day counts and expired access logs. + */ + function testExpiredLogs() { + variable_set('statistics_enable_access_log', 1); + variable_set('statistics_count_content_views', 1); + variable_set('statistics_day_timestamp', 8640000); + variable_set('statistics_flush_accesslog_timer', 1); + + $this->drupalGet('node/' . $this->test_node->nid); + // Manually calling statistics.php, simulating ajax behavior. + $nid = $this->test_node->nid; + $post = http_build_query(array('nid' => $nid)); + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + global $base_url; + $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $this->drupalGet('node/' . $this->test_node->nid); + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $this->assertText('1 view', t('Node is viewed once.')); + + $this->drupalGet('admin/reports/pages'); + $this->assertText('node/' . $this->test_node->nid, t('Hit URL found.')); + + // statistics_cron will subtract the statistics_flush_accesslog_timer + // variable from REQUEST_TIME in the delete query, so wait two secs here to + // make sure the access log will be flushed for the node just hit. + sleep(2); + $this->cronRun(); + + $this->drupalGet('admin/reports/pages'); + $this->assertNoText('node/' . $this->test_node->nid, t('No hit URL found.')); + + $result = db_select('node_counter', 'nc') + ->fields('nc', array('daycount')) + ->condition('nid', $this->test_node->nid, '=') + ->execute() + ->fetchField(); + $this->assertFalse($result, t('Daycounter is zero.')); + } +} diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsBlockVisitorsTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsBlockVisitorsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c8786ce7a5cbadb0ba30b8dd44195db2d9f11145 --- /dev/null +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsBlockVisitorsTest.php @@ -0,0 +1,58 @@ +<?php + +/** + * @file + * Definition of Drupal\statistics\Tests\StatisticsBlockVisitorsTest. + */ + +namespace Drupal\statistics\Tests; + +/** + * Tests that the visitor blocking functionality works. + */ +class StatisticsBlockVisitorsTest extends StatisticsTestBase { + public static function getInfo() { + return array( + 'name' => 'Top visitor blocking', + 'description' => 'Tests blocking of IP addresses via the top visitors report.', + 'group' => 'Statistics' + ); + } + + /** + * Blocks an IP address via the top visitors report and then unblocks it. + */ + function testIPAddressBlocking() { + // IP address for testing. + $test_ip_address = '192.168.1.1'; + + // Verify the IP address from accesslog appears on the top visitors page + // and that a 'block IP address' link is displayed. + $this->drupalLogin($this->blocking_user); + $this->drupalGet('admin/reports/visitors'); + $this->assertText($test_ip_address, t('IP address found.')); + $this->assertText(t('block IP address'), t('Block IP link displayed')); + + // Block the IP address. + $this->clickLink('block IP address'); + $this->assertText(t('IP address blocking'), t('IP blocking page displayed.')); + $edit = array(); + $edit['ip'] = $test_ip_address; + $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); + $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField(); + $this->assertNotEqual($ip, FALSE, t('IP address found in database')); + $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.')); + + // Verify that the block/unblock link on the top visitors page has been + // altered. + $this->drupalGet('admin/reports/visitors'); + $this->assertText(t('unblock IP address'), t('Unblock IP address link displayed')); + + // Unblock the IP address. + $this->clickLink('unblock IP address'); + $this->assertRaw(t('Are you sure you want to delete %ip?', array('%ip' => $test_ip_address)), t('IP address deletion confirmation found.')); + $edit = array(); + $this->drupalPost('admin/config/people/ip-blocking/delete/1', NULL, t('Delete')); + $this->assertRaw(t('The IP address %ip was deleted.', array('%ip' => $test_ip_address)), t('IP address deleted.')); + } +} diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e0a25f907e97cf5d48e368d39de3e143a6f665dc --- /dev/null +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php @@ -0,0 +1,130 @@ +<?php + +/** + * @file + * Definition of Drupal\statistics\Tests\StatisticsLoggingTest. + */ + +namespace Drupal\statistics\Tests; + +use Drupal\simpletest\WebTestBase; +use PDO; + +/** + * Tests that logging via statistics_exit() works for all pages. + * + * We subclass WebTestBase rather than StatisticsTestBase, because we + * want to test requests from an anonymous user. + */ +class StatisticsLoggingTest extends WebTestBase { + public static function getInfo() { + return array( + 'name' => 'Statistics logging tests', + 'description' => 'Tests request logging for cached and uncached pages.', + 'group' => 'Statistics' + ); + } + + function setUp() { + parent::setUp(array('statistics', 'block')); + + // Create Basic page node type. + if ($this->profile != 'standard') { + $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); + } + + $this->auth_user = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content')); + + // Ensure we have a node page to access. + $this->node = $this->drupalCreateNode(array('title' => $this->randomName(255), 'uid' => $this->auth_user->uid)); + + // Enable page caching. + $config = config('system.performance'); + $config->set('cache', 1); + $config->save(); + + // Enable access logging. + variable_set('statistics_enable_access_log', 1); + variable_set('statistics_count_content_views', 1); + + // Clear the logs. + db_truncate('accesslog'); + db_truncate('node_counter'); + } + + /** + * Verifies request logging for cached and uncached pages. + */ + function testLogging() { + $path = 'node/' . $this->node->nid; + $expected = array( + 'title' => $this->node->title, + 'path' => $path, + ); + + // Verify logging of an uncached page. + $this->drupalGet($path); + // Manually calling statistics.php, simulating ajax behavior. + $nid = $this->node->nid; + $post = http_build_query(array('nid' => $nid)); + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + global $base_url; + $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', t('Testing an uncached page.')); + $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); + $this->assertTrue(is_array($log) && count($log) == 1, t('Page request was logged.')); + $this->assertEqual(array_intersect_key($log[0], $expected), $expected); + $node_counter = statistics_get($this->node->nid); + $this->assertIdentical($node_counter['totalcount'], '1'); + + // Verify logging of a cached page. + $this->drupalGet($path); + // Manually calling statistics.php, simulating ajax behavior. + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Testing a cached page.')); + $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); + $this->assertTrue(is_array($log) && count($log) == 2, t('Page request was logged.')); + $this->assertEqual(array_intersect_key($log[1], $expected), $expected); + $node_counter = statistics_get($this->node->nid); + $this->assertIdentical($node_counter['totalcount'], '2'); + + // Test logging from authenticated users + $this->drupalLogin($this->auth_user); + $this->drupalGet($path); + // Manually calling statistics.php, simulating ajax behavior. + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); + // Check the 6th item since login and account pages are also logged + $this->assertTrue(is_array($log) && count($log) == 6, t('Page request was logged.')); + $this->assertEqual(array_intersect_key($log[5], $expected), $expected); + $node_counter = statistics_get($this->node->nid); + $this->assertIdentical($node_counter['totalcount'], '3'); + + // Visit edit page to generate a title greater than 255. + $path = 'node/' . $this->node->nid . '/edit'; + $expected = array( + 'title' => truncate_utf8(t('Edit Basic page') . ' ' . $this->node->title, 255), + 'path' => $path, + ); + $this->drupalGet($path); + $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); + $this->assertTrue(is_array($log) && count($log) == 7, t('Page request was logged.')); + $this->assertEqual(array_intersect_key($log[6], $expected), $expected); + + // Create a path longer than 255 characters. Drupal's .htaccess file + // instructs Apache to test paths against the file system before routing to + // index.php. Many file systems restrict file names to 255 characters + // (http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits), and + // Apache returns a 403 when testing longer file names, but the total path + // length is not restricted. + $long_path = $this->randomName(127) . '/' . $this->randomName(128); + + // Test that the long path is properly truncated when logged. + $this->drupalGet($long_path); + $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); + $this->assertTrue(is_array($log) && count($log) == 8, 'Page request was logged for a path over 255 characters.'); + $this->assertEqual($log[7]['path'], truncate_utf8($long_path, 255)); + + } +} diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7c0007ab237b2176a51d9e61739abb9adda535c8 --- /dev/null +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php @@ -0,0 +1,105 @@ +<?php + +/** + * @file + * Definition of Drupal\statistics\Tests\StatisticsReportsTest. + */ + +namespace Drupal\statistics\Tests; + +/** + * Tests that report pages render properly, and that access logging works. + */ +class StatisticsReportsTest extends StatisticsTestBase { + public static function getInfo() { + return array( + 'name' => 'Statistics reports tests', + 'description' => 'Tests display of statistics report pages and access logging.', + 'group' => 'Statistics' + ); + } + + /** + * Verifies that 'Recent hits' renders properly and displays the added hit. + */ + function testRecentHits() { + $this->drupalGet('admin/reports/hits'); + $this->assertText('test', t('Hit title found.')); + $this->assertText('node/1', t('Hit URL found.')); + $this->assertText('Anonymous', t('Hit user found.')); + } + + /** + * Verifies that 'Top pages' renders properly and displays the added hit. + */ + function testTopPages() { + $this->drupalGet('admin/reports/pages'); + $this->assertText('test', t('Hit title found.')); + $this->assertText('node/1', t('Hit URL found.')); + } + + /** + * Verifies that 'Top referrers' renders properly and displays the added hit. + */ + function testTopReferrers() { + $this->drupalGet('admin/reports/referrers'); + $this->assertText('http://example.com', t('Hit referrer found.')); + } + + /** + * Verifies that 'Details' page renders properly and displays the added hit. + */ + function testDetails() { + $this->drupalGet('admin/reports/access/1'); + $this->assertText('test', t('Hit title found.')); + $this->assertText('node/1', t('Hit URL found.')); + $this->assertText('Anonymous', t('Hit user found.')); + } + + /** + * Verifies that access logging is working and is reported correctly. + */ + function testAccessLogging() { + $this->drupalGet('admin/reports/referrers'); + $this->drupalGet('admin/reports/hits'); + $this->assertText('Top referrers in the past 3 days', t('Hit title found.')); + $this->assertText('admin/reports/referrers', t('Hit URL found.')); + } + + /** + * Tests the "popular content" block. + */ + function testPopularContentBlock() { + // Visit a node to have something show up in the block. + $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->blocking_user->uid)); + $this->drupalGet('node/' . $node->nid); + // Manually calling statistics.php, simulating ajax behavior. + $nid = $node->nid; + $post = http_build_query(array('nid' => $nid)); + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + global $base_url; + $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + + // Configure and save the block. + $block = block_load('statistics', 'popular'); + $block->theme = variable_get('theme_default', 'stark'); + $block->status = 1; + $block->pages = ''; + $block->region = 'sidebar_first'; + $block->cache = -1; + $block->visibility = 0; + $edit = array('statistics_block_top_day_num' => 3, 'statistics_block_top_all_num' => 3, 'statistics_block_top_last_num' => 3); + module_invoke('statistics', 'block_save', 'popular', $edit); + drupal_write_record('block', $block); + + // Get some page and check if the block is displayed. + $this->drupalGet('user'); + $this->assertText('Popular content', t('Found the popular content block.')); + $this->assertText("Today's", t('Found today\'s popular content.')); + $this->assertText('All time', t('Found the alll time popular content.')); + $this->assertText('Last viewed', t('Found the last viewed popular content.')); + + $this->assertRaw(l($node->title, 'node/' . $node->nid), t('Found link to visited node.')); + } +} diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTestBase.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..11831558d463dfedd8090d75a87939c7f3e8f116 --- /dev/null +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTestBase.php @@ -0,0 +1,55 @@ +<?php + +/** + * @file + * Definition of Drupal\statistics\Tests\StatisticsTestBase. + */ + +namespace Drupal\statistics\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Defines a base class for testing the Statistics module. + */ +class StatisticsTestBase extends WebTestBase { + + function setUp() { + parent::setUp(array('node', 'block', 'statistics')); + + // Create Basic page node type. + if ($this->profile != 'standard') { + $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); + } + + // Create user. + $this->blocking_user = $this->drupalCreateUser(array( + 'access administration pages', + 'access site reports', + 'access statistics', + 'block IP addresses', + 'administer blocks', + 'administer statistics', + 'administer users', + )); + $this->drupalLogin($this->blocking_user); + + // Enable access logging. + variable_set('statistics_enable_access_log', 1); + variable_set('statistics_count_content_views', 1); + + // Insert dummy access by anonymous user into access log. + db_insert('accesslog') + ->fields(array( + 'title' => 'test', + 'path' => 'node/1', + 'url' => 'http://example.com', + 'hostname' => '192.168.1.1', + 'uid' => 0, + 'sid' => 10, + 'timer' => 10, + 'timestamp' => REQUEST_TIME, + )) + ->execute(); + } +} diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..304561138c8611e91b7724457edfc6eb832b5154 --- /dev/null +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php @@ -0,0 +1,59 @@ +<?php + +/** + * @file + * Definition of Drupal\statistics\Tests\StatisticsTokenReplaceTest. + */ + +namespace Drupal\statistics\Tests; + +/** + * Tests statistics token replacement in strings. + */ +class StatisticsTokenReplaceTest extends StatisticsTestBase { + public static function getInfo() { + return array( + 'name' => 'Statistics token replacement', + 'description' => 'Generates text using placeholders for dummy content to check statistics token replacement.', + 'group' => 'Statistics', + ); + } + + /** + * Creates a node, then tests the statistics tokens generated from it. + */ + function testStatisticsTokenReplacement() { + global $language_interface; + + // Create user and node. + $user = $this->drupalCreateUser(array('create page content')); + $this->drupalLogin($user); + $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $user->uid)); + + // Hit the node. + $this->drupalGet('node/' . $node->nid); + // Manually calling statistics.php, simulating ajax behavior. + $nid = $node->nid; + $post = http_build_query(array('nid' => $nid)); + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + global $base_url; + $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; + drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); + $statistics = statistics_get($node->nid); + + // Generate and test tokens. + $tests = array(); + $tests['[node:total-count]'] = 1; + $tests['[node:day-count]'] = 1; + $tests['[node:last-view]'] = format_date($statistics['timestamp']); + $tests['[node:last-view:short]'] = format_date($statistics['timestamp'], 'short'); + + // Test to make sure that we generated something for each token. + $this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.')); + + foreach ($tests as $input => $expected) { + $output = token_replace($input, array('node' => $node), array('language' => $language_interface)); + $this->assertEqual($output, $expected, t('Statistics token %token replaced.', array('%token' => $input))); + } + } +} diff --git a/core/modules/statistics/statistics.info b/core/modules/statistics/statistics.info index e7add6033adfb2eff6643688f39cc0c1b6752ae8..4b18b8a0dfe3cba6fe54bdd768569296dc43e7ca 100644 --- a/core/modules/statistics/statistics.info +++ b/core/modules/statistics/statistics.info @@ -3,5 +3,4 @@ description = Logs access statistics for your site. package = Core version = VERSION core = 8.x -files[] = statistics.test configure = admin/config/system/statistics diff --git a/core/modules/statistics/statistics.test b/core/modules/statistics/statistics.test deleted file mode 100644 index bb28b01cb3dba278569a6f4406f6f3a52996f488..0000000000000000000000000000000000000000 --- a/core/modules/statistics/statistics.test +++ /dev/null @@ -1,557 +0,0 @@ -<?php - -/** - * @file - * Tests for the Statistics module. - */ - -use Drupal\simpletest\WebTestBase; - -/** - * Defines a base class for testing the Statistics module. - */ -class StatisticsTestCase extends WebTestBase { - - function setUp() { - parent::setUp(array('node', 'block', 'statistics')); - - // Create Basic page node type. - if ($this->profile != 'standard') { - $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); - } - - // Create user. - $this->blocking_user = $this->drupalCreateUser(array( - 'access administration pages', - 'access site reports', - 'access statistics', - 'block IP addresses', - 'administer blocks', - 'administer statistics', - 'administer users', - )); - $this->drupalLogin($this->blocking_user); - - // Enable access logging. - variable_set('statistics_enable_access_log', 1); - variable_set('statistics_count_content_views', 1); - - // Insert dummy access by anonymous user into access log. - db_insert('accesslog') - ->fields(array( - 'title' => 'test', - 'path' => 'node/1', - 'url' => 'http://example.com', - 'hostname' => '192.168.1.1', - 'uid' => 0, - 'sid' => 10, - 'timer' => 10, - 'timestamp' => REQUEST_TIME, - )) - ->execute(); - } -} - -/** - * Tests that logging via statistics_exit() works for all pages. - * - * We subclass WebTestBase rather than StatisticsTestCase, because we - * want to test requests from an anonymous user. - */ -class StatisticsLoggingTestCase extends WebTestBase { - public static function getInfo() { - return array( - 'name' => 'Statistics logging tests', - 'description' => 'Tests request logging for cached and uncached pages.', - 'group' => 'Statistics' - ); - } - - function setUp() { - parent::setUp(array('statistics', 'block')); - - // Create Basic page node type. - if ($this->profile != 'standard') { - $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); - } - - $this->auth_user = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content')); - - // Ensure we have a node page to access. - $this->node = $this->drupalCreateNode(array('title' => $this->randomName(255), 'uid' => $this->auth_user->uid)); - - // Enable page caching. - $config = config('system.performance'); - $config->set('cache', 1); - $config->save(); - - // Enable access logging. - variable_set('statistics_enable_access_log', 1); - variable_set('statistics_count_content_views', 1); - - // Clear the logs. - db_truncate('accesslog'); - db_truncate('node_counter'); - } - - /** - * Verifies request logging for cached and uncached pages. - */ - function testLogging() { - $path = 'node/' . $this->node->nid; - $expected = array( - 'title' => $this->node->title, - 'path' => $path, - ); - - // Verify logging of an uncached page. - $this->drupalGet($path); - // Manually calling statistics.php, simulating ajax behavior. - $nid = $this->node->nid; - $post = http_build_query(array('nid' => $nid)); - $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); - global $base_url; - $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', t('Testing an uncached page.')); - $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 1, t('Page request was logged.')); - $this->assertEqual(array_intersect_key($log[0], $expected), $expected); - $node_counter = statistics_get($this->node->nid); - $this->assertIdentical($node_counter['totalcount'], '1'); - - // Verify logging of a cached page. - $this->drupalGet($path); - // Manually calling statistics.php, simulating ajax behavior. - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Testing a cached page.')); - $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 2, t('Page request was logged.')); - $this->assertEqual(array_intersect_key($log[1], $expected), $expected); - $node_counter = statistics_get($this->node->nid); - $this->assertIdentical($node_counter['totalcount'], '2'); - - // Test logging from authenticated users - $this->drupalLogin($this->auth_user); - $this->drupalGet($path); - // Manually calling statistics.php, simulating ajax behavior. - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - // Check the 6th item since login and account pages are also logged - $this->assertTrue(is_array($log) && count($log) == 6, t('Page request was logged.')); - $this->assertEqual(array_intersect_key($log[5], $expected), $expected); - $node_counter = statistics_get($this->node->nid); - $this->assertIdentical($node_counter['totalcount'], '3'); - - // Visit edit page to generate a title greater than 255. - $path = 'node/' . $this->node->nid . '/edit'; - $expected = array( - 'title' => truncate_utf8(t('Edit Basic page') . ' ' . $this->node->title, 255), - 'path' => $path, - ); - $this->drupalGet($path); - $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 7, t('Page request was logged.')); - $this->assertEqual(array_intersect_key($log[6], $expected), $expected); - - // Create a path longer than 255 characters. Drupal's .htaccess file - // instructs Apache to test paths against the file system before routing to - // index.php. Many file systems restrict file names to 255 characters - // (http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits), and - // Apache returns a 403 when testing longer file names, but the total path - // length is not restricted. - $long_path = $this->randomName(127) . '/' . $this->randomName(128); - - // Test that the long path is properly truncated when logged. - $this->drupalGet($long_path); - $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 8, 'Page request was logged for a path over 255 characters.'); - $this->assertEqual($log[7]['path'], truncate_utf8($long_path, 255)); - - } -} - -/** - * Tests that report pages render properly, and that access logging works. - */ -class StatisticsReportsTestCase extends StatisticsTestCase { - public static function getInfo() { - return array( - 'name' => 'Statistics reports tests', - 'description' => 'Tests display of statistics report pages and access logging.', - 'group' => 'Statistics' - ); - } - - /** - * Verifies that 'Recent hits' renders properly and displays the added hit. - */ - function testRecentHits() { - $this->drupalGet('admin/reports/hits'); - $this->assertText('test', t('Hit title found.')); - $this->assertText('node/1', t('Hit URL found.')); - $this->assertText('Anonymous', t('Hit user found.')); - } - - /** - * Verifies that 'Top pages' renders properly and displays the added hit. - */ - function testTopPages() { - $this->drupalGet('admin/reports/pages'); - $this->assertText('test', t('Hit title found.')); - $this->assertText('node/1', t('Hit URL found.')); - } - - /** - * Verifies that 'Top referrers' renders properly and displays the added hit. - */ - function testTopReferrers() { - $this->drupalGet('admin/reports/referrers'); - $this->assertText('http://example.com', t('Hit referrer found.')); - } - - /** - * Verifies that 'Details' page renders properly and displays the added hit. - */ - function testDetails() { - $this->drupalGet('admin/reports/access/1'); - $this->assertText('test', t('Hit title found.')); - $this->assertText('node/1', t('Hit URL found.')); - $this->assertText('Anonymous', t('Hit user found.')); - } - - /** - * Verifies that access logging is working and is reported correctly. - */ - function testAccessLogging() { - $this->drupalGet('admin/reports/referrers'); - $this->drupalGet('admin/reports/hits'); - $this->assertText('Top referrers in the past 3 days', t('Hit title found.')); - $this->assertText('admin/reports/referrers', t('Hit URL found.')); - } - - /** - * Tests the "popular content" block. - */ - function testPopularContentBlock() { - // Visit a node to have something show up in the block. - $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->blocking_user->uid)); - $this->drupalGet('node/' . $node->nid); - // Manually calling statistics.php, simulating ajax behavior. - $nid = $node->nid; - $post = http_build_query(array('nid' => $nid)); - $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); - global $base_url; - $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - - // Configure and save the block. - $block = block_load('statistics', 'popular'); - $block->theme = variable_get('theme_default', 'stark'); - $block->status = 1; - $block->pages = ''; - $block->region = 'sidebar_first'; - $block->cache = -1; - $block->visibility = 0; - $edit = array('statistics_block_top_day_num' => 3, 'statistics_block_top_all_num' => 3, 'statistics_block_top_last_num' => 3); - module_invoke('statistics', 'block_save', 'popular', $edit); - drupal_write_record('block', $block); - - // Get some page and check if the block is displayed. - $this->drupalGet('user'); - $this->assertText('Popular content', t('Found the popular content block.')); - $this->assertText("Today's", t('Found today\'s popular content.')); - $this->assertText('All time', t('Found the alll time popular content.')); - $this->assertText('Last viewed', t('Found the last viewed popular content.')); - - $this->assertRaw(l($node->title, 'node/' . $node->nid), t('Found link to visited node.')); - } -} - -/** - * Tests that the visitor blocking functionality works. - */ -class StatisticsBlockVisitorsTestCase extends StatisticsTestCase { - public static function getInfo() { - return array( - 'name' => 'Top visitor blocking', - 'description' => 'Tests blocking of IP addresses via the top visitors report.', - 'group' => 'Statistics' - ); - } - - /** - * Blocks an IP address via the top visitors report and then unblocks it. - */ - function testIPAddressBlocking() { - // IP address for testing. - $test_ip_address = '192.168.1.1'; - - // Verify the IP address from accesslog appears on the top visitors page - // and that a 'block IP address' link is displayed. - $this->drupalLogin($this->blocking_user); - $this->drupalGet('admin/reports/visitors'); - $this->assertText($test_ip_address, t('IP address found.')); - $this->assertText(t('block IP address'), t('Block IP link displayed')); - - // Block the IP address. - $this->clickLink('block IP address'); - $this->assertText(t('IP address blocking'), t('IP blocking page displayed.')); - $edit = array(); - $edit['ip'] = $test_ip_address; - $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); - $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField(); - $this->assertNotEqual($ip, FALSE, t('IP address found in database')); - $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.')); - - // Verify that the block/unblock link on the top visitors page has been - // altered. - $this->drupalGet('admin/reports/visitors'); - $this->assertText(t('unblock IP address'), t('Unblock IP address link displayed')); - - // Unblock the IP address. - $this->clickLink('unblock IP address'); - $this->assertRaw(t('Are you sure you want to delete %ip?', array('%ip' => $test_ip_address)), t('IP address deletion confirmation found.')); - $edit = array(); - $this->drupalPost('admin/config/people/ip-blocking/delete/1', NULL, t('Delete')); - $this->assertRaw(t('The IP address %ip was deleted.', array('%ip' => $test_ip_address)), t('IP address deleted.')); - } -} - -/** - * Tests the statistics administration screen. - */ -class StatisticsAdminTestCase extends WebTestBase { - - /** - * A user that has permission to administer and access statistics. - * - * @var object|FALSE - * - * A fully loaded user object, or FALSE if user creation failed. - */ - protected $privileged_user; - - /** - * A page node for which to check access statistics. - * - * @var object - */ - protected $test_node; - - public static function getInfo() { - return array( - 'name' => 'Test statistics admin.', - 'description' => 'Tests the statistics admin.', - 'group' => 'Statistics' - ); - } - - function setUp() { - parent::setUp(array('node', 'statistics')); - - // Create Basic page node type. - if ($this->profile != 'standard') { - $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); - } - $this->privileged_user = $this->drupalCreateUser(array('access statistics', 'administer statistics', 'view post access counter', 'create page content')); - $this->drupalLogin($this->privileged_user); - $this->test_node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->privileged_user->uid)); - } - - /** - * Verifies that the statistics settings page works. - */ - function testStatisticsSettings() { - $this->assertFalse(variable_get('statistics_enable_access_log', 0), t('Access log is disabled by default.')); - $this->assertFalse(variable_get('statistics_count_content_views', 0), t('Count content view log is disabled by default.')); - - $this->drupalGet('admin/reports/pages'); - $this->assertRaw(t('No statistics available.'), t('Verifying text shown when no statistics is available.')); - - // Enable access log and counter on content view. - $edit['statistics_enable_access_log'] = 1; - $edit['statistics_count_content_views'] = 1; - $this->drupalPost('admin/config/system/statistics', $edit, t('Save configuration')); - $this->assertTrue(variable_get('statistics_enable_access_log'), t('Access log is enabled.')); - $this->assertTrue(variable_get('statistics_count_content_views'), t('Count content view log is enabled.')); - - // Hit the node. - $this->drupalGet('node/' . $this->test_node->nid); - // Manually calling statistics.php, simulating ajax behavior. - $nid = $this->test_node->nid; - $post = http_build_query(array('nid' => $nid)); - $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); - global $base_url; - $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - - $this->drupalGet('admin/reports/pages'); - $this->assertText('node/1', t('Test node found.')); - - // Hit the node again (the counter is incremented after the hit, so - // "1 view" will actually be shown when the node is hit the second time). - $this->drupalGet('node/' . $this->test_node->nid); - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $this->assertText('1 view', t('Node is viewed once.')); - - $this->drupalGet('node/' . $this->test_node->nid); - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $this->assertText('2 views', t('Node is viewed 2 times.')); - } - - /** - * Tests that when a node is deleted, the node counter is deleted too. - */ - function testDeleteNode() { - variable_set('statistics_count_content_views', 1); - - $this->drupalGet('node/' . $this->test_node->nid); - // Manually calling statistics.php, simulating ajax behavior. - $nid = $this->test_node->nid; - $post = http_build_query(array('nid' => $nid)); - $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); - global $base_url; - $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - - $result = db_select('node_counter', 'n') - ->fields('n', array('nid')) - ->condition('n.nid', $this->test_node->nid) - ->execute() - ->fetchAssoc(); - $this->assertEqual($result['nid'], $this->test_node->nid, 'Verifying that the node counter is incremented.'); - - node_delete($this->test_node->nid); - - $result = db_select('node_counter', 'n') - ->fields('n', array('nid')) - ->condition('n.nid', $this->test_node->nid) - ->execute() - ->fetchAssoc(); - $this->assertFalse($result, 'Verifying that the node counter is deleted.'); - } - - /** - * Tests that accesslog reflects when a user is deleted. - */ - function testDeleteUser() { - variable_set('statistics_enable_access_log', 1); - - variable_set('user_cancel_method', 'user_cancel_delete'); - $this->drupalLogout($this->privileged_user); - $account = $this->drupalCreateUser(array('access content', 'cancel account')); - $this->drupalLogin($account); - $this->drupalGet('node/' . $this->test_node->nid); - - $account = user_load($account->uid, TRUE); - - $this->drupalGet('user/' . $account->uid . '/edit'); - $this->drupalPost(NULL, NULL, t('Cancel account')); - - $timestamp = time(); - $this->drupalPost(NULL, NULL, t('Cancel account')); - // Confirm account cancellation request. - $mails = $this->drupalGetMails(); - $mail = end($mails); - preg_match('@http.+?(user/\d+/cancel/confirm/\d+/[^\s]+)@', $mail['body'], $matches); - $path = $matches[1]; - $this->drupalGet($path); - $this->assertFalse(user_load($account->uid, TRUE), t('User is not found in the database.')); - - $this->drupalGet('admin/reports/visitors'); - $this->assertNoText($account->name, t('Did not find user in visitor statistics.')); - } - - /** - * Tests that cron clears day counts and expired access logs. - */ - function testExpiredLogs() { - variable_set('statistics_enable_access_log', 1); - variable_set('statistics_count_content_views', 1); - variable_set('statistics_day_timestamp', 8640000); - variable_set('statistics_flush_accesslog_timer', 1); - - $this->drupalGet('node/' . $this->test_node->nid); - // Manually calling statistics.php, simulating ajax behavior. - $nid = $this->test_node->nid; - $post = http_build_query(array('nid' => $nid)); - $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); - global $base_url; - $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $this->drupalGet('node/' . $this->test_node->nid); - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $this->assertText('1 view', t('Node is viewed once.')); - - $this->drupalGet('admin/reports/pages'); - $this->assertText('node/' . $this->test_node->nid, t('Hit URL found.')); - - // statistics_cron will subtract the statistics_flush_accesslog_timer - // variable from REQUEST_TIME in the delete query, so wait two secs here to - // make sure the access log will be flushed for the node just hit. - sleep(2); - $this->cronRun(); - - $this->drupalGet('admin/reports/pages'); - $this->assertNoText('node/' . $this->test_node->nid, t('No hit URL found.')); - - $result = db_select('node_counter', 'nc') - ->fields('nc', array('daycount')) - ->condition('nid', $this->test_node->nid, '=') - ->execute() - ->fetchField(); - $this->assertFalse($result, t('Daycounter is zero.')); - } -} - -/** - * Tests statistics token replacement in strings. - */ -class StatisticsTokenReplaceTestCase extends StatisticsTestCase { - public static function getInfo() { - return array( - 'name' => 'Statistics token replacement', - 'description' => 'Generates text using placeholders for dummy content to check statistics token replacement.', - 'group' => 'Statistics', - ); - } - - /** - * Creates a node, then tests the statistics tokens generated from it. - */ - function testStatisticsTokenReplacement() { - global $language_interface; - - // Create user and node. - $user = $this->drupalCreateUser(array('create page content')); - $this->drupalLogin($user); - $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $user->uid)); - - // Hit the node. - $this->drupalGet('node/' . $node->nid); - // Manually calling statistics.php, simulating ajax behavior. - $nid = $node->nid; - $post = http_build_query(array('nid' => $nid)); - $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); - global $base_url; - $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000)); - $statistics = statistics_get($node->nid); - - // Generate and test tokens. - $tests = array(); - $tests['[node:total-count]'] = 1; - $tests['[node:day-count]'] = 1; - $tests['[node:last-view]'] = format_date($statistics['timestamp']); - $tests['[node:last-view:short]'] = format_date($statistics['timestamp'], 'short'); - - // Test to make sure that we generated something for each token. - $this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.')); - - foreach ($tests as $input => $expected) { - $output = token_replace($input, array('node' => $node), array('language' => $language_interface)); - $this->assertEqual($output, $expected, t('Statistics token %token replaced.', array('%token' => $input))); - } - } -}