2015-07-16 08:18:04 +02:00
|
|
|
<?php
|
|
|
|
|
2017-11-14 21:48:52 +01:00
|
|
|
namespace SilverStripe\FullTextSearch\Tests;
|
|
|
|
|
2017-04-26 12:52:20 +02:00
|
|
|
use SilverStripe\Core\Config\Config;
|
|
|
|
use SilverStripe\Core\Injector\Injector;
|
2017-04-21 02:23:27 +02:00
|
|
|
use SilverStripe\Dev\SapphireTest;
|
2017-04-21 03:26:07 +02:00
|
|
|
use SilverStripe\FullTextSearch\Search\FullTextSearch;
|
2020-06-10 07:22:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Search\Services\SearchableService;
|
2017-04-26 12:52:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler;
|
2018-06-15 04:33:40 +02:00
|
|
|
use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexQueuedHandler;
|
2017-04-26 12:52:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexGroupQueuedJob;
|
2018-06-15 04:33:40 +02:00
|
|
|
use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexQueuedJob;
|
|
|
|
use SilverStripe\FullTextSearch\Solr\Services\Solr4Service;
|
|
|
|
use SilverStripe\FullTextSearch\Solr\Services\SolrService;
|
2020-06-10 07:22:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SearchVariantVersionedTest\SearchVariantVersionedTest_Item;
|
2018-06-15 04:33:40 +02:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrReindexQueuedTest\SolrReindexQueuedTest_Service;
|
2017-04-26 12:52:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Index;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Item;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_RecordingLogger;
|
2018-06-15 04:33:40 +02:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant;
|
2017-11-29 03:31:17 +01:00
|
|
|
use Symbiote\QueuedJobs\Services\QueuedJob;
|
2017-04-21 03:26:07 +02:00
|
|
|
|
2015-07-16 08:18:04 +02:00
|
|
|
/**
|
|
|
|
* Additional tests of solr reindexing processes when run with queuedjobs
|
|
|
|
*/
|
2015-11-21 07:19:20 +01:00
|
|
|
class SolrReindexQueuedTest extends SapphireTest
|
|
|
|
{
|
|
|
|
protected $usesDatabase = true;
|
|
|
|
|
2017-04-26 12:52:20 +02:00
|
|
|
protected static $extra_dataobjects = array(
|
|
|
|
SolrReindexTest_Item::class
|
2015-11-21 07:19:20 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Forced index for testing
|
|
|
|
*
|
|
|
|
* @var SolrReindexTest_Index
|
|
|
|
*/
|
|
|
|
protected $index = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mock service
|
|
|
|
*
|
|
|
|
* @var SolrService
|
|
|
|
*/
|
|
|
|
protected $service = null;
|
|
|
|
|
2021-11-02 02:48:12 +01:00
|
|
|
protected function setUp(): void
|
2015-11-21 07:19:20 +01:00
|
|
|
{
|
|
|
|
parent::setUp();
|
|
|
|
|
2017-12-04 21:11:51 +01:00
|
|
|
if (!interface_exists(QueuedJob::class)) {
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->skipTest = true;
|
2021-11-02 02:48:12 +01:00
|
|
|
$this->markTestSkipped("These tests need the QueuedJobs module installed to run");
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set queued handler for reindex
|
2017-04-26 12:52:20 +02:00
|
|
|
Config::modify()->set(Injector::class, SolrReindexHandler::class, array(
|
|
|
|
'class' => SolrReindexQueuedHandler::class
|
2015-11-21 07:19:20 +01:00
|
|
|
));
|
2017-04-26 12:52:20 +02:00
|
|
|
Injector::inst()->registerService(new SolrReindexQueuedHandler(), SolrReindexHandler::class);
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
// Set test variant
|
|
|
|
SolrReindexTest_Variant::enable();
|
|
|
|
|
|
|
|
// Set index list
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->service = $this->serviceMock();
|
|
|
|
$this->index = singleton(SolrReindexTest_Index::class);
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->index->setService($this->service);
|
|
|
|
FullTextSearch::force_index_list($this->index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Populate database with dummy dataset
|
|
|
|
*
|
|
|
|
* @param int $number Number of records to create in each variant
|
|
|
|
*/
|
|
|
|
protected function createDummyData($number)
|
|
|
|
{
|
|
|
|
// Note that we don't create any records in variant = 2, to represent a variant
|
|
|
|
// that should be cleared without any re-indexes performed
|
2018-06-15 04:33:40 +02:00
|
|
|
foreach ([0, 1] as $variant) {
|
2015-11-21 07:19:20 +01:00
|
|
|
for ($i = 1; $i <= $number; $i++) {
|
|
|
|
$item = new SolrReindexTest_Item();
|
|
|
|
$item->Variant = $variant;
|
|
|
|
$item->Title = "Item $variant / $i";
|
|
|
|
$item->write();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mock service
|
|
|
|
*
|
|
|
|
* @return SolrService
|
|
|
|
*/
|
2017-04-26 12:52:20 +02:00
|
|
|
protected function serviceMock()
|
2015-11-21 07:19:20 +01:00
|
|
|
{
|
2017-04-26 12:52:20 +02:00
|
|
|
// Setup mock
|
2018-06-15 04:33:40 +02:00
|
|
|
/** @var Solr4Service $serviceMock */
|
2017-04-26 12:52:20 +02:00
|
|
|
$serviceMock = $this->getMockBuilder(Solr4Service::class)
|
|
|
|
->setMethods(['deleteByQuery', 'addDocument'])
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
return $serviceMock;
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
2021-11-02 02:48:12 +01:00
|
|
|
protected function tearDown(): void
|
2015-11-21 07:19:20 +01:00
|
|
|
{
|
|
|
|
FullTextSearch::force_index_list();
|
|
|
|
SolrReindexTest_Variant::disable();
|
|
|
|
parent::tearDown();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the reindex handler
|
|
|
|
*
|
|
|
|
* @return SolrReindexHandler
|
|
|
|
*/
|
|
|
|
protected function getHandler()
|
|
|
|
{
|
2017-04-26 12:52:20 +02:00
|
|
|
return Injector::inst()->get(SolrReindexHandler::class);
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return SolrReindexQueuedTest_Service
|
|
|
|
*/
|
|
|
|
protected function getQueuedJobService()
|
|
|
|
{
|
2017-04-26 12:52:20 +02:00
|
|
|
return Injector::inst()->get(SolrReindexQueuedTest_Service::class);
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that reindex will generate a top top level queued job, and executing this will perform
|
|
|
|
* the necessary initialisation of the grouped queued jobs
|
|
|
|
*/
|
|
|
|
public function testReindexSegmentsGroups()
|
|
|
|
{
|
2020-06-10 07:22:20 +02:00
|
|
|
$classesToSkip = [SolrReindexTest_Item::class];
|
|
|
|
Config::modify()->set(SearchableService::class, 'indexing_canview_exclude_classes', $classesToSkip);
|
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->createDummyData(18);
|
|
|
|
|
2017-04-26 12:52:20 +02:00
|
|
|
// Deletes are performed in the main task prior to individual groups being processed
|
|
|
|
// 18 records means 3 groups of 6 in each variant (6 total)
|
|
|
|
// Ensure correct call is made to Solr
|
|
|
|
$this->service->expects($this->exactly(2))
|
|
|
|
->method('deleteByQuery')
|
|
|
|
->withConsecutive(
|
|
|
|
[
|
|
|
|
$this->equalTo('-(ClassHierarchy:' . SolrReindexTest_Item::class . ')')
|
|
|
|
],
|
|
|
|
[
|
|
|
|
$this->equalTo('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")')
|
|
|
|
]
|
|
|
|
);
|
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
// Create pre-existing jobs
|
|
|
|
$this->getQueuedJobService()->queueJob(new SolrReindexQueuedJob());
|
|
|
|
$this->getQueuedJobService()->queueJob(new SolrReindexGroupQueuedJob());
|
|
|
|
$this->getQueuedJobService()->queueJob(new SolrReindexGroupQueuedJob());
|
|
|
|
|
|
|
|
// Initiate re-index
|
|
|
|
$logger = new SolrReindexTest_RecordingLogger();
|
|
|
|
$this->getHandler()->triggerReindex($logger, 6, 'Solr_Reindex');
|
|
|
|
|
|
|
|
// Old jobs should be cancelled
|
|
|
|
$this->assertEquals(1, $logger->countMessages('Cancelled 1 re-index tasks and 2 re-index groups'));
|
|
|
|
$this->assertEquals(1, $logger->countMessages('Queued Solr Reindex Job'));
|
|
|
|
|
|
|
|
// Next job should be queue job
|
|
|
|
$job = $this->getQueuedJobService()->getNextJob();
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->assertInstanceOf(SolrReindexQueuedJob::class, $job);
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals(6, $job->getBatchSize());
|
|
|
|
|
|
|
|
// Test that necessary items are created
|
|
|
|
$logger->clear();
|
|
|
|
$job->setLogger($logger);
|
|
|
|
$job->process();
|
|
|
|
|
|
|
|
$this->assertEquals(1, $logger->countMessages('Beginning init of reindex'));
|
|
|
|
$this->assertEquals(6, $logger->countMessages('Queued Solr Reindex Group '));
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}'));
|
|
|
|
$this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"1"}'));
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals(1, $logger->countMessages('Completed init of reindex'));
|
|
|
|
|
|
|
|
// Test that invalid classes are removed
|
2017-04-26 14:24:46 +02:00
|
|
|
$this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from ' . SolrReindexTest_Index::class));
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
// Test that valid classes in invalid variants are removed
|
|
|
|
$this->assertNotEmpty($logger->getMessages(
|
2017-04-26 12:52:20 +02:00
|
|
|
'Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {"' . SolrReindexTest_Variant::class . '":"2"}'
|
2015-11-21 07:19:20 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test index processing on individual groups
|
|
|
|
*/
|
|
|
|
public function testRunGroup()
|
|
|
|
{
|
2020-06-10 07:22:20 +02:00
|
|
|
$classesToSkip = [SolrReindexTest_Item::class];
|
|
|
|
Config::modify()->set(SearchableService::class, 'indexing_canview_exclude_classes', $classesToSkip);
|
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->createDummyData(18);
|
|
|
|
|
|
|
|
// Just do what the SolrReindexQueuedJob would do to create each sub
|
|
|
|
$logger = new SolrReindexTest_RecordingLogger();
|
|
|
|
$this->getHandler()->runReindex($logger, 6, 'Solr_Reindex');
|
|
|
|
|
|
|
|
// Assert jobs are created
|
|
|
|
$this->assertEquals(6, $logger->countMessages('Queued Solr Reindex Group'));
|
|
|
|
|
|
|
|
// Check next job is a group queued job
|
2018-06-15 04:33:40 +02:00
|
|
|
/** @var SolrReindexGroupQueuedJob $job */
|
2015-11-21 07:19:20 +01:00
|
|
|
$job = $this->getQueuedJobService()->getNextJob();
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->assertInstanceOf(SolrReindexGroupQueuedJob::class, $job);
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals(
|
2017-04-26 12:52:20 +02:00
|
|
|
'Solr Reindex Group (1/3) of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}',
|
2015-11-21 07:19:20 +01:00
|
|
|
$job->getTitle()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Running this job performs the necessary reindex
|
|
|
|
$logger->clear();
|
|
|
|
$job->setLogger($logger);
|
|
|
|
$job->process();
|
|
|
|
|
|
|
|
// Check tasks completed (as per non-queuedjob version)
|
|
|
|
$this->assertEquals(1, $logger->countMessages('Beginning reindex group'));
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->assertEquals(1, $logger->countMessages('Adding ' . SolrReindexTest_Item::class . ''));
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals(1, $logger->countMessages('Queuing commit on all changes'));
|
|
|
|
$this->assertEquals(1, $logger->countMessages('Completed reindex group'));
|
|
|
|
|
|
|
|
// Check IDs
|
|
|
|
$idMessage = $logger->filterMessages('Updated ');
|
2022-04-13 01:24:03 +02:00
|
|
|
$this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0] ?? '', $matches));
|
|
|
|
$ids = array_unique(explode(',', $matches['ids'] ?? ''));
|
|
|
|
$this->assertEquals(6, count($ids ?? []));
|
2015-11-21 07:19:20 +01:00
|
|
|
foreach ($ids as $id) {
|
|
|
|
// Each id should be % 3 == 0
|
|
|
|
$this->assertEquals(0, $id % 3, "ID $id Should match pattern ID % 3 = 0");
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 08:18:04 +02:00
|
|
|
}
|