Completed
Push — master ( d98303...8deccf )
by
unknown
14s
created

tests/SolrReindexTest.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SilverStripe\FullTextSearch\Tests;
4
5
use SilverStripe\Dev\SapphireTest;
6
use SilverStripe\FullTextSearch\Search\FullTextSearch;
7
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
8
use SilverStripe\FullTextSearch\Search\Variants\SearchVariant;
9
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant;
10
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Index;
11
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_TestHandler;
12
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Item;
13
use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_RecordingLogger;
14
use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler;
15
use SilverStripe\FullTextSearch\Solr\Services\Solr4Service;
16
use SilverStripe\FullTextSearch\Solr\Tasks\Solr_Reindex;
17
use SilverStripe\Core\Config\Config;
18
use SilverStripe\Core\Injector\Injector;
19
use SilverStripe\ORM\DataObject;
20
use SilverStripe\ORM\DB;
21
22
class SolrReindexTest extends SapphireTest
23
{
24
    protected $usesDatabase = true;
25
26
    protected static $extra_dataobjects = array(
27
        SolrReindexTest_Item::class
28
    );
29
30
    /**
31
     * Forced index for testing
32
     *
33
     * @var SolrReindexTest_Index
34
     */
35
    protected $index = null;
36
37
    /**
38
     * Mock service
39
     *
40
     * @var SolrService
41
     */
42
    protected $service = null;
43
44
    protected function setUp()
45
    {
46
        parent::setUp();
47
48
        // Set test handler for reindex
49
        Config::modify()->set(Injector::class, SolrReindexHandler::class, array(
50
            'class' => SolrReindexTest_TestHandler::class
51
        ));
52
53
        Injector::inst()->registerService(new SolrReindexTest_TestHandler(), SolrReindexHandler::class);
54
55
        // Set test variant
56
        SolrReindexTest_Variant::enable();
57
58
        // Set index list
59
        $this->service = $this->getServiceMock();
60
        $this->index = singleton(SolrReindexTest_Index::class);
61
        $this->index->setService($this->service);
62
63
        FullTextSearch::force_index_list($this->index);
64
    }
65
66
    /**
67
     * Populate database with dummy dataset
68
     *
69
     * @param int $number Number of records to create in each variant
70
     */
71
    protected function createDummyData($number)
72
    {
73
        self::resetDBSchema();
74
75
        // Note that we don't create any records in variant = 2, to represent a variant
76
        // that should be cleared without any re-indexes performed
77 View Code Duplication
        foreach (array(0, 1) as $variant) {
78
            for ($i = 1; $i <= $number; $i++) {
79
                $item = new SolrReindexTest_Item();
80
                $item->Variant = $variant;
81
                $item->Title = "Item $variant / $i";
82
                $item->write();
83
            }
84
        }
85
    }
86
87
    /**
88
     * Mock service
89
     *
90
     * @return SolrService
91
     */
92
    protected function getServiceMock()
93
    {
94
        $serviceMock = $this->getMockBuilder(Solr4Service::class)
95
            ->setMethods(['deleteByQuery', 'addDocument']);
96
97
        return $serviceMock->getMock();
98
    }
99
100
    public function tearDown()
101
    {
102
        FullTextSearch::force_index_list();
103
        SolrReindexTest_Variant::disable();
104
        parent::tearDown();
105
    }
106
107
    /**
108
     * Get the reindex handler
109
     *
110
     * @return SolrReindexHandler
111
     */
112
    protected function getHandler()
113
    {
114
        return Injector::inst()->get(SolrReindexHandler::class);
115
    }
116
117
    /**
118
     * Ensure the test variant is up and running properly
119
     */
120
    public function testVariant()
121
    {
122
        // State defaults to 0
123
        $variant = SearchVariant::current_state();
124
        $this->assertEquals(
125
            array(
126
                SolrReindexTest_Variant::class => "0"
127
            ),
128
            $variant
129
        );
130
131
        // All states enumerated
132
        $allStates = iterator_to_array(SearchVariant::reindex_states());
133
        $this->assertEquals(
134
            array(
135
                array(
136
                    SolrReindexTest_Variant::class => "0"
137
                ),
138
                array(
139
                    SolrReindexTest_Variant::class => "1"
140
                ),
141
                array(
142
                    SolrReindexTest_Variant::class => "2"
143
                )
144
            ),
145
            $allStates
146
        );
147
148
        // Check correct items created and that filtering on variant works
149
        $this->createDummyData(120);
150
        SolrReindexTest_Variant::set_current(2);
151
        $this->assertEquals(0, SolrReindexTest_Item::get()->count());
152
        SolrReindexTest_Variant::set_current(1);
153
        $this->assertEquals(120, SolrReindexTest_Item::get()->count());
154
        SolrReindexTest_Variant::set_current(0);
155
        $this->assertEquals(120, SolrReindexTest_Item::get()->count());
156
        SolrReindexTest_Variant::disable();
157
        $this->assertEquals(240, SolrReindexTest_Item::get()->count());
158
    }
159
160
161
    /**
162
     * Given the invocation of a new re-index with a given set of data, ensure that the necessary
163
     * list of groups are created and segmented for each state
164
     *
165
     * Test should work fine with any variants (versioned, subsites, etc) specified
166
     */
167
    public function testReindexSegmentsGroups()
168
    {
169
        $this->service->method('deleteByQuery')
170
            ->withConsecutive(
171
                ['-(ClassHierarchy:' . SolrReindexTest_Item::class . ')'],
172
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")']
173
            );
174
175
        $this->createDummyData(120);
176
177
        // Initiate re-index
178
        $logger = new SolrReindexTest_RecordingLogger();
179
        $this->getHandler()->runReindex($logger, 21, Solr_Reindex::class);
180
181
        // Test that invalid classes are removed
182
        $this->assertContains('Clearing obsolete classes from ' . SolrReindexTest_Index::class, $logger->getMessages());
183
        //var_dump($logger->getMessages());
0 ignored issues
show
Unused Code Comprehensibility introduced by
78% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
184
        // Test that valid classes in invalid variants are removed
185
        $this->assertContains('Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {' . json_encode(SolrReindexTest_Variant::class) . ':"2"}', $logger->getMessages());
186
187
        // 120x2 grouped into groups of 21 results in 12 groups
188
        $this->assertEquals(12, $logger->countMessages('Called processGroup with '));
189
        $this->assertEquals(6, $logger->countMessages('{' . json_encode(SolrReindexTest_Variant::class) . ':"0"}'));
190
        $this->assertEquals(6, $logger->countMessages('{' . json_encode(SolrReindexTest_Variant::class) . ':"1"}'));
191
192
        // Given that there are two variants, there should be two group ids of each number
193
        $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 0 of 6'));
194
        $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 1 of 6'));
195
        $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 2 of 6'));
196
        $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 3 of 6'));
197
        $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 4 of 6'));
198
        $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 5 of 6'));
199
200
        // Check various group sizes
201
        $logger->clear();
202
        $this->getHandler()->runReindex($logger, 120, 'Solr_Reindex');
203
        $this->assertEquals(2, $logger->countMessages('Called processGroup with '));
204
        $logger->clear();
205
        $this->getHandler()->runReindex($logger, 119, 'Solr_Reindex');
206
        $this->assertEquals(4, $logger->countMessages('Called processGroup with '));
207
        $logger->clear();
208
        $this->getHandler()->runReindex($logger, 121, 'Solr_Reindex');
209
        $this->assertEquals(2, $logger->countMessages('Called processGroup with '));
210
        $logger->clear();
211
        $this->getHandler()->runReindex($logger, 2, 'Solr_Reindex');
212
        $this->assertEquals(120, $logger->countMessages('Called processGroup with '));
213
    }
214
215
    /**
216
     * Test index processing on individual groups
217
     */
218
    public function testRunGroup()
219
    {
220
        $this->service->method('deleteByQuery')
221
            ->with('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")');
222
223
        $this->createDummyData(120);
224
        $logger = new SolrReindexTest_RecordingLogger();
225
226
        // Initiate re-index of third group (index 2 of 6)
227
        $state = array(SolrReindexTest_Variant::class => '1');
228
        $this->getHandler()->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, 2);
229
        $idMessage = $logger->filterMessages('Updated ');
230
        $this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0], $matches));
