File size: 4,145 Bytes
c938f2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

declare(strict_types=1);

namespace Piwik\Plugins\BotTracking\tests\Integration;

use Piwik\Archive\ArchiveInvalidator;
use Piwik\Cache;
use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\Db;
use Piwik\Period\Range;
use Piwik\Plugins\BotTracking\API;
use Piwik\Plugins\BotTracking\Archiver;
use Piwik\Plugins\BotTracking\tests\Fixtures\BotTraffic;
use Piwik\Tests\Framework\Fixture;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;

/**
 * Verifies that the Favoured Pages buildForNonDayPeriod override honours partial archiving: when only
 * one favoured report is requested for a non-day period (e.g. a single-report invalidation /
 * --force-report), only that record is (re)built and the other is left untouched. This exercises the
 * guard that mirrors core's default non-day loop.
 *
 * @group BotTracking
 * @group AIChatbotFavouredPages
 * @group Plugins
 */
class AIChatbotFavouredPagesPartialArchiveTest extends IntegrationTestCase
{
    /**
     * @var BotTraffic
     */
    public static $fixture;

    public function testNonDayPartialArchivingRebuildsOnlyTheRequestedFavouredRecord(): void
    {
        // Full archive of the range first (range is the period that supports single-report partial
        // archiving): both favoured records are built.
        $_GET['trigger'] = 'archivephp';
        API::getInstance()->getAIChatbotHumanFavouredPages(1, 'range', '2025-02-03,2025-02-09');

        $fullNames = $this->favouredBlobNames();
        self::assertContains(Archiver::AI_CHATBOTS_HUMAN_FAVOURED_PAGES_RECORD, $fullNames);
        self::assertContains(Archiver::AI_CHATBOTS_AI_FAVOURED_PAGES_RECORD, $fullNames);

        $maxIdArchive = $this->maxBlobIdArchive();

        // Change a day inside the range, then re-archive that day, so the range must re-aggregate.
        $tracker = Fixture::getTracker(1, '2025-02-04 09:00:00');
        $tracker->setUrl('https://example.com/article/2');
        Fixture::checkResponse($tracker->doTrackPageView('Partial archive page'));

        Cache::flushAll();
        API::getInstance()->getAIChatbotHumanFavouredPages(1, 'day', '2025-02-04'); // re-archive the changed day (trigger still set)
        unset($_GET['trigger']);

        // Invalidate the range and re-query ONLY the human-favoured report, which triggers partial
        // archiving with that single record as the requested report.
        StaticContainer::get(ArchiveInvalidator::class)->markArchivesAsInvalidated([1], ['2025-02-03,2025-02-09'], 'range');
        API::getInstance()->getAIChatbotHumanFavouredPages(1, 'range', '2025-02-03,2025-02-09');

        // The new partial archive must (re)build only the requested human-favoured record; the guard
        // must skip the AI-favoured one.
        $partialNames = $this->favouredBlobNames($maxIdArchive);
        self::assertContains(Archiver::AI_CHATBOTS_HUMAN_FAVOURED_PAGES_RECORD, $partialNames);
        self::assertNotContains(Archiver::AI_CHATBOTS_AI_FAVOURED_PAGES_RECORD, $partialNames);
    }

    private function maxBlobIdArchive(): int
    {
        return (int) Db::fetchOne('SELECT MAX(idarchive) FROM ' . Common::prefixTable('archive_blob_2025_02'));
    }

    /**
     * Favoured-pages blob record names archived in Feb 2025, optionally only from archives created
     * after $idArchiveGreaterThan.
     *
     * @return string[]
     */
    private function favouredBlobNames(int $idArchiveGreaterThan = 0): array
    {
        $sql = 'SELECT DISTINCT name FROM ' . Common::prefixTable('archive_blob_2025_02')
            . ' WHERE idarchive > ? AND period = ? AND date1 = ? AND date2 = ? AND name LIKE ?';
        $rows = Db::fetchAll($sql, [
            $idArchiveGreaterThan,
            Range::PERIOD_ID,
            '2025-02-03',
            '2025-02-09',
            'BotTracking_AIChatbots%FavouredPages',
        ]);

        return array_column($rows, 'name');
    }
}

AIChatbotFavouredPagesPartialArchiveTest::$fixture = new BotTraffic();