121fbd01bSAndreas Gohr<?php 221fbd01bSAndreas Gohr 321fbd01bSAndreas Gohrnamespace dokuwiki\test\Search; 421fbd01bSAndreas Gohr 521fbd01bSAndreas Gohruse dokuwiki\Search\Collection\PageFulltextCollection; 621fbd01bSAndreas Gohruse dokuwiki\Search\Collection\PageTitleCollection; 721fbd01bSAndreas Gohruse dokuwiki\Search\Exception\IndexIntegrityException; 821fbd01bSAndreas Gohruse dokuwiki\Search\Indexer; 921fbd01bSAndreas Gohr 1021fbd01bSAndreas Gohr/** 1121fbd01bSAndreas Gohr * Tests the index integrity checking 1221fbd01bSAndreas Gohr */ 1321fbd01bSAndreas Gohrclass IntegrityTest extends \DokuWikiTest 1421fbd01bSAndreas Gohr{ 1521fbd01bSAndreas Gohr /** 16*b188a75bSAndreas Gohr * Clear the index directory and indexing metadata before each test 1721fbd01bSAndreas Gohr */ 1821fbd01bSAndreas Gohr public function setUp(): void 1921fbd01bSAndreas Gohr { 2021fbd01bSAndreas Gohr parent::setUp(); 2121fbd01bSAndreas Gohr global $conf; 2221fbd01bSAndreas Gohr $files = glob($conf['indexdir'] . '/*.idx'); 2321fbd01bSAndreas Gohr foreach ($files as $file) { 2421fbd01bSAndreas Gohr @unlink($file); 2521fbd01bSAndreas Gohr } 26*b188a75bSAndreas Gohr // remove the .indexed tag so needsIndexing() won't skip re-indexing 27*b188a75bSAndreas Gohr @unlink(metaFN('integritytest', '.indexed')); 2821fbd01bSAndreas Gohr \dokuwiki\Search\Index\Lock::releaseAll(); 2921fbd01bSAndreas Gohr } 3021fbd01bSAndreas Gohr 3121fbd01bSAndreas Gohr /** 3221fbd01bSAndreas Gohr * Index a page so we have data to check 3321fbd01bSAndreas Gohr */ 3421fbd01bSAndreas Gohr protected function indexTestPage(): void 3521fbd01bSAndreas Gohr { 3621fbd01bSAndreas Gohr saveWikiText('integritytest', 'Hello world testing integrity check.', 'Test'); 3721fbd01bSAndreas Gohr $indexer = new Indexer(); 3821fbd01bSAndreas Gohr $indexer->addPage('integritytest'); 3921fbd01bSAndreas Gohr } 4021fbd01bSAndreas Gohr 4121fbd01bSAndreas Gohr /** 4221fbd01bSAndreas Gohr * A healthy index should not throw 4321fbd01bSAndreas Gohr */ 4421fbd01bSAndreas Gohr public function testHealthyIndex() 4521fbd01bSAndreas Gohr { 4621fbd01bSAndreas Gohr $this->indexTestPage(); 4721fbd01bSAndreas Gohr 4821fbd01bSAndreas Gohr $indexer = new Indexer(); 4921fbd01bSAndreas Gohr $indexer->checkIntegrity(); 5021fbd01bSAndreas Gohr $this->assertFalse($indexer->isIndexEmpty()); 5121fbd01bSAndreas Gohr } 5221fbd01bSAndreas Gohr 5321fbd01bSAndreas Gohr /** 5421fbd01bSAndreas Gohr * An empty index should not throw 5521fbd01bSAndreas Gohr */ 5621fbd01bSAndreas Gohr public function testEmptyIndex() 5721fbd01bSAndreas Gohr { 5821fbd01bSAndreas Gohr $indexer = new Indexer(); 5921fbd01bSAndreas Gohr $indexer->checkIntegrity(); 6021fbd01bSAndreas Gohr $this->assertTrue($indexer->isIndexEmpty()); 6121fbd01bSAndreas Gohr } 6221fbd01bSAndreas Gohr 6321fbd01bSAndreas Gohr /** 6421fbd01bSAndreas Gohr * Corrupted fulltext index (token/frequency mismatch) should throw 6521fbd01bSAndreas Gohr */ 6621fbd01bSAndreas Gohr public function testCorruptedFulltextTokenFrequency() 6721fbd01bSAndreas Gohr { 6821fbd01bSAndreas Gohr global $conf; 6921fbd01bSAndreas Gohr $this->indexTestPage(); 7021fbd01bSAndreas Gohr 7121fbd01bSAndreas Gohr // Append an extra line to a token index to create a mismatch 7221fbd01bSAndreas Gohr $collection = new PageFulltextCollection(); 7321fbd01bSAndreas Gohr $max = $collection->getTokenIndexMaximum(); 7421fbd01bSAndreas Gohr $this->assertGreaterThan(0, $max); 7521fbd01bSAndreas Gohr 7621fbd01bSAndreas Gohr $tokenFile = $conf['indexdir'] . '/w' . $max . '.idx'; 7721fbd01bSAndreas Gohr $this->assertFileExists($tokenFile); 7821fbd01bSAndreas Gohr file_put_contents($tokenFile, "corruptedentry\n", FILE_APPEND); 7921fbd01bSAndreas Gohr 8021fbd01bSAndreas Gohr $this->expectException(IndexIntegrityException::class); 8121fbd01bSAndreas Gohr (new PageFulltextCollection())->checkIntegrity(); 8221fbd01bSAndreas Gohr } 8321fbd01bSAndreas Gohr 8421fbd01bSAndreas Gohr /** 8521fbd01bSAndreas Gohr * Corrupted fulltext index (entity/reverse mismatch) should throw 8621fbd01bSAndreas Gohr */ 8721fbd01bSAndreas Gohr public function testCorruptedFulltextEntityReverse() 8821fbd01bSAndreas Gohr { 8921fbd01bSAndreas Gohr global $conf; 9021fbd01bSAndreas Gohr $this->indexTestPage(); 9121fbd01bSAndreas Gohr 9221fbd01bSAndreas Gohr $reverseFile = $conf['indexdir'] . '/pageword.idx'; 9321fbd01bSAndreas Gohr $this->assertFileExists($reverseFile); 9421fbd01bSAndreas Gohr file_put_contents($reverseFile, "0\n", FILE_APPEND); 9521fbd01bSAndreas Gohr 9621fbd01bSAndreas Gohr $this->expectException(IndexIntegrityException::class); 9721fbd01bSAndreas Gohr (new PageFulltextCollection())->checkIntegrity(); 9821fbd01bSAndreas Gohr } 9921fbd01bSAndreas Gohr 10021fbd01bSAndreas Gohr /** 10121fbd01bSAndreas Gohr * Corrupted title index (entity/token mismatch) should throw 10221fbd01bSAndreas Gohr */ 10321fbd01bSAndreas Gohr public function testCorruptedTitleIndex() 10421fbd01bSAndreas Gohr { 10521fbd01bSAndreas Gohr global $conf; 10621fbd01bSAndreas Gohr $this->indexTestPage(); 10721fbd01bSAndreas Gohr 10821fbd01bSAndreas Gohr $titleFile = $conf['indexdir'] . '/title.idx'; 10921fbd01bSAndreas Gohr $this->assertFileExists($titleFile); 11021fbd01bSAndreas Gohr file_put_contents($titleFile, "extra title\n", FILE_APPEND); 11121fbd01bSAndreas Gohr 11221fbd01bSAndreas Gohr $this->expectException(IndexIntegrityException::class); 11321fbd01bSAndreas Gohr (new PageTitleCollection())->checkIntegrity(); 11421fbd01bSAndreas Gohr } 11521fbd01bSAndreas Gohr 11621fbd01bSAndreas Gohr /** 11721fbd01bSAndreas Gohr * Indexer.checkIntegrity aggregates all collection checks 11821fbd01bSAndreas Gohr */ 11921fbd01bSAndreas Gohr public function testIndexerCheckIntegrityDetectsCorruption() 12021fbd01bSAndreas Gohr { 12121fbd01bSAndreas Gohr global $conf; 12221fbd01bSAndreas Gohr $this->indexTestPage(); 12321fbd01bSAndreas Gohr 12421fbd01bSAndreas Gohr // Corrupt title index 12521fbd01bSAndreas Gohr $titleFile = $conf['indexdir'] . '/title.idx'; 12621fbd01bSAndreas Gohr file_put_contents($titleFile, "extra title\n", FILE_APPEND); 12721fbd01bSAndreas Gohr 12821fbd01bSAndreas Gohr $this->expectException(IndexIntegrityException::class); 12921fbd01bSAndreas Gohr (new Indexer())->checkIntegrity(); 13021fbd01bSAndreas Gohr } 13121fbd01bSAndreas Gohr} 132