231
        $ids = array_unique(explode(',', $matches['ids']));
232
233
        // Test successful
234
        $this->assertNotEmpty($logger->getMessages('Adding ' . SolrReindexTest_Item::class));
235
        $this->assertNotEmpty($logger->getMessages('Done'));
236
237
        // Test that items in this variant / group are re-indexed
238
        // 120 divided into 6 groups should be 20 at least (max 21)
239
        $this->assertEquals(21, count($ids), 'Group size is about 20', 1);
240
        foreach ($ids as $id) {
241
            // Each id should be % 6 == 2
242
            $this->assertEquals(2, $id % 6, "ID $id Should match pattern ID % 6 = 2");
243
        }
244
    }
245
246
    /**
247
     * Test that running all groups covers the entire range of dataobject IDs
248
     */
249
    public function testRunAllGroups()
250
    {
251
        $this->service->method('deleteByQuery')
252
            ->withConsecutive(
253
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=0 u=0}mod(ID, 6)" +(_testvariant:"1")'],
254
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=1 u=1}mod(ID, 6)" +(_testvariant:"1")'],
255
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")'],
256
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=3 u=3}mod(ID, 6)" +(_testvariant:"1")'],
257
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=4 u=4}mod(ID, 6)" +(_testvariant:"1")'],
258
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=5 u=5}mod(ID, 6)" +(_testvariant:"1")'],
259
                ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=6 u=6}mod(ID, 6)" +(_testvariant:"1")']
260
            );
261
262
        $this->createDummyData(120);
263
        $logger = new SolrReindexTest_RecordingLogger();
264
265
        // Test that running all groups covers the complete set of ids
266
        $state = array(SolrReindexTest_Variant::class => '1');
267
        for ($i = 0; $i < 6; $i++) {
268
            // See testReindexSegmentsGroups for test that each of these states is invoked during a full reindex
269
            $this
270
                ->getHandler()
271
                ->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, $i);
272
        }
273
274
        // Count all ids updated
275
        $ids = array();
276
        foreach ($logger->filterMessages('Updated ') as $message) {
277
            $this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/', $message, $matches));
278
            $ids = array_unique(array_merge($ids, explode(',', $matches['ids'])));
279
        }
280
281
        // Check ids
282
        $this->assertEquals(120, count($ids));
283
    }
284
}
285