xref: /plugin/statistics/_test/LoggerTest.php (revision 00f786d8543ecba8806a73e00cab7a6e9718571a)
15cc1319aSAndreas Gohr<?php
25cc1319aSAndreas Gohr
35cc1319aSAndreas Gohrnamespace dokuwiki\plugin\statistics\test;
45cc1319aSAndreas Gohr
55cc1319aSAndreas Gohruse DokuWikiTest;
6696a1b1bSAndreas Gohruse dokuwiki\plugin\statistics\Logger;
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
22696a1b1bSAndreas Gohr    /** @var Logger */
23696a1b1bSAndreas Gohr    protected $logger;
24696a1b1bSAndreas Gohr
25696a1b1bSAndreas Gohr    public function setUp(): void
26696a1b1bSAndreas Gohr    {
27696a1b1bSAndreas Gohr        parent::setUp();
28696a1b1bSAndreas Gohr
29696a1b1bSAndreas Gohr        // Load the helper plugin
30696a1b1bSAndreas Gohr        $this->helper = plugin_load('helper', 'statistics');
31696a1b1bSAndreas Gohr
32696a1b1bSAndreas Gohr        // Mock user agent to avoid bot detection
33696a1b1bSAndreas Gohr        $_SERVER['HTTP_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';
34696a1b1bSAndreas Gohr
35696a1b1bSAndreas Gohr        // Initialize logger
36696a1b1bSAndreas Gohr        $this->logger = new Logger($this->helper);
37696a1b1bSAndreas Gohr    }
38696a1b1bSAndreas Gohr
39696a1b1bSAndreas Gohr    public function tearDown(): void
40696a1b1bSAndreas Gohr    {
41696a1b1bSAndreas Gohr        unset($_SERVER['HTTP_USER_AGENT']);
42696a1b1bSAndreas Gohr        parent::tearDown();
43696a1b1bSAndreas Gohr    }
44696a1b1bSAndreas Gohr
45696a1b1bSAndreas Gohr    /**
46696a1b1bSAndreas Gohr     * Test constructor initializes properties correctly
47696a1b1bSAndreas Gohr     */
48696a1b1bSAndreas Gohr    public function testConstructor()
49696a1b1bSAndreas Gohr    {
50696a1b1bSAndreas Gohr        $this->assertInstanceOf(Logger::class, $this->logger);
51696a1b1bSAndreas Gohr
52696a1b1bSAndreas Gohr        // Test that bot user agents throw exception
53696a1b1bSAndreas Gohr        $_SERVER['HTTP_USER_AGENT'] = 'Googlebot/2.1 (+http://www.google.com/bot.html)';
54696a1b1bSAndreas Gohr
55696a1b1bSAndreas Gohr        $this->expectException(\RuntimeException::class);
56696a1b1bSAndreas Gohr        $this->expectExceptionMessage('Bot detected, not logging');
57696a1b1bSAndreas Gohr        new Logger($this->helper);
58696a1b1bSAndreas Gohr    }
59696a1b1bSAndreas Gohr
60696a1b1bSAndreas Gohr    /**
61696a1b1bSAndreas Gohr     * Test begin and end transaction methods
62696a1b1bSAndreas Gohr     */
63696a1b1bSAndreas Gohr    public function testBeginEnd()
64696a1b1bSAndreas Gohr    {
65696a1b1bSAndreas Gohr        $this->logger->begin();
66696a1b1bSAndreas Gohr
67696a1b1bSAndreas Gohr        // Verify transaction is active by checking PDO
68696a1b1bSAndreas Gohr        $pdo = $this->helper->getDB()->getPdo();
69696a1b1bSAndreas Gohr        $this->assertTrue($pdo->inTransaction());
70696a1b1bSAndreas Gohr
71696a1b1bSAndreas Gohr        $this->logger->end();
72696a1b1bSAndreas Gohr
73696a1b1bSAndreas Gohr        // Verify transaction is committed
74696a1b1bSAndreas Gohr        $this->assertFalse($pdo->inTransaction());
75696a1b1bSAndreas Gohr    }
76696a1b1bSAndreas Gohr
77696a1b1bSAndreas Gohr    /**
78696a1b1bSAndreas Gohr     * Test logLastseen method
79696a1b1bSAndreas Gohr     */
80696a1b1bSAndreas Gohr    public function testLogLastseen()
81696a1b1bSAndreas Gohr    {
82696a1b1bSAndreas Gohr        global $INPUT;
83696a1b1bSAndreas Gohr
84696a1b1bSAndreas Gohr        // Test with no user (should not log)
85696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', '');
86696a1b1bSAndreas Gohr        $this->logger->logLastseen();
87696a1b1bSAndreas Gohr
88696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM lastseen');
89696a1b1bSAndreas Gohr        $this->assertEquals(0, $count);
90696a1b1bSAndreas Gohr
91696a1b1bSAndreas Gohr        // Test with user
92696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', 'testuser');
93696a1b1bSAndreas Gohr        $this->logger->logLastseen();
94696a1b1bSAndreas Gohr
95696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM lastseen');
96696a1b1bSAndreas Gohr        $this->assertEquals(1, $count);
97696a1b1bSAndreas Gohr
98696a1b1bSAndreas Gohr        $user = $this->helper->getDB()->queryValue('SELECT user FROM lastseen WHERE user = ?', ['testuser']);
99696a1b1bSAndreas Gohr        $this->assertEquals('testuser', $user);
100696a1b1bSAndreas Gohr    }
101696a1b1bSAndreas Gohr
102696a1b1bSAndreas Gohr    /**
103696a1b1bSAndreas Gohr     * Data provider for logGroups test
104696a1b1bSAndreas Gohr     */
105696a1b1bSAndreas Gohr    public function logGroupsProvider()
106696a1b1bSAndreas Gohr    {
107696a1b1bSAndreas Gohr        return [
108696a1b1bSAndreas Gohr            'empty groups' => [[], 'view', 0],
109696a1b1bSAndreas Gohr            'single group' => [['admin'], 'view', 1],
110696a1b1bSAndreas Gohr            'multiple groups' => [['admin', 'user'], 'edit', 2],
111696a1b1bSAndreas Gohr            'filtered groups' => [['admin', 'nonexistent'], 'view', 1], // assuming only 'admin' is configured
112696a1b1bSAndreas Gohr        ];
113696a1b1bSAndreas Gohr    }
114696a1b1bSAndreas Gohr
115696a1b1bSAndreas Gohr    /**
116696a1b1bSAndreas Gohr     * Test logGroups method
117696a1b1bSAndreas Gohr     * @dataProvider logGroupsProvider
118696a1b1bSAndreas Gohr     */
119696a1b1bSAndreas Gohr    public function testLogGroups($groups, $type, $expectedCount)
120696a1b1bSAndreas Gohr    {
121de1daf8cSAndreas Gohr        global $conf;
122de1daf8cSAndreas Gohr        $conf['plugin']['statistics']['loggroups'] = ['admin', 'user'];
123696a1b1bSAndreas Gohr
12423e0cc03SAndreas Gohr        // Clear any existing data for this test
12523e0cc03SAndreas Gohr        $this->helper->getDB()->exec('DELETE FROM groups WHERE type = ?', [$type]);
12623e0cc03SAndreas Gohr
127696a1b1bSAndreas Gohr        $this->logger->logGroups($type, $groups);
128696a1b1bSAndreas Gohr
129696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM groups WHERE type = ?', [$type]);
130696a1b1bSAndreas Gohr        $this->assertEquals($expectedCount, $count);
131696a1b1bSAndreas Gohr
132696a1b1bSAndreas Gohr        if ($expectedCount > 0) {
133696a1b1bSAndreas Gohr            $loggedGroups = $this->helper->getDB()->queryAll('SELECT `group` FROM groups WHERE type = ?', [$type]);
134696a1b1bSAndreas Gohr            $this->assertCount($expectedCount, $loggedGroups);
135696a1b1bSAndreas Gohr        }
136696a1b1bSAndreas Gohr    }
137696a1b1bSAndreas Gohr
138696a1b1bSAndreas Gohr    /**
139696a1b1bSAndreas Gohr     * Data provider for logExternalSearch test
140696a1b1bSAndreas Gohr     */
141696a1b1bSAndreas Gohr    public function logExternalSearchProvider()
142696a1b1bSAndreas Gohr    {
143696a1b1bSAndreas Gohr        return [
144696a1b1bSAndreas Gohr            'google search' => [
145696a1b1bSAndreas Gohr                'https://www.google.com/search?q=dokuwiki+test',
146696a1b1bSAndreas Gohr                'search',
147696a1b1bSAndreas Gohr                'dokuwiki test',
148de1daf8cSAndreas Gohr                'google'
149696a1b1bSAndreas Gohr            ],
150696a1b1bSAndreas Gohr            'non-search referer' => [
151696a1b1bSAndreas Gohr                'https://example.com/page',
152696a1b1bSAndreas Gohr                '',
153696a1b1bSAndreas Gohr                null,
154696a1b1bSAndreas Gohr                null
155696a1b1bSAndreas Gohr            ],
156696a1b1bSAndreas Gohr        ];
157696a1b1bSAndreas Gohr    }
158696a1b1bSAndreas Gohr
159696a1b1bSAndreas Gohr    /**
160696a1b1bSAndreas Gohr     * Test logExternalSearch method
161696a1b1bSAndreas Gohr     * @dataProvider logExternalSearchProvider
162696a1b1bSAndreas Gohr     */
163696a1b1bSAndreas Gohr    public function testLogExternalSearch($referer, $expectedType, $expectedQuery, $expectedEngine)
164696a1b1bSAndreas Gohr    {
165696a1b1bSAndreas Gohr        global $INPUT;
166696a1b1bSAndreas Gohr        $INPUT->set('p', 'test:page');
167696a1b1bSAndreas Gohr
168696a1b1bSAndreas Gohr        $type = '';
169696a1b1bSAndreas Gohr        $this->logger->logExternalSearch($referer, $type);
170696a1b1bSAndreas Gohr
171696a1b1bSAndreas Gohr        $this->assertEquals($expectedType, $type);
172696a1b1bSAndreas Gohr
173696a1b1bSAndreas Gohr        if ($expectedType === 'search') {
174696a1b1bSAndreas Gohr            $searchCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM search');
175696a1b1bSAndreas Gohr            $this->assertEquals(1, $searchCount);
176696a1b1bSAndreas Gohr
177696a1b1bSAndreas Gohr            $search = $this->helper->getDB()->queryRecord('SELECT * FROM search ORDER BY dt DESC LIMIT 1');
178696a1b1bSAndreas Gohr            $this->assertEquals($expectedQuery, $search['query']);
179696a1b1bSAndreas Gohr            $this->assertEquals($expectedEngine, $search['engine']);
180696a1b1bSAndreas Gohr        }
181696a1b1bSAndreas Gohr    }
182696a1b1bSAndreas Gohr
183696a1b1bSAndreas Gohr    /**
184696a1b1bSAndreas Gohr     * Test logSearch method
185696a1b1bSAndreas Gohr     */
186696a1b1bSAndreas Gohr    public function testLogSearch()
187696a1b1bSAndreas Gohr    {
188696a1b1bSAndreas Gohr        $page = 'test:page';
189696a1b1bSAndreas Gohr        $query = 'test search query';
190696a1b1bSAndreas Gohr        $words = ['test', 'search', 'query'];
191696a1b1bSAndreas Gohr        $engine = 'Google';
192696a1b1bSAndreas Gohr
193696a1b1bSAndreas Gohr        $this->logger->logSearch($page, $query, $words, $engine);
194696a1b1bSAndreas Gohr
195696a1b1bSAndreas Gohr        // Check search table
196696a1b1bSAndreas Gohr        $search = $this->helper->getDB()->queryRecord('SELECT * FROM search ORDER BY dt DESC LIMIT 1');
197696a1b1bSAndreas Gohr        $this->assertEquals($page, $search['page']);
198696a1b1bSAndreas Gohr        $this->assertEquals($query, $search['query']);
199696a1b1bSAndreas Gohr        $this->assertEquals($engine, $search['engine']);
200696a1b1bSAndreas Gohr
201696a1b1bSAndreas Gohr        // Check searchwords table
202de1daf8cSAndreas Gohr        $wordCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM searchwords WHERE sid = ?', [$search['id']]);
203696a1b1bSAndreas Gohr        $this->assertEquals(3, $wordCount);
204696a1b1bSAndreas Gohr
205de1daf8cSAndreas Gohr        $loggedWords = $this->helper->getDB()->queryAll('SELECT word FROM searchwords WHERE sid = ? ORDER BY word', [$search['id']]);
206696a1b1bSAndreas Gohr        $this->assertEquals(['query', 'search', 'test'], array_column($loggedWords, 'word'));
207696a1b1bSAndreas Gohr    }
208696a1b1bSAndreas Gohr
209696a1b1bSAndreas Gohr    /**
210696a1b1bSAndreas Gohr     * Test logSession method
211696a1b1bSAndreas Gohr     */
212696a1b1bSAndreas Gohr    public function testLogSession()
213696a1b1bSAndreas Gohr    {
214696a1b1bSAndreas Gohr        // Test without adding view
215696a1b1bSAndreas Gohr        $this->logger->logSession(0);
216696a1b1bSAndreas Gohr
217696a1b1bSAndreas Gohr        $sessionCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM session');
218696a1b1bSAndreas Gohr        $this->assertEquals(1, $sessionCount);
219696a1b1bSAndreas Gohr
220696a1b1bSAndreas Gohr        $session = $this->helper->getDB()->queryRecord('SELECT * FROM session ORDER BY dt DESC LIMIT 1');
221696a1b1bSAndreas Gohr        $this->assertEquals(0, $session['views']);
222696a1b1bSAndreas Gohr
223696a1b1bSAndreas Gohr        // Test adding view
224696a1b1bSAndreas Gohr        $this->logger->logSession(1);
225696a1b1bSAndreas Gohr
226696a1b1bSAndreas Gohr        $session = $this->helper->getDB()->queryRecord('SELECT * FROM session ORDER BY dt DESC LIMIT 1');
227696a1b1bSAndreas Gohr        $this->assertEquals(1, $session['views']);
228696a1b1bSAndreas Gohr
229696a1b1bSAndreas Gohr        // Test incrementing views
230696a1b1bSAndreas Gohr        $this->logger->logSession(1);
231696a1b1bSAndreas Gohr
232696a1b1bSAndreas Gohr        $session = $this->helper->getDB()->queryRecord('SELECT * FROM session ORDER BY dt DESC LIMIT 1');
233696a1b1bSAndreas Gohr        $this->assertEquals(2, $session['views']);
234696a1b1bSAndreas Gohr    }
235696a1b1bSAndreas Gohr
236696a1b1bSAndreas Gohr    /**
237696a1b1bSAndreas Gohr     * Test logIp method
238696a1b1bSAndreas Gohr     */
239696a1b1bSAndreas Gohr    public function testLogIp()
240696a1b1bSAndreas Gohr    {
241696a1b1bSAndreas Gohr        $ip = '8.8.8.8';
242696a1b1bSAndreas Gohr
243c7cad24dSAndreas Gohr        // Create a mock HTTP client
244c7cad24dSAndreas Gohr        $mockHttpClient = $this->createMock(\dokuwiki\HTTP\DokuHTTPClient::class);
2456c24c4b8SAndreas Gohr
246c7cad24dSAndreas Gohr        // Mock the API response
247c7cad24dSAndreas Gohr        $mockResponse = json_encode([
248c7cad24dSAndreas Gohr            'status' => 'success',
249c7cad24dSAndreas Gohr            'country' => 'United States',
250c7cad24dSAndreas Gohr            'countryCode' => 'US',
251c7cad24dSAndreas Gohr            'city' => 'Ashburn',
252c7cad24dSAndreas Gohr            'query' => $ip
253c7cad24dSAndreas Gohr        ]);
2546c24c4b8SAndreas Gohr
255c7cad24dSAndreas Gohr        $mockHttpClient->expects($this->once())
256c7cad24dSAndreas Gohr            ->method('get')
257c7cad24dSAndreas Gohr            ->with('http://ip-api.com/json/' . $ip)
258c7cad24dSAndreas Gohr            ->willReturn($mockResponse);
259696a1b1bSAndreas Gohr
260c7cad24dSAndreas Gohr        // Set timeout property
261c7cad24dSAndreas Gohr        $mockHttpClient->timeout = 10;
262c7cad24dSAndreas Gohr
263c7cad24dSAndreas Gohr        // Create logger with mock HTTP client
264c7cad24dSAndreas Gohr        $logger = new Logger($this->helper, $mockHttpClient);
265c7cad24dSAndreas Gohr
266c7cad24dSAndreas Gohr        // Test with IP that doesn't exist in database
267c7cad24dSAndreas Gohr        $logger->logIp($ip);
268c7cad24dSAndreas Gohr
269c7cad24dSAndreas Gohr        // Verify the IP was logged
270c7cad24dSAndreas Gohr        $ipRecord = $this->helper->getDB()->queryRecord('SELECT * FROM iplocation WHERE ip = ?', [$ip]);
271c7cad24dSAndreas Gohr        $this->assertNotNull($ipRecord);
272c7cad24dSAndreas Gohr        $this->assertEquals($ip, $ipRecord['ip']);
273c7cad24dSAndreas Gohr        $this->assertEquals('United States', $ipRecord['country']);
274c7cad24dSAndreas Gohr        $this->assertEquals('US', $ipRecord['code']);
275c7cad24dSAndreas Gohr        $this->assertEquals('Ashburn', $ipRecord['city']);
276c7cad24dSAndreas Gohr        $this->assertNotEmpty($ipRecord['host']); // gethostbyaddr result
277c7cad24dSAndreas Gohr
278c7cad24dSAndreas Gohr        // Test with IP that already exists and is recent (should not make HTTP call)
279c7cad24dSAndreas Gohr        $mockHttpClient2 = $this->createMock(\dokuwiki\HTTP\DokuHTTPClient::class);
280c7cad24dSAndreas Gohr        $mockHttpClient2->expects($this->never())->method('get');
281c7cad24dSAndreas Gohr
282c7cad24dSAndreas Gohr        $logger2 = new Logger($this->helper, $mockHttpClient2);
283c7cad24dSAndreas Gohr        $logger2->logIp($ip); // Should not trigger HTTP call
284696a1b1bSAndreas Gohr    }
285696a1b1bSAndreas Gohr
286696a1b1bSAndreas Gohr    /**
287696a1b1bSAndreas Gohr     * Test logOutgoing method
288696a1b1bSAndreas Gohr     */
289696a1b1bSAndreas Gohr    public function testLogOutgoing()
290696a1b1bSAndreas Gohr    {
291696a1b1bSAndreas Gohr        global $INPUT;
292696a1b1bSAndreas Gohr
293696a1b1bSAndreas Gohr        // Test without outgoing link
294696a1b1bSAndreas Gohr        $INPUT->set('ol', '');
295696a1b1bSAndreas Gohr        $this->logger->logOutgoing();
296696a1b1bSAndreas Gohr
297696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM outlinks');
298696a1b1bSAndreas Gohr        $this->assertEquals(0, $count);
299696a1b1bSAndreas Gohr
300696a1b1bSAndreas Gohr        // Test with outgoing link
301696a1b1bSAndreas Gohr        $link = 'https://example.com';
302696a1b1bSAndreas Gohr        $page = 'test:page';
303696a1b1bSAndreas Gohr        $INPUT->set('ol', $link);
304696a1b1bSAndreas Gohr        $INPUT->set('p', $page);
305696a1b1bSAndreas Gohr
306696a1b1bSAndreas Gohr        $this->logger->logOutgoing();
307696a1b1bSAndreas Gohr
308696a1b1bSAndreas Gohr        $count = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM outlinks');
309696a1b1bSAndreas Gohr        $this->assertEquals(1, $count);
310696a1b1bSAndreas Gohr
311696a1b1bSAndreas Gohr        $outlink = $this->helper->getDB()->queryRecord('SELECT * FROM outlinks ORDER BY dt DESC LIMIT 1');
312696a1b1bSAndreas Gohr        $this->assertEquals($link, $outlink['link']);
313696a1b1bSAndreas Gohr        $this->assertEquals(md5($link), $outlink['link_md5']);
314696a1b1bSAndreas Gohr        $this->assertEquals($page, $outlink['page']);
315696a1b1bSAndreas Gohr    }
316696a1b1bSAndreas Gohr
317696a1b1bSAndreas Gohr    /**
318696a1b1bSAndreas Gohr     * Test logAccess method
319696a1b1bSAndreas Gohr     */
320696a1b1bSAndreas Gohr    public function testLogAccess()
321696a1b1bSAndreas Gohr    {
322de1daf8cSAndreas Gohr        global $INPUT, $USERINFO, $conf;
323de1daf8cSAndreas Gohr
324de1daf8cSAndreas Gohr        $conf['plugin']['statistics']['loggroups'] = ['admin', 'user'];
325696a1b1bSAndreas Gohr
32623e0cc03SAndreas Gohr        // Clear any existing data for this test
32723e0cc03SAndreas Gohr        $this->helper->getDB()->exec('DELETE FROM groups WHERE type = ?', ['view']);
32823e0cc03SAndreas Gohr
329696a1b1bSAndreas Gohr        $page = 'test:page';
330696a1b1bSAndreas Gohr        $referer = 'https://example.com';
331696a1b1bSAndreas Gohr        $user = 'testuser';
332696a1b1bSAndreas Gohr
333696a1b1bSAndreas Gohr        $INPUT->set('p', $page);
334696a1b1bSAndreas Gohr        $INPUT->set('r', $referer);
335696a1b1bSAndreas Gohr        $INPUT->set('sx', 1920);
336696a1b1bSAndreas Gohr        $INPUT->set('sy', 1080);
337696a1b1bSAndreas Gohr        $INPUT->set('vx', 1200);
338696a1b1bSAndreas Gohr        $INPUT->set('vy', 800);
339696a1b1bSAndreas Gohr        $INPUT->set('js', 1);
340696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', $user);
341696a1b1bSAndreas Gohr
342696a1b1bSAndreas Gohr        $USERINFO = ['grps' => ['admin', 'user']];
343696a1b1bSAndreas Gohr
344696a1b1bSAndreas Gohr        $this->logger->logAccess();
345696a1b1bSAndreas Gohr
346696a1b1bSAndreas Gohr        // Check access table
347696a1b1bSAndreas Gohr        $access = $this->helper->getDB()->queryRecord('SELECT * FROM access ORDER BY dt DESC LIMIT 1');
348696a1b1bSAndreas Gohr        $this->assertEquals($page, $access['page']);
349696a1b1bSAndreas Gohr        $this->assertEquals($user, $access['user']);
350696a1b1bSAndreas Gohr        $this->assertEquals(1920, $access['screen_x']);
351696a1b1bSAndreas Gohr        $this->assertEquals(1080, $access['screen_y']);
352696a1b1bSAndreas Gohr        $this->assertEquals(1200, $access['view_x']);
353696a1b1bSAndreas Gohr        $this->assertEquals(800, $access['view_y']);
354696a1b1bSAndreas Gohr        $this->assertEquals(1, $access['js']);
355696a1b1bSAndreas Gohr        $this->assertEquals('external', $access['ref_type']);
356696a1b1bSAndreas Gohr
357696a1b1bSAndreas Gohr        // Check refseen table
358696a1b1bSAndreas Gohr        $refCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM refseen WHERE ref_md5 = ?', [md5($referer)]);
359696a1b1bSAndreas Gohr        $this->assertEquals(1, $refCount);
360696a1b1bSAndreas Gohr
361696a1b1bSAndreas Gohr        // Check groups table
362696a1b1bSAndreas Gohr        $groupCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM groups WHERE type = ?', ['view']);
363696a1b1bSAndreas Gohr        $this->assertEquals(2, $groupCount);
364696a1b1bSAndreas Gohr    }
365696a1b1bSAndreas Gohr
366696a1b1bSAndreas Gohr    /**
367696a1b1bSAndreas Gohr     * Data provider for logMedia test
368696a1b1bSAndreas Gohr     */
369696a1b1bSAndreas Gohr    public function logMediaProvider()
370696a1b1bSAndreas Gohr    {
371696a1b1bSAndreas Gohr        return [
372696a1b1bSAndreas Gohr            'image inline' => ['test.jpg', 'image/jpeg', true, 1024],
373696a1b1bSAndreas Gohr            'video not inline' => ['test.mp4', 'video/mp4', false, 2048],
374696a1b1bSAndreas Gohr            'document' => ['test.pdf', 'application/pdf', false, 512],
375696a1b1bSAndreas Gohr        ];
376696a1b1bSAndreas Gohr    }
377696a1b1bSAndreas Gohr
378696a1b1bSAndreas Gohr    /**
379696a1b1bSAndreas Gohr     * Test logMedia method
380696a1b1bSAndreas Gohr     * @dataProvider logMediaProvider
381696a1b1bSAndreas Gohr     */
382696a1b1bSAndreas Gohr    public function testLogMedia($media, $mime, $inline, $size)
383696a1b1bSAndreas Gohr    {
384696a1b1bSAndreas Gohr        global $INPUT;
385696a1b1bSAndreas Gohr
386696a1b1bSAndreas Gohr        $user = 'testuser';
387696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', $user);
388696a1b1bSAndreas Gohr
389696a1b1bSAndreas Gohr        $this->logger->logMedia($media, $mime, $inline, $size);
390696a1b1bSAndreas Gohr
391696a1b1bSAndreas Gohr        $mediaLog = $this->helper->getDB()->queryRecord('SELECT * FROM media ORDER BY dt DESC LIMIT 1');
392696a1b1bSAndreas Gohr        $this->assertEquals($media, $mediaLog['media']);
393696a1b1bSAndreas Gohr        $this->assertEquals($user, $mediaLog['user']);
394696a1b1bSAndreas Gohr        $this->assertEquals($size, $mediaLog['size']);
395696a1b1bSAndreas Gohr        $this->assertEquals($inline ? 1 : 0, $mediaLog['inline']);
396696a1b1bSAndreas Gohr
397696a1b1bSAndreas Gohr        [$mime1, $mime2] = explode('/', strtolower($mime));
398696a1b1bSAndreas Gohr        $this->assertEquals($mime1, $mediaLog['mime1']);
399696a1b1bSAndreas Gohr        $this->assertEquals($mime2, $mediaLog['mime2']);
400696a1b1bSAndreas Gohr    }
401696a1b1bSAndreas Gohr
402696a1b1bSAndreas Gohr    /**
403696a1b1bSAndreas Gohr     * Data provider for logEdit test
404696a1b1bSAndreas Gohr     */
405696a1b1bSAndreas Gohr    public function logEditProvider()
406696a1b1bSAndreas Gohr    {
407696a1b1bSAndreas Gohr        return [
408696a1b1bSAndreas Gohr            'create page' => ['new:page', 'create'],
409696a1b1bSAndreas Gohr            'edit page' => ['existing:page', 'edit'],
410696a1b1bSAndreas Gohr            'delete page' => ['old:page', 'delete'],
411696a1b1bSAndreas Gohr        ];
412696a1b1bSAndreas Gohr    }
413696a1b1bSAndreas Gohr
414696a1b1bSAndreas Gohr    /**
415696a1b1bSAndreas Gohr     * Test logEdit method
416696a1b1bSAndreas Gohr     * @dataProvider logEditProvider
417696a1b1bSAndreas Gohr     */
418696a1b1bSAndreas Gohr    public function testLogEdit($page, $type)
419696a1b1bSAndreas Gohr    {
420de1daf8cSAndreas Gohr        global $INPUT, $USERINFO, $conf;
421de1daf8cSAndreas Gohr
422de1daf8cSAndreas Gohr        $conf['plugin']['statistics']['loggroups'] = ['admin'];
423696a1b1bSAndreas Gohr
42423e0cc03SAndreas Gohr        // Clear any existing data for this test
42523e0cc03SAndreas Gohr        $this->helper->getDB()->exec('DELETE FROM groups WHERE type = ?', ['edit']);
42623e0cc03SAndreas Gohr
427696a1b1bSAndreas Gohr        $user = 'testuser';
428696a1b1bSAndreas Gohr        $INPUT->server->set('REMOTE_USER', $user);
429696a1b1bSAndreas Gohr        $USERINFO = ['grps' => ['admin']];
430696a1b1bSAndreas Gohr
431696a1b1bSAndreas Gohr        $this->logger->logEdit($page, $type);
432696a1b1bSAndreas Gohr
433696a1b1bSAndreas Gohr        // Check edits table
434696a1b1bSAndreas Gohr        $edit = $this->helper->getDB()->queryRecord('SELECT * FROM edits ORDER BY dt DESC LIMIT 1');
435696a1b1bSAndreas Gohr        $this->assertEquals($page, $edit['page']);
436696a1b1bSAndreas Gohr        $this->assertEquals($type, $edit['type']);
437696a1b1bSAndreas Gohr        $this->assertEquals($user, $edit['user']);
438696a1b1bSAndreas Gohr
439696a1b1bSAndreas Gohr        // Check groups table
440696a1b1bSAndreas Gohr        $groupCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM groups WHERE type = ?', ['edit']);
441696a1b1bSAndreas Gohr        $this->assertEquals(1, $groupCount);
442696a1b1bSAndreas Gohr    }
443696a1b1bSAndreas Gohr
444696a1b1bSAndreas Gohr    /**
445696a1b1bSAndreas Gohr     * Data provider for logLogin test
446696a1b1bSAndreas Gohr     */
447696a1b1bSAndreas Gohr    public function logLoginProvider()
448696a1b1bSAndreas Gohr    {
449696a1b1bSAndreas Gohr        return [
450696a1b1bSAndreas Gohr            'login' => ['login', 'testuser'],
451696a1b1bSAndreas Gohr            'logout' => ['logout', 'testuser'],
452696a1b1bSAndreas Gohr            'create' => ['create', 'newuser'],
453696a1b1bSAndreas Gohr        ];
454696a1b1bSAndreas Gohr    }
455696a1b1bSAndreas Gohr
456696a1b1bSAndreas Gohr    /**
457696a1b1bSAndreas Gohr     * Test logLogin method
458696a1b1bSAndreas Gohr     * @dataProvider logLoginProvider
459696a1b1bSAndreas Gohr     */
460696a1b1bSAndreas Gohr    public function testLogLogin($type, $user)
461696a1b1bSAndreas Gohr    {
462696a1b1bSAndreas Gohr        global $INPUT;
463696a1b1bSAndreas Gohr
464696a1b1bSAndreas Gohr        if ($user === 'testuser') {
465696a1b1bSAndreas Gohr            $INPUT->server->set('REMOTE_USER', $user);
466696a1b1bSAndreas Gohr            $this->logger->logLogin($type);
467696a1b1bSAndreas Gohr        } else {
468696a1b1bSAndreas Gohr            $this->logger->logLogin($type, $user);
469696a1b1bSAndreas Gohr        }
470696a1b1bSAndreas Gohr
471696a1b1bSAndreas Gohr        $login = $this->helper->getDB()->queryRecord('SELECT * FROM logins ORDER BY dt DESC LIMIT 1');
472696a1b1bSAndreas Gohr        $this->assertEquals($type, $login['type']);
473696a1b1bSAndreas Gohr        $this->assertEquals($user, $login['user']);
474696a1b1bSAndreas Gohr    }
475696a1b1bSAndreas Gohr
476696a1b1bSAndreas Gohr    /**
477696a1b1bSAndreas Gohr     * Test logHistoryPages method
478696a1b1bSAndreas Gohr     */
479696a1b1bSAndreas Gohr    public function testLogHistoryPages()
480696a1b1bSAndreas Gohr    {
481696a1b1bSAndreas Gohr        $this->logger->logHistoryPages();
482696a1b1bSAndreas Gohr
483696a1b1bSAndreas Gohr        // Check that both page_count and page_size entries were created
484696a1b1bSAndreas Gohr        $pageCount = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['page_count']);
485696a1b1bSAndreas Gohr        $pageSize = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['page_size']);
486696a1b1bSAndreas Gohr
487696a1b1bSAndreas Gohr        $this->assertIsNumeric($pageCount);
488696a1b1bSAndreas Gohr        $this->assertIsNumeric($pageSize);
489696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $pageCount);
490696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $pageSize);
491696a1b1bSAndreas Gohr    }
492696a1b1bSAndreas Gohr
493696a1b1bSAndreas Gohr    /**
494696a1b1bSAndreas Gohr     * Test logHistoryMedia method
495696a1b1bSAndreas Gohr     */
496696a1b1bSAndreas Gohr    public function testLogHistoryMedia()
497696a1b1bSAndreas Gohr    {
498696a1b1bSAndreas Gohr        $this->logger->logHistoryMedia();
499696a1b1bSAndreas Gohr
500696a1b1bSAndreas Gohr        // Check that both media_count and media_size entries were created
501696a1b1bSAndreas Gohr        $mediaCount = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['media_count']);
502696a1b1bSAndreas Gohr        $mediaSize = $this->helper->getDB()->queryValue('SELECT value FROM history WHERE info = ?', ['media_size']);
503696a1b1bSAndreas Gohr
504696a1b1bSAndreas Gohr        $this->assertIsNumeric($mediaCount);
505696a1b1bSAndreas Gohr        $this->assertIsNumeric($mediaSize);
506696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $mediaCount);
507696a1b1bSAndreas Gohr        $this->assertGreaterThanOrEqual(0, $mediaSize);
508696a1b1bSAndreas Gohr    }
509696a1b1bSAndreas Gohr
510696a1b1bSAndreas Gohr    /**
511696a1b1bSAndreas Gohr     * Test that feedreader user agents are handled correctly
512696a1b1bSAndreas Gohr     */
513696a1b1bSAndreas Gohr    public function testFeedReaderUserAgent()
514696a1b1bSAndreas Gohr    {
515*00f786d8SAndreas Gohr        // Use a user agent that DeviceDetector recognizes as a feedreader
516*00f786d8SAndreas Gohr        $_SERVER['HTTP_USER_AGENT'] = 'BashPodder/1.0 (http://bashpodder.sourceforge.net/)';
517696a1b1bSAndreas Gohr
518696a1b1bSAndreas Gohr        $logger = new Logger($this->helper);
519696a1b1bSAndreas Gohr
520696a1b1bSAndreas Gohr        // Use reflection to access protected property
521696a1b1bSAndreas Gohr        $reflection = new \ReflectionClass($logger);
522696a1b1bSAndreas Gohr        $uaTypeProperty = $reflection->getProperty('uaType');
523696a1b1bSAndreas Gohr        $uaTypeProperty->setAccessible(true);
524696a1b1bSAndreas Gohr
525696a1b1bSAndreas Gohr        $this->assertEquals('feedreader', $uaTypeProperty->getValue($logger));
526696a1b1bSAndreas Gohr    }
527696a1b1bSAndreas Gohr
528696a1b1bSAndreas Gohr    /**
529696a1b1bSAndreas Gohr     * Test session logging only works for browser type
530696a1b1bSAndreas Gohr     */
531696a1b1bSAndreas Gohr    public function testLogSessionOnlyForBrowser()
532696a1b1bSAndreas Gohr    {
53323e0cc03SAndreas Gohr        // Clear any existing session data
53423e0cc03SAndreas Gohr        $this->helper->getDB()->exec('DELETE FROM session');
53523e0cc03SAndreas Gohr
536696a1b1bSAndreas Gohr        // Change user agent type to feedreader using reflection
537696a1b1bSAndreas Gohr        $reflection = new \ReflectionClass($this->logger);
538696a1b1bSAndreas Gohr        $uaTypeProperty = $reflection->getProperty('uaType');
539696a1b1bSAndreas Gohr        $uaTypeProperty->setAccessible(true);
540696a1b1bSAndreas Gohr        $uaTypeProperty->setValue($this->logger, 'feedreader');
541696a1b1bSAndreas Gohr
542696a1b1bSAndreas Gohr        $this->logger->logSession(1);
543696a1b1bSAndreas Gohr
544696a1b1bSAndreas Gohr        $sessionCount = $this->helper->getDB()->queryValue('SELECT COUNT(*) FROM session');
545696a1b1bSAndreas Gohr        $this->assertEquals(0, $sessionCount);
5465cc1319aSAndreas Gohr    }
5475cc1319aSAndreas Gohr}
548