Passed
Pull Request — master (#208)
by
unknown
02:17
created

SolrReindexQueuedTest::setUp()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 12
nc 2
nop 0
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\FullTextSearch\Tests;
4
5
use SilverStripe\Core\Config\Config;
6
use SilverStripe\Core\Injector\Injector;
7
use SilverStripe\Dev\SapphireTest;
8
use SilverStripe\ORM\DataObject;
9
use SilverStripe\ORM\DB;
10
use SilverStripe\FullTextSearch\Search\FullTextSearch;
11
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
12
use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexQueuedHandler;
13
use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler;
14
use SilverStripe\FullTextSearch\Solr\Services\Solr4Service;
15
use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexQueuedJob;
16
use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexGroupQueuedJob;
17
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant;
18
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Index;
19
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Item;
20
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_RecordingLogger;
21
use SilverStripe\FullTextSearch\Tests\SolrReindexQueuedTest\SolrReindexQueuedTest_Service;
22
use Symbiote\QueuedJobs\Services\QueuedJob;
0 ignored issues
show
Bug introduced by
The type Symbiote\QueuedJobs\Services\QueuedJob was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Symbiote\QueuedJobs\Services\QueuedJobService;
0 ignored issues
show
Bug introduced by
The type Symbiote\QueuedJobs\Services\QueuedJobService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
25
/**
26
 * Additional tests of solr reindexing processes when run with queuedjobs
27
 */
28
class SolrReindexQueuedTest extends SapphireTest
29
{
30
    protected $usesDatabase = true;
31
32
    protected static $extra_dataobjects = array(
33
        SolrReindexTest_Item::class
34
    );
35
36
    /**
37
     * Forced index for testing
38
     *
39
     * @var SolrReindexTest_Index
40
     */
41
    protected $index = null;
42
43
    /**
44
     * Mock service
45
     *
46
     * @var SolrService
0 ignored issues
show
Bug introduced by
The type SilverStripe\FullTextSearch\Tests\SolrService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
47
     */
48
    protected $service = null;
49
50
    protected function setUp()
51
    {
52
        parent::setUp();
53
54
        if (!interface_exists(QueuedJob::class)) {
55
            $this->skipTest = true;
0 ignored issues
show
Bug Best Practice introduced by
The property skipTest does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
56
            return $this->markTestSkipped("These tests need the QueuedJobs module installed to run");
57
        }
58
59
        // Set queued handler for reindex
60
        Config::modify()->set(Injector::class, SolrReindexHandler::class, array(
61
            'class' => SolrReindexQueuedHandler::class
62
        ));
63
        Injector::inst()->registerService(new SolrReindexQueuedHandler(), SolrReindexHandler::class);
64
65
        // Set test variant
66
        SolrReindexTest_Variant::enable();
67
68
        // Set index list
69
        $this->service = $this->serviceMock();
70
        $this->index = singleton(SolrReindexTest_Index::class);
71
        $this->index->setService($this->service);
72
        FullTextSearch::force_index_list($this->index);
73
    }
74
75
    /**
76
     * Populate database with dummy dataset
77
     *
78
     * @param int $number Number of records to create in each variant
79
     */
80
    protected function createDummyData($number)
81
    {
82
        // Populate dataobjects. Use truncate to generate predictable IDs
83
        $tableName = DataObject::getSchema()->tableName(SolrReindexTest_Item::class);
84
        DB::get_conn()->clearTable($tableName);
85
86
        // Note that we don't create any records in variant = 2, to represent a variant
87
        // that should be cleared without any re-indexes performed
88
        foreach (array(0, 1) as $variant) {
89
            for ($i = 1; $i <= $number; $i++) {
90
                $item = new SolrReindexTest_Item();
91
                $item->Variant = $variant;
0 ignored issues
show
Bug Best Practice introduced by
The property Variant does not exist on SilverStripe\FullTextSea...st\SolrReindexTest_Item. Since you implemented __set, consider adding a @property annotation.
Loading history...
92
                $item->Title = "Item $variant / $i";
93
                $item->write();
94
            }
95
        }
96
    }
97
98
    /**
99
     * Mock service
100
     *
101
     * @return SolrService
102
     */
103
    protected function serviceMock()
104
    {
105
        // Setup mock
106
        /** @var SilverStripe\FullTextSearch\Solr\Services\Solr4Service|ObjectProphecy $serviceMock */
107
        $serviceMock = $this->getMockBuilder(Solr4Service::class)
108
            ->setMethods(['deleteByQuery', 'addDocument'])
109
            ->getMock();
110
111
        return $serviceMock;
112
    }
113
114
    public function tearDown()
115
    {
116
        FullTextSearch::force_index_list();
117
        SolrReindexTest_Variant::disable();
118
        parent::tearDown();
119
    }
120
121
    /**
122
     * Get the reindex handler
123
     *
124
     * @return SolrReindexHandler
125
     */
126
    protected function getHandler()
127
    {
128
        return Injector::inst()->get(SolrReindexHandler::class);
129
    }
130
131
    /**
132
     * @return SolrReindexQueuedTest_Service
133
     */
134
    protected function getQueuedJobService()
135
    {
136
        return Injector::inst()->get(SolrReindexQueuedTest_Service::class);
137
    }
138
139
    /**
140
     * Test that reindex will generate a top top level queued job, and executing this will perform
141
     * the necessary initialisation of the grouped queued jobs
142
     */
143
    public function testReindexSegmentsGroups()
144
    {
145
        $this->createDummyData(18);
146
147
        // Deletes are performed in the main task prior to individual groups being processed
148
        // 18 records means 3 groups of 6 in each variant (6 total)
149
        // Ensure correct call is made to Solr
150
        $this->service->expects($this->exactly(2))
151
            ->method('deleteByQuery')
152
            ->withConsecutive(
153
                [
154
                    $this->equalTo('-(ClassHierarchy:' . SolrReindexTest_Item::class . ')')
155
                ],
156
                [
157
                    $this->equalTo('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")')
158
                ]
159
            );
160
161
        // Create pre-existing jobs
162
        $this->getQueuedJobService()->queueJob(new SolrReindexQueuedJob());
163
        $this->getQueuedJobService()->queueJob(new SolrReindexGroupQueuedJob());
164
        $this->getQueuedJobService()->queueJob(new SolrReindexGroupQueuedJob());
165
166
        // Initiate re-index
167
        $logger = new SolrReindexTest_RecordingLogger();
168
        $this->getHandler()->triggerReindex($logger, 6, 'Solr_Reindex');
169
170
        // Old jobs should be cancelled
171
        $this->assertEquals(1, $logger->countMessages('Cancelled 1 re-index tasks and 2 re-index groups'));
172
        $this->assertEquals(1, $logger->countMessages('Queued Solr Reindex Job'));
173
174
        // Next job should be queue job
175
        $job = $this->getQueuedJobService()->getNextJob();
176
        $this->assertInstanceOf(SolrReindexQueuedJob::class, $job);
177
        $this->assertEquals(6, $job->getBatchSize());
178
179
        // Test that necessary items are created
180
        $logger->clear();
181
        $job->setLogger($logger);
182
        $job->process();
183
184
        $this->assertEquals(1, $logger->countMessages('Beginning init of reindex'));
185
        $this->assertEquals(6, $logger->countMessages('Queued Solr Reindex Group '));
186
        $this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}'));
187
        $this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"1"}'));
188
        $this->assertEquals(1, $logger->countMessages('Completed init of reindex'));
189
190
        // Test that invalid classes are removed
191
        $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from ' . SolrReindexTest_Index::class));
0 ignored issues
show
Unused Code introduced by
The call to SilverStripe\FullTextSea...ngLogger::getMessages() has too many arguments starting with 'Clearing obsolete class...eindexTest_Index::class. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

191
        $this->assertNotEmpty($logger->/** @scrutinizer ignore-call */ getMessages('Clearing obsolete classes from ' . SolrReindexTest_Index::class));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
192
193
        // Test that valid classes in invalid variants are removed
194
        $this->assertNotEmpty($logger->getMessages(
195
            'Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {"' . SolrReindexTest_Variant::class . '":"2"}'
196
        ));
197
    }
