xref: /dokuwiki/_test/tests/Search/IntegrityTest.php (revision 5e9d26e3624fd22ca3c57447be9e16d0b502761e)
1<?php
2
3namespace dokuwiki\test\Search;
4
5use dokuwiki\Search\Collection\PageFulltextCollection;
6use dokuwiki\Search\Collection\PageTitleCollection;
7use dokuwiki\Search\Exception\IndexIntegrityException;
8use dokuwiki\Search\Indexer;
9
10/**
11 * Tests the index integrity checking
12 */
13class IntegrityTest extends \DokuWikiTest
14{
15    /**
16     * Clear the index directory before each test
17     */
18    public function setUp(): void
19    {
20        parent::setUp();
21        global $conf;
22        $files = glob($conf['indexdir'] . '/*.idx');
23        foreach ($files as $file) {
24            @unlink($file);
25        }
26        \dokuwiki\Search\Index\Lock::releaseAll();
27    }
28
29    /**
30     * Index a page so we have data to check
31     */
32    protected function indexTestPage(): void
33    {
34        saveWikiText('integritytest', 'Hello world testing integrity check.', 'Test');
35        $indexer = new Indexer();
36        $indexer->addPage('integritytest');
37    }
38
39    /**
40     * A healthy index should not throw
41     */
42    public function testHealthyIndex()
43    {
44        $this->indexTestPage();
45
46        $indexer = new Indexer();
47        $indexer->checkIntegrity();
48        $this->assertFalse($indexer->isIndexEmpty());
49    }
50
51    /**
52     * An empty index should not throw
53     */
54    public function testEmptyIndex()
55    {
56        $indexer = new Indexer();
57        $indexer->checkIntegrity();
58        $this->assertTrue($indexer->isIndexEmpty());
59    }
60
61    /**
62     * Corrupted fulltext index (token/frequency mismatch) should throw
63     */
64    public function testCorruptedFulltextTokenFrequency()
65    {
66        global $conf;
67        $this->indexTestPage();
68
69        // Append an extra line to a token index to create a mismatch
70        $collection = new PageFulltextCollection();
71        $max = $collection->getTokenIndexMaximum();
72        $this->assertGreaterThan(0, $max);
73
74        $tokenFile = $conf['indexdir'] . '/w' . $max . '.idx';
75        $this->assertFileExists($tokenFile);
76        file_put_contents($tokenFile, "corruptedentry\n", FILE_APPEND);
77
78        $this->expectException(IndexIntegrityException::class);
79        (new PageFulltextCollection())->checkIntegrity();
80    }
81
82    /**
83     * Corrupted fulltext index (entity/reverse mismatch) should throw
84     */
85    public function testCorruptedFulltextEntityReverse()
86    {
87        global $conf;
88        $this->indexTestPage();
89
90        $reverseFile = $conf['indexdir'] . '/pageword.idx';
91        $this->assertFileExists($reverseFile);
92        file_put_contents($reverseFile, "0\n", FILE_APPEND);
93
94        $this->expectException(IndexIntegrityException::class);
95        (new PageFulltextCollection())->checkIntegrity();
96    }
97
98    /**
99     * Corrupted title index (entity/token mismatch) should throw
100     */
101    public function testCorruptedTitleIndex()
102    {
103        global $conf;
104        $this->indexTestPage();
105
106        $titleFile = $conf['indexdir'] . '/title.idx';
107        $this->assertFileExists($titleFile);
108        file_put_contents($titleFile, "extra title\n", FILE_APPEND);
109
110        $this->expectException(IndexIntegrityException::class);
111        (new PageTitleCollection())->checkIntegrity();
112    }
113
114    /**
115     * Indexer.checkIntegrity aggregates all collection checks
116     */
117    public function testIndexerCheckIntegrityDetectsCorruption()
118    {
119        global $conf;
120        $this->indexTestPage();
121
122        // Corrupt title index
123        $titleFile = $conf['indexdir'] . '/title.idx';
124        file_put_contents($titleFile, "extra title\n", FILE_APPEND);
125
126        $this->expectException(IndexIntegrityException::class);
127        (new Indexer())->checkIntegrity();
128    }
129}
130