xref: /plugin/statistics/_test/LoggerTest.php (revision 569a50664ac8b883b8bdf6f42f326d88d099ad6e)
15cc1319aSAndreas Gohr<?php
25cc1319aSAndreas Gohr
35cc1319aSAndreas Gohrnamespace dokuwiki\plugin\statistics\test;
45cc1319aSAndreas Gohr
5696a1b1bSAndreas Gohruse dokuwiki\plugin\statistics\Logger;
641d1fffcSAndreas Gohruse DokuWikiTest;
7696a1b1bSAndreas Gohruse helper_plugin_statistics;
85cc1319aSAndreas Gohr
95cc1319aSAndreas Gohr/**
10696a1b1bSAndreas Gohr * Tests for the statistics plugin Logger class
115cc1319aSAndreas Gohr *
125cc1319aSAndreas Gohr * @group plugin_statistics
135cc1319aSAndreas Gohr * @group plugins
145cc1319aSAndreas Gohr */
155cc1319aSAndreas Gohrclass LoggerTest extends DokuWikiTest
165cc1319aSAndreas Gohr{
17de1daf8cSAndreas Gohr    protected $pluginsEnabled = ['statistics', 'sqlite'];
18de1daf8cSAndreas Gohr
19696a1b1bSAndreas Gohr    /** @var helper_plugin_statistics */
20696a1b1bSAndreas Gohr    protected $helper;
215cc1319aSAndreas Gohr
2241d1fffcSAndreas Gohr    const SESSION_ID = 'test-session-12345';
2341d1fffcSAndreas Gohr    const USER_ID = 'test-uid-12345';
2441d1fffcSAndreas Gohr    const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36';
25696a1b1bSAndreas Gohr
26696a1b1bSAndreas Gohr    public function setUp(): void
27696a1b1bSAndreas Gohr    {
28696a1b1bSAndreas Gohr        parent::setUp();
29696a1b1bSAndreas Gohr
30696a1b1bSAndreas Gohr        // Load the helper plugin
31696a1b1bSAndreas Gohr        $this->helper = plugin_load('helper', 'statistics');
32696a1b1bSAndreas Gohr
3341d1fffcSAndreas Gohr        // set default user agent
3441d1fffcSAndreas Gohr        $_SERVER['HTTP_USER_AGENT'] = self::USER_AGENT;
35696a1b1bSAndreas Gohr
3641d1fffcSAndreas Gohr        // Set up session data that Logger expects
3741d1fffcSAndreas Gohr        $_SESSION[DOKU_COOKIE]['statistics']['uid'] = self::USER_ID;
3841d1fffcSAndreas Gohr        $_SESSION[DOKU_COOKIE]['statistics']['id'] = self::SESSION_ID;
39696a1b1bSAndreas Gohr    }
40696a1b1bSAndreas Gohr
41696a1b1bSAndreas Gohr    public function tearDown(): void
42696a1b1bSAndreas Gohr    {
43696a1b1bSAndreas Gohr        unset($_SERVER['HTTP_USER_AGENT']);
4441d1fffcSAndreas Gohr        unset($_SESSION[DOKU_COOKIE]['statistics']);
45696a1b1bSAndreas Gohr        parent::tearDown();
46696a1b1bSAndreas Gohr    }
47696a1b1bSAndreas Gohr
48696a1b1bSAndreas Gohr    /**
49696a1b1bSAndreas Gohr     * Test constructor initializes properties correctly
50696a1b1bSAndreas Gohr     */
51696a1b1bSAndreas Gohr    public function testConstructor()
52696a1b1bSAndreas Gohr    {
5341d1fffcSAndreas Gohr        $this->assertInstanceOf(Logger::class, $this->helper->getLogger());
54696a1b1bSAndreas Gohr
55696a1b1bSAndreas Gohr        // Test that bot user agents throw exception
56696a1b1bSAndreas Gohr        $_SERVER['HTTP_USER_AGENT'] = 'Googlebot/2.1 (+http://www.google.com/bot.html)';
57696a1b1bSAndreas Gohr
5841d1fffcSAndreas Gohr        $this->expectException(\dokuwiki\plugin\statistics\IgnoreException::class);
59696a1b1bSAndreas Gohr        $this->expectExceptionMessage('Bot detected, not logging');
60696a1b1bSAndreas Gohr        new Logger($this->helper);
61696a1b1bSAndreas Gohr    }
62696a1b1bSAndreas Gohr
63696a1b1bSAndreas Gohr    /**
64696a1b1bSAndreas Gohr     * Test begin and end transaction methods
65696a1b1bSAndreas Gohr     */
66696a1b1bSAndreas Gohr    public function testBeginEnd()
67696a1b1bSAndreas Gohr    {
6841d1fffcSAndreas Gohr        $this->helper->getLogger()->begin();
69696a1b1bSAndreas Gohr
70696a1b1bSAndreas Gohr        // Verify transaction is active by checking PDO
71696a1b1bSAndreas Gohr        $pdo = $this->helper->getDB()->getPdo();
72696a1b1bSAndreas Gohr        $this->assertTrue($pdo->inTransaction());
73696a1b1bSAndreas Gohr
7441d1fffcSAndreas Gohr        $this->helper->getLogger()->end();
75696a1b1bSAndreas Gohr
76696a1b1bSAndreas Gohr        // Verify transaction is committed
77696a1b1bSAndreas Gohr        $this->assertFalse($pdo->inTransaction());
78696a1b1bSAndreas Gohr    }
79696a1b1bSAndreas Gohr
80696a1b1bSAndreas Gohr    /**
8141d1fffcSAndreas Gohr     * Test user logging
82696a1b1bSAndreas Gohr     */
8341d1fffcSAndreas Gohr    public function testLogUser()
84696a1b1bSAndreas Gohr    {
85696a1b1bSAndreas Gohr        // Test with no user (should not log)
8641d1fffcSAndreas Gohr        $_SERVER['REMOTE_USER'] = '';
8741d1fffcSAndreas Gohr        $this->helper->getLogger()->begin();
8841d1fffcSAndreas Gohr        $this->helper->getLogger()->end();
89696a1b1bSAndreas Gohr
9041d1fffcSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM users');
91696a1b1bSAndreas Gohr        $this->assertEquals(0, $count);
92696a1b1bSAndreas Gohr
93696a1b1bSAndreas Gohr        // Test with user
9441d1fffcSAndreas Gohr        $_SERVER['REMOTE_USER'] = 'testuser';
9541d1fffcSAndreas Gohr        $this->helper->getLogger()->begin();
9641d1fffcSAndreas Gohr        $this->helper->getLogger()->end();
97696a1b1bSAndreas Gohr
9841d1fffcSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM users');
99696a1b1bSAndreas Gohr        $this->assertEquals(1, $count);
100696a1b1bSAndreas Gohr
10141d1fffcSAndreas Gohr        $user = $this->helper->getDB()->queryValue('SELECT user FROM users WHERE user = ?', ['testuser']);
102696a1b1bSAndreas Gohr        $this->assertEquals('testuser', $user);
103696a1b1bSAndreas Gohr    }
104696a1b1bSAndreas Gohr
105696a1b1bSAndreas Gohr    /**
106696a1b1bSAndreas Gohr     * Data provider for logGroups test
107696a1b1bSAndreas Gohr     */
108696a1b1bSAndreas Gohr    public function logGroupsProvider()
109696a1b1bSAndreas Gohr    {
110696a1b1bSAndreas Gohr        return [
11141d1fffcSAndreas Gohr            'empty groups' => [[], 0],
11241d1fffcSAndreas Gohr            'single group' => [['admin'], 1],
11341d1fffcSAndreas Gohr            'multiple groups' => [['admin', 'user'], 2],
11441d1fffcSAndreas Gohr            'filtered groups' => [['admin', 'nonexistent'], 2], // all groups are logged
115696a1b1bSAndreas Gohr        ];
116696a1b1bSAndreas Gohr    }
117696a1b1bSAndreas Gohr
118696a1b1bSAndreas Gohr    /**
119696a1b1bSAndreas Gohr     * Test logGroups method
120696a1b1bSAndreas Gohr     * @dataProvider logGroupsProvider
121696a1b1bSAndreas Gohr     */
12241d1fffcSAndreas Gohr    public function testLogGroups($groups, $expectedCount)
123696a1b1bSAndreas Gohr    {
12441d1fffcSAndreas Gohr        global $USERINFO;
125696a1b1bSAndreas Gohr
12641d1fffcSAndreas Gohr        // Set up a test user and groups
12741d1fffcSAndreas Gohr        $_SERVER['REMOTE_USER'] = 'testuser';
12841d1fffcSAndreas Gohr        $USERINFO = ['grps' => $groups];
12923e0cc03SAndreas Gohr
130696a1b1bSAndreas Gohr
13141d1fffcSAndreas Gohr        $this->helper->getLogger()->begin();
13241d1fffcSAndreas Gohr        $this->helper->getLogger()->end();
13341d1fffcSAndreas Gohr
13441d1fffcSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM groups WHERE user = ?', ['testuser']);
135696a1b1bSAndreas Gohr        $this->assertEquals($expectedCount, $count);
136696a1b1bSAndreas Gohr
137696a1b1bSAndreas Gohr        if ($expectedCount > 0) {
13841d1fffcSAndreas Gohr            $loggedGroups = $this->helper->getDB()->queryAll('SELECT `group` FROM groups WHERE user = ?', ['testuser']);
139696a1b1bSAndreas Gohr            $this->assertCount($expectedCount, $loggedGroups);
140696a1b1bSAndreas Gohr        }
141696a1b1bSAndreas Gohr    }
142696a1b1bSAndreas Gohr
143696a1b1bSAndreas Gohr    /**
14441d1fffcSAndreas Gohr     * Data provider for testLogReferer test
145696a1b1bSAndreas Gohr     */
14641d1fffcSAndreas Gohr    public function logRefererProvider()
147696a1b1bSAndreas Gohr    {
148696a1b1bSAndreas Gohr        return [
149696a1b1bSAndreas Gohr            'google search' => [
150696a1b1bSAndreas Gohr                'https://www.google.com/search?q=dokuwiki+test',
151*569a5066SAndreas Gohr                'google',
152*569a5066SAndreas Gohr                true // should be logged
153696a1b1bSAndreas Gohr            ],
154*569a5066SAndreas Gohr            'bing search' => [
155*569a5066SAndreas Gohr                'https://www.bing.com/search?q=test+query',
156*569a5066SAndreas Gohr                'bing',
157*569a5066SAndreas Gohr                true // should be logged
158*569a5066SAndreas Gohr            ],
159*569a5066SAndreas Gohr            'external referer' => [
160696a1b1bSAndreas Gohr                'https://example.com/page',
161696a1b1bSAndreas Gohr                null,
162*569a5066SAndreas Gohr                true // should be logged
163*569a5066SAndreas Gohr            ],
164*569a5066SAndreas Gohr            'direct access (empty referer)' => [
165*569a5066SAndreas Gohr                '',
166*569a5066SAndreas Gohr                null,
167*569a5066SAndreas Gohr                true // should be logged
168*569a5066SAndreas Gohr            ],
169*569a5066SAndreas Gohr            'ws' => [
170*569a5066SAndreas Gohr                '   ',
171*569a5066SAndreas Gohr                null,
172*569a5066SAndreas Gohr                true // should be logged (trimmed to empty)
173696a1b1bSAndreas Gohr            ],
174696a1b1bSAndreas Gohr        ];
175696a1b1bSAndreas Gohr    }
176696a1b1bSAndreas Gohr
177696a1b1bSAndreas Gohr    /**
17841d1fffcSAndreas Gohr     * Test logReferer method
17941d1fffcSAndreas Gohr     * @dataProvider logRefererProvider
180696a1b1bSAndreas Gohr     */
181*569a5066SAndreas Gohr    public function testLogReferer($referer, $expectedEngine, $shouldBeLogged)
182696a1b1bSAndreas Gohr    {
183*569a5066SAndreas Gohr        $logger = $this->helper->getLogger();
184*569a5066SAndreas Gohr        $logger->begin();
185*569a5066SAndreas Gohr        $refId = $logger->logReferer($referer);
186*569a5066SAndreas Gohr        $logger->end();
187*569a5066SAndreas Gohr
188*569a5066SAndreas Gohr        if ($shouldBeLogged) {
18941d1fffcSAndreas Gohr            $this->assertNotNull($refId);
19041d1fffcSAndreas Gohr            $refererRecord = $this->helper->getDB()->queryRecord('SELECT * FROM referers WHERE id = ?', [$refId]);
191*569a5066SAndreas Gohr            $this->assertNotNull($refererRecord);
19241d1fffcSAndreas Gohr            $this->assertEquals($expectedEngine, $refererRecord['engine']);
193*569a5066SAndreas Gohr            $this->assertEquals(trim($referer), $refererRecord['url']);
194*569a5066SAndreas Gohr        } else {
195*569a5066SAndreas Gohr            $this->assertNull($refId);
196*569a5066SAndreas Gohr        }
197*569a5066SAndreas Gohr    }
198*569a5066SAndreas Gohr
199*569a5066SAndreas Gohr    /**
200*569a5066SAndreas Gohr     * Test that internal referers (our own pages) are not logged
201*569a5066SAndreas Gohr     */
202*569a5066SAndreas Gohr    public function testLogRefererInternal()
203*569a5066SAndreas Gohr    {
204*569a5066SAndreas Gohr        // Test internal referer (should return null and not be logged)
205*569a5066SAndreas Gohr        $internalReferer = DOKU_URL;
206*569a5066SAndreas Gohr        $refId = $this->helper->getLogger()->logReferer($internalReferer);
207*569a5066SAndreas Gohr        $this->assertNull($refId, 'Internal referers should not be logged');
208*569a5066SAndreas Gohr
209*569a5066SAndreas Gohr        // Verify no referer was actually stored
210*569a5066SAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM referers WHERE url = ?', [$internalReferer]);
211*569a5066SAndreas Gohr        $this->assertEquals(0, $count, 'Internal referer should not be stored in database');
212*569a5066SAndreas Gohr
213*569a5066SAndreas Gohr        // Test another internal referer pattern
214*569a5066SAndreas Gohr        $internalReferer2 = rtrim(DOKU_URL, '/') . '/doku.php?id=start';
215*569a5066SAndreas Gohr        $refId2 = $this->helper->getLogger()->logReferer($internalReferer2);
216*569a5066SAndreas Gohr        $this->assertNull($refId2, 'Internal wiki pages should not be logged as referers');
217696a1b1bSAndreas Gohr    }
218696a1b1bSAndreas Gohr
219696a1b1bSAndreas Gohr    /**
220696a1b1bSAndreas Gohr     * Test logSearch method
221696a1b1bSAndreas Gohr     */
222696a1b1bSAndreas Gohr    public function testLogSearch()
223696a1b1bSAndreas Gohr    {
224696a1b1bSAndreas Gohr        $query = 'test search query';
225696a1b1bSAndreas Gohr        $words = ['test', 'search', 'query'];
226696a1b1bSAndreas Gohr
22741d1fffcSAndreas Gohr        $this->helper->getLogger()->logSearch($query, $words);
228696a1b1bSAndreas Gohr
229696a1b1bSAndreas Gohr        // Check search table
230696a1b1bSAndreas Gohr        $search = $this->helper->getDB()->queryRecord('SELECT * FROM search ORDER BY dt DESC LIMIT 1');
231696a1b1bSAndreas Gohr        $this->assertEquals($query, $search['query']);
232696a1b1bSAndreas Gohr
233696a1b1bSAndreas Gohr        // Check searchwords table
234de1daf8cSAndreas Gohr        $wordCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM searchwords WHERE sid = ?', [$search['id']]);
235696a1b1bSAndreas Gohr        $this->assertEquals(3, $wordCount);
236696a1b1bSAndreas Gohr
237de1daf8cSAndreas Gohr        $loggedWords = $this->helper->getDB()->queryAll('SELECT word FROM searchwords WHERE sid = ? ORDER BY word', [$search['id']]);
238696a1b1bSAndreas Gohr        $this->assertEquals(['query', 'search', 'test'], array_column($loggedWords, 'word'));
239696a1b1bSAndreas Gohr    }
240696a1b1bSAndreas Gohr
241696a1b1bSAndreas Gohr    /**
242696a1b1bSAndreas Gohr     * Test logSession method
243696a1b1bSAndreas Gohr     */
244696a1b1bSAndreas Gohr    public function testLogSession()
245696a1b1bSAndreas Gohr    {
24641d1fffcSAndreas Gohr        $_SERVER['REMOTE_USER'] = 'testuser';
247696a1b1bSAndreas Gohr
24841d1fffcSAndreas Gohr        // Test session creation
24941d1fffcSAndreas Gohr        $logger = $this->helper->getLogger();
25041d1fffcSAndreas Gohr
25141d1fffcSAndreas Gohr        $logger->begin();
25241d1fffcSAndreas Gohr        $logger->end();
25341d1fffcSAndreas Gohr
25441d1fffcSAndreas Gohr        $sessionCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM sessions');
255696a1b1bSAndreas Gohr        $this->assertEquals(1, $sessionCount);
256696a1b1bSAndreas Gohr
25741d1fffcSAndreas Gohr        $session = $this->helper->getDB()->queryRecord('SELECT * FROM sessions LIMIT 1');
25841d1fffcSAndreas Gohr        $this->assertIsArray($session);
25941d1fffcSAndreas Gohr        $this->assertEquals('testuser', $session['user']);
26041d1fffcSAndreas Gohr        $this->assertEquals(self::SESSION_ID, $session['session']);
26141d1fffcSAndreas Gohr        $this->assertEquals(self::USER_ID, $session['uid']);
26241d1fffcSAndreas Gohr        $this->assertEquals(self::USER_AGENT, $session['ua']);
26341d1fffcSAndreas Gohr        $this->assertEquals('Chrome', $session['ua_info']);
26441d1fffcSAndreas Gohr        $this->assertEquals('browser', $session['ua_type']);
26541d1fffcSAndreas Gohr        $this->assertEquals('91', $session['ua_ver']);
26641d1fffcSAndreas Gohr        $this->assertEquals('Windows', $session['os']);
267696a1b1bSAndreas Gohr
268696a1b1bSAndreas Gohr    }
269696a1b1bSAndreas Gohr
270696a1b1bSAndreas Gohr    /**
271696a1b1bSAndreas Gohr     * Test logIp method
272696a1b1bSAndreas Gohr     */
273696a1b1bSAndreas Gohr    public function testLogIp()
274696a1b1bSAndreas Gohr    {
275696a1b1bSAndreas Gohr        $ip = '8.8.8.8';
27641d1fffcSAndreas Gohr        $_SERVER['REMOTE_ADDR'] = $ip;
277696a1b1bSAndreas Gohr
278c7cad24dSAndreas Gohr        // Create a mock HTTP client
279c7cad24dSAndreas Gohr        $mockHttpClient = $this->createMock(\dokuwiki\HTTP\DokuHTTPClient::class);
2806c24c4b8SAndreas Gohr
281c7cad24dSAndreas Gohr        // Mock the API response
282c7cad24dSAndreas Gohr        $mockResponse = json_encode([
283c7cad24dSAndreas Gohr            'status' => 'success',
284c7cad24dSAndreas Gohr            'country' => 'United States',
285c7cad24dSAndreas Gohr            'countryCode' => 'US',
286c7cad24dSAndreas Gohr            'city' => 'Ashburn',
287c7cad24dSAndreas Gohr            'query' => $ip
288c7cad24dSAndreas Gohr        ]);
2896c24c4b8SAndreas Gohr
290c7cad24dSAndreas Gohr        $mockHttpClient->expects($this->once())
291c7cad24dSAndreas Gohr            ->method('get')
292c7cad24dSAndreas Gohr            ->with('http://ip-api.com/json/' . $ip)
293c7cad24dSAndreas Gohr            ->willReturn($mockResponse);
294696a1b1bSAndreas Gohr
295c7cad24dSAndreas Gohr        // Set timeout property
296c7cad24dSAndreas Gohr        $mockHttpClient->timeout = 10;
297c7cad24dSAndreas Gohr
298c7cad24dSAndreas Gohr        // Create logger with mock HTTP client
299c7cad24dSAndreas Gohr        $logger = new Logger($this->helper, $mockHttpClient);
300c7cad24dSAndreas Gohr
301c7cad24dSAndreas Gohr        // Test with IP that doesn't exist in database
30241d1fffcSAndreas Gohr        $logger->logIp();
303c7cad24dSAndreas Gohr
304c7cad24dSAndreas Gohr        // Verify the IP was logged
305c7cad24dSAndreas Gohr        $ipRecord = $this->helper->getDB()->queryRecord('SELECT * FROM iplocation WHERE ip = ?', [$ip]);
306c7cad24dSAndreas Gohr        $this->assertNotNull($ipRecord);
307c7cad24dSAndreas Gohr        $this->assertEquals($ip, $ipRecord['ip']);
308c7cad24dSAndreas Gohr        $this->assertEquals('United States', $ipRecord['country']);
309c7cad24dSAndreas Gohr        $this->assertEquals('US', $ipRecord['code']);
310c7cad24dSAndreas Gohr        $this->assertEquals('Ashburn', $ipRecord['city']);
311c7cad24dSAndreas Gohr        $this->assertNotEmpty($ipRecord['host']); // gethostbyaddr result
312c7cad24dSAndreas Gohr
313c7cad24dSAndreas Gohr        // Test with IP that already exists and is recent (should not make HTTP call)
314c7cad24dSAndreas Gohr        $mockHttpClient2 = $this->createMock(\dokuwiki\HTTP\DokuHTTPClient::class);
315c7cad24dSAndreas Gohr        $mockHttpClient2->expects($this->never())->method('get');
316c7cad24dSAndreas Gohr
317c7cad24dSAndreas Gohr        $logger2 = new Logger($this->helper, $mockHttpClient2);
31841d1fffcSAndreas Gohr        $logger2->logIp(); // Should not trigger HTTP call
319696a1b1bSAndreas Gohr    }
320696a1b1bSAndreas Gohr
321696a1b1bSAndreas Gohr    /**
322696a1b1bSAndreas Gohr     * Test logOutgoing method
323696a1b1bSAndreas Gohr     */
324696a1b1bSAndreas Gohr    public function testLogOutgoing()
325696a1b1bSAndreas Gohr    {
326696a1b1bSAndreas Gohr        global $INPUT;
327696a1b1bSAndreas Gohr
328696a1b1bSAndreas Gohr        // Test without outgoing link
329696a1b1bSAndreas Gohr        $INPUT->set('ol', '');
33041d1fffcSAndreas Gohr        $this->helper->getLogger()->logOutgoing();
331696a1b1bSAndreas Gohr
332696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM outlinks');
333696a1b1bSAndreas Gohr        $this->assertEquals(0, $count);
334696a1b1bSAndreas Gohr
335696a1b1bSAndreas Gohr        // Test with outgoing link
336696a1b1bSAndreas Gohr        $link = 'https://example.com';
337696a1b1bSAndreas Gohr        $page = 'test:page';
338696a1b1bSAndreas Gohr        $INPUT->set('ol', $link);
339696a1b1bSAndreas Gohr        $INPUT->set('p', $page);
340696a1b1bSAndreas Gohr
34141d1fffcSAndreas Gohr        $this->helper->getLogger()->logOutgoing();
342696a1b1bSAndreas Gohr
343696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM outlinks');
344696a1b1bSAndreas Gohr        $this->assertEquals(1, $count);
345696a1b1bSAndreas Gohr
346696a1b1bSAndreas Gohr        $outlink = $this->helper->getDB()->queryRecord('SELECT * FROM outlinks ORDER BY dt DESC LIMIT 1');
347696a1b1bSAndreas Gohr        $this->assertEquals($link, $outlink['link']);
348696a1b1bSAndreas Gohr        $this->assertEquals($page, $outlink['page']);
349696a1b1bSAndreas Gohr    }
350696a1b1bSAndreas Gohr
351696a1b1bSAndreas Gohr    /**
35241d1fffcSAndreas Gohr     * Test logPageView method
353696a1b1bSAndreas Gohr     */
35441d1fffcSAndreas Gohr    public function testLogPageView()
355696a1b1bSAndreas Gohr    {
356de1daf8cSAndreas Gohr        global $INPUT, $USERINFO, $conf;
357de1daf8cSAndreas Gohr
358de1daf8cSAndreas Gohr        $conf['plugin']['statistics']['loggroups'] = ['admin', 'user'];
359696a1b1bSAndreas Gohr
360696a1b1bSAndreas Gohr        $page = 'test:page';
361696a1b1bSAndreas Gohr        $referer = 'https://example.com';
362696a1b1bSAndreas Gohr        $user = 'testuser';
363696a1b1bSAndreas Gohr
364696a1b1bSAndreas Gohr        $INPUT->set('p', $page);
365696a1b1bSAndreas Gohr        $INPUT->set('r', $referer);
366696a1b1bSAndreas Gohr        $INPUT->set('sx', 1920);
367696a1b1bSAndreas Gohr        $INPUT->set('sy', 1080);
368696a1b1bSAndreas Gohr        $INPUT->set('vx', 1200);
369696a1b1bSAndreas Gohr        $INPUT->set('vy', 800);
370696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', $user);
371696a1b1bSAndreas Gohr
372696a1b1bSAndreas Gohr        $USERINFO = ['grps' => ['admin', 'user']];
373696a1b1bSAndreas Gohr
37441d1fffcSAndreas Gohr        $logger = $this->helper->getLogger();
37541d1fffcSAndreas Gohr        $logger->begin();
37641d1fffcSAndreas Gohr        $logger->logPageView();
37741d1fffcSAndreas Gohr        $logger->end();
378696a1b1bSAndreas Gohr
37941d1fffcSAndreas Gohr        // Check pageviews table
38041d1fffcSAndreas Gohr        $pageview = $this->helper->getDB()->queryRecord('SELECT * FROM pageviews ORDER BY dt DESC LIMIT 1');
38141d1fffcSAndreas Gohr        $this->assertEquals($page, $pageview['page']);
38241d1fffcSAndreas Gohr        $this->assertEquals(1920, $pageview['screen_x']);
38341d1fffcSAndreas Gohr        $this->assertEquals(1080, $pageview['screen_y']);
38441d1fffcSAndreas Gohr        $this->assertEquals(1200, $pageview['view_x']);
38541d1fffcSAndreas Gohr        $this->assertEquals(800, $pageview['view_y']);
38641d1fffcSAndreas Gohr        $this->assertEquals(self::SESSION_ID, $pageview['session']);
387696a1b1bSAndreas Gohr    }
388696a1b1bSAndreas Gohr
389696a1b1bSAndreas Gohr    /**
390696a1b1bSAndreas Gohr     * Data provider for logMedia test
391696a1b1bSAndreas Gohr     */
392696a1b1bSAndreas Gohr    public function logMediaProvider()
393696a1b1bSAndreas Gohr    {
394696a1b1bSAndreas Gohr        return [
395696a1b1bSAndreas Gohr            'image inline' => ['test.jpg', 'image/jpeg', true, 1024],
396696a1b1bSAndreas Gohr            'video not inline' => ['test.mp4', 'video/mp4', false, 2048],
397696a1b1bSAndreas Gohr            'document' => ['test.pdf', 'application/pdf', false, 512],
398696a1b1bSAndreas Gohr        ];
399696a1b1bSAndreas Gohr    }
400696a1b1bSAndreas Gohr
401696a1b1bSAndreas Gohr    /**
402696a1b1bSAndreas Gohr     * Test logMedia method
403696a1b1bSAndreas Gohr     * @dataProvider logMediaProvider
404696a1b1bSAndreas Gohr     */
405696a1b1bSAndreas Gohr    public function testLogMedia($media, $mime, $inline, $size)
406696a1b1bSAndreas Gohr    {
407696a1b1bSAndreas Gohr        global $INPUT;
408696a1b1bSAndreas Gohr
409696a1b1bSAndreas Gohr        $user = 'testuser';
410696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', $user);
411696a1b1bSAndreas Gohr
41241d1fffcSAndreas Gohr        $this->helper->getLogger()->logMedia($media, $mime, $inline, $size);
413696a1b1bSAndreas Gohr
414696a1b1bSAndreas Gohr        $mediaLog = $this->helper->getDB()->queryRecord('SELECT * FROM media ORDER BY dt DESC LIMIT 1');
415696a1b1bSAndreas Gohr        $this->assertEquals($media, $mediaLog['media']);
416696a1b1bSAndreas Gohr        $this->assertEquals($size, $mediaLog['size']);
417696a1b1bSAndreas Gohr        $this->assertEquals($inline ? 1 : 0, $mediaLog['inline']);
418696a1b1bSAndreas Gohr
419696a1b1bSAndreas Gohr        [$mime1, $mime2] = explode('/', strtolower($mime));
420696a1b1bSAndreas Gohr        $this->assertEquals($mime1, $mediaLog['mime1']);
421696a1b1bSAndreas Gohr        $this->assertEquals($mime2, $mediaLog['mime2']);
422696a1b1bSAndreas Gohr    }
423696a1b1bSAndreas Gohr
424696a1b1bSAndreas Gohr    /**
425696a1b1bSAndreas Gohr     * Data provider for logEdit test
426696a1b1bSAndreas Gohr     */
427696a1b1bSAndreas Gohr    public function logEditProvider()
428696a1b1bSAndreas Gohr    {
429696a1b1bSAndreas Gohr        return [
430696a1b1bSAndreas Gohr            'create page' => ['new:page', 'create'],
431696a1b1bSAndreas Gohr            'edit page' => ['existing:page', 'edit'],
432696a1b1bSAndreas Gohr            'delete page' => ['old:page', 'delete'],
433696a1b1bSAndreas Gohr        ];
434696a1b1bSAndreas Gohr    }
435696a1b1bSAndreas Gohr
436696a1b1bSAndreas Gohr    /**
437696a1b1bSAndreas Gohr     * Test logEdit method
438696a1b1bSAndreas Gohr     * @dataProvider logEditProvider
439696a1b1bSAndreas Gohr     */
440696a1b1bSAndreas Gohr    public function testLogEdit($page, $type)
441696a1b1bSAndreas Gohr    {
44241d1fffcSAndreas Gohr        global $INPUT, $USERINFO;
443de1daf8cSAndreas Gohr
44423e0cc03SAndreas Gohr
445696a1b1bSAndreas Gohr        $user = 'testuser';
446696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', $user);
447696a1b1bSAndreas Gohr        $USERINFO = ['grps' => ['admin']];
448696a1b1bSAndreas Gohr
44941d1fffcSAndreas Gohr        $this->helper->getLogger()->logEdit($page, $type);
450696a1b1bSAndreas Gohr
451696a1b1bSAndreas Gohr        // Check edits table
452696a1b1bSAndreas Gohr        $edit = $this->helper->getDB()->queryRecord('SELECT * FROM edits ORDER BY dt DESC LIMIT 1');
453696a1b1bSAndreas Gohr        $this->assertEquals($page, $edit['page']);
454696a1b1bSAndreas Gohr        $this->assertEquals($type, $edit['type']);
455696a1b1bSAndreas Gohr    }
456696a1b1bSAndreas Gohr
457696a1b1bSAndreas Gohr    /**
458696a1b1bSAndreas Gohr     * Data provider for logLogin test
459696a1b1bSAndreas Gohr     */
460696a1b1bSAndreas Gohr    public function logLoginProvider()
461696a1b1bSAndreas Gohr    {
462696a1b1bSAndreas Gohr        return [
463696a1b1bSAndreas Gohr            'login' => ['login', 'testuser'],
464696a1b1bSAndreas Gohr            'logout' => ['logout', 'testuser'],
465696a1b1bSAndreas Gohr            'create' => ['create', 'newuser'],
466696a1b1bSAndreas Gohr        ];
467696a1b1bSAndreas Gohr    }
468696a1b1bSAndreas Gohr
469696a1b1bSAndreas Gohr    /**
470696a1b1bSAndreas Gohr     * Test logLogin method
471696a1b1bSAndreas Gohr     * @dataProvider logLoginProvider
472696a1b1bSAndreas Gohr     */
473696a1b1bSAndreas Gohr    public function testLogLogin($type, $user)
474696a1b1bSAndreas Gohr    {
47541d1fffcSAndreas Gohr        $this->helper->getLogger()->logLogin($type, $user);
476696a1b1bSAndreas Gohr        $login = $this->helper->getDB()->queryRecord('SELECT * FROM logins ORDER BY dt DESC LIMIT 1');
477696a1b1bSAndreas Gohr        $this->assertEquals($type, $login['type']);
478696a1b1bSAndreas Gohr        $this->assertEquals($user, $login['user']);
479696a1b1bSAndreas Gohr    }
480696a1b1bSAndreas Gohr
481696a1b1bSAndreas Gohr    /**
482696a1b1bSAndreas Gohr     * Test logHistoryPages method
483696a1b1bSAndreas Gohr     */
484696a1b1bSAndreas Gohr    public function testLogHistoryPages()
485696a1b1bSAndreas Gohr    {
48641d1fffcSAndreas Gohr        $this->helper->getLogger()->logHistoryPages();
487696a1b1bSAndreas Gohr
488696a1b1bSAndreas Gohr        // Check that both page_count and page_size entries were created
489696a1b1bSAndreas Gohr        $pageCount = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['page_count']);
490696a1b1bSAndreas Gohr        $pageSize = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['page_size']);
491696a1b1bSAndreas Gohr
492696a1b1bSAndreas Gohr        $this->assertIsNumeric($pageCount);
493696a1b1bSAndreas Gohr        $this->assertIsNumeric($pageSize);
494696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $pageCount);
495696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $pageSize);
496696a1b1bSAndreas Gohr    }
497696a1b1bSAndreas Gohr
498696a1b1bSAndreas Gohr    /**
499696a1b1bSAndreas Gohr     * Test logHistoryMedia method
500696a1b1bSAndreas Gohr     */
501696a1b1bSAndreas Gohr    public function testLogHistoryMedia()
502696a1b1bSAndreas Gohr    {
50341d1fffcSAndreas Gohr        $this->helper->getLogger()->logHistoryMedia();
504696a1b1bSAndreas Gohr
505696a1b1bSAndreas Gohr        // Check that both media_count and media_size entries were created
506696a1b1bSAndreas Gohr        $mediaCount = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['media_count']);
507696a1b1bSAndreas Gohr        $mediaSize = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['media_size']);
508696a1b1bSAndreas Gohr
509696a1b1bSAndreas Gohr        $this->assertIsNumeric($mediaCount);
510696a1b1bSAndreas Gohr        $this->assertIsNumeric($mediaSize);
511696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $mediaCount);
512696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $mediaSize);
513696a1b1bSAndreas Gohr    }
514696a1b1bSAndreas Gohr
515696a1b1bSAndreas Gohr    /**
516696a1b1bSAndreas Gohr     * Test that feedreader user agents are handled correctly
517696a1b1bSAndreas Gohr     */
518696a1b1bSAndreas Gohr    public function testFeedReaderUserAgent()
519696a1b1bSAndreas Gohr    {
52000f786d8SAndreas Gohr        // Use a user agent that DeviceDetector recognizes as a feedreader
52100f786d8SAndreas Gohr        $_SERVER['HTTP_USER_AGENT'] = 'BashPodder/1.0 (http://bashpodder.sourceforge.net/)';
522696a1b1bSAndreas Gohr
523696a1b1bSAndreas Gohr        $logger = new Logger($this->helper);
524696a1b1bSAndreas Gohr
525696a1b1bSAndreas Gohr        // Use reflection to access protected property
526696a1b1bSAndreas Gohr        $reflection = new \ReflectionClass($logger);
527696a1b1bSAndreas Gohr        $uaTypeProperty = $reflection->getProperty('uaType');
528696a1b1bSAndreas Gohr        $uaTypeProperty->setAccessible(true);
529696a1b1bSAndreas Gohr
530696a1b1bSAndreas Gohr        $this->assertEquals('feedreader', $uaTypeProperty->getValue($logger));
531696a1b1bSAndreas Gohr    }
5325cc1319aSAndreas Gohr}
533