198
199
    /**
200
     * Test index processing on individual groups
201
     */
202
    public function testRunGroup()
203
    {
204
        $this->createDummyData(18);
205
206
        // Just do what the SolrReindexQueuedJob would do to create each sub
207
        $logger = new SolrReindexTest_RecordingLogger();
208
        $this->getHandler()->runReindex($logger, 6, 'Solr_Reindex');
209
210
        // Assert jobs are created
211
        $this->assertEquals(6, $logger->countMessages('Queued Solr Reindex Group'));
212
213
        // Check next job is a group queued job
214
        $job = $this->getQueuedJobService()->getNextJob();
215
        $this->assertInstanceOf(SolrReindexGroupQueuedJob::class, $job);
216
        $this->assertEquals(
217
            'Solr Reindex Group (1/3) of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}',
218
            $job->getTitle()
219
        );
220
221
        // Running this job performs the necessary reindex
222
        $logger->clear();
223
        $job->setLogger($logger);
224
        $job->process();
225
226
        // Check tasks completed (as per non-queuedjob version)
227
        $this->assertEquals(1, $logger->countMessages('Beginning reindex group'));
228
        $this->assertEquals(1, $logger->countMessages('Adding ' . SolrReindexTest_Item::class . ''));
229
        $this->assertEquals(1, $logger->countMessages('Queuing commit on all changes'));
230
        $this->assertEquals(1, $logger->countMessages('Completed reindex group'));
231
232
        // Check IDs
233
        $idMessage = $logger->filterMessages('Updated ');
234
        $this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0], $matches));
235
        $ids = array_unique(explode(',', $matches['ids']));
236
        $this->assertEquals(6, count($ids));
237
        foreach ($ids as $id) {
238
            // Each id should be % 3 == 0
239
            $this->assertEquals(0, $id % 3, "ID $id Should match pattern ID % 3 = 0");
240
        }
241
    }
242
}
243