Issues (186)

tests/SolrIndexTest.php (5 issues)

1
<?php
2
3
namespace SilverStripe\FullTextSearch\Tests;
4
5
use Apache_Solr_Document;
6
use Page;
0 ignored issues
show
The type Page 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...
7
use SebastianBergmann\Version;
8
use SilverStripe\Assets\File;
9
use SilverStripe\CMS\Model\SiteTree;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\Core\Environment;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Core\Kernel;
14
use SilverStripe\Dev\SapphireTest;
15
use SilverStripe\FullTextSearch\Search\FullTextSearch;
16
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
17
use SilverStripe\FullTextSearch\Search\Services\IndexableService;
18
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
19
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites;
20
use SilverStripe\FullTextSearch\Solr\SolrIndex;
21
use SilverStripe\FullTextSearch\Solr\Services\Solr3Service;
22
use SilverStripe\FullTextSearch\Solr\Services\Solr4Service;
23
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container;
24
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne;
25
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany;
26
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_ManyMany;
27
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_OtherContainer;
28
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationIndex;
29
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationInheritedIndex;
30
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex;
31
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex;
32
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2;
33
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_ShowInSearchIndex;
34
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_MyPage;
35
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_MyDataObjectOne;
36
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_MyDataObjectTwo;
37
use SilverStripe\ORM\DataObject;
38
use SilverStripe\Subsites\Model\Subsite;
39
use SilverStripe\Versioned\Versioned;
40
41
class SolrIndexTest extends SapphireTest
42
{
43
44
    protected $usesDatabase = true;
45
46
    protected static $extra_dataobjects = [
47
        SolrIndexTest_MyPage::class,
48
        SolrIndexTest_MyDataObjectOne::class,
49
        SolrIndexTest_MyDataObjectTwo::class,
50
    ];
51
52
    public function testFieldDataHasOne()
53
    {
54
        $index = new SolrIndexTest_FakeIndex();
55
        $data = $index->fieldData('HasOneObject.Field1');
56
57
        $data = $data[SearchUpdaterTest_Container::class . '_HasOneObject_Field1'];
58
59
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
60
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
61
        $this->assertEquals(SearchUpdaterTest_HasOne::class, $data['class']);
62
    }
63
64
    public function testFieldDataHasMany()
65
    {
66
        $index = new SolrIndexTest_FakeIndex();
67
        $data = $index->fieldData('HasManyObjects.Field1');
68
        $data = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1'];
69
70
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
71
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
72
        $this->assertEquals(SearchUpdaterTest_HasMany::class, $data['class']);
73
    }
74
75
    public function testFieldDataManyMany()
76
    {
77
        $index = new SolrIndexTest_FakeIndex();
78
        $data = $index->fieldData('ManyManyObjects.Field1');
79
        $data = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
80
81
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
82
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
83
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $data['class']);
84
    }
85
86
    public function testFieldDataAmbiguousHasMany()
87
    {
88
        $index = new SolrIndexTest_AmbiguousRelationIndex();
89
        $data = $index->fieldData('HasManyObjects.Field1');
90
91
        $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_HasManyObjects_Field1', $data);
92
        $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1', $data);
93
94
        $dataContainer = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1'];
95
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
96
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
97
        $this->assertEquals(SearchUpdaterTest_HasMany::class, $dataContainer['class']);
98
99
        $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1'];
100
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
101
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
102
        $this->assertEquals(SearchUpdaterTest_HasMany::class, $dataOtherContainer['class']);
103
    }
104
105
    public function testFieldDataAmbiguousManyMany()
106
    {
107
        $index = new SolrIndexTest_AmbiguousRelationIndex();
108
        $data = $index->fieldData('ManyManyObjects.Field1');
109
110
        $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data);
111
        $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data);
112
113
        $dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
114
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
115
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
116
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']);
117
118
        $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1'];
119
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
120
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
121
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']);
122
    }
123
124
    public function testFieldDataAmbiguousManyManyInherited()
125
    {
126
        $index = new SolrIndexTest_AmbiguousRelationInheritedIndex();
127
        $data = $index->fieldData('ManyManyObjects.Field1');
128
129
        $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data);
130
        $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data);
131
        $this->assertArrayNotHasKey(SearchUpdaterTest_ExtendedContainer::class . '_ManyManyObjects_Field1', $data);
132
133
        $dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
134
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
135
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
136
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']);
137
138
        $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1'];
139
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
140
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
141
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']);
142
    }
143
144
    /**
145
     * Test boosting on SearchQuery
146
     */
147
    public function testBoostedQuery()
148
    {
149
        /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */
150
        $serviceMock = $this->getMockBuilder(Solr3Service::class)
151
            ->setMethods(['search'])
152
            ->getMock();
153
154
        $serviceMock->expects($this->once())
155
            ->method('search')
156
            ->with(
157
                $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
158
                $this->anything(),
159
                $this->anything(),
160
                $this->anything(),
161
                $this->anything()
162
            )->willReturn($this->getFakeRawSolrResponse());
163
164
        $index = new SolrIndexTest_FakeIndex();
165
        $index->setService($serviceMock);
166
167
        $query = new SearchQuery();
168
        $query->addSearchTerm(
169
            'term',
170
            null,
171
            array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
172
        );
173
        $index->search($query);
174
    }
175
176
    /**
177
     * Test boosting on field schema (via queried fields parameter)
178
     */
179
    public function testBoostedField()
180
    {
181
        if (class_exists(Subsite::class)) {
182
            Config::modify()->set(SearchVariantSubsites::class, 'enabled', false);
183
        }
184
185
        /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */
186
        $serviceMock = $this->getMockBuilder(Solr3Service::class)
187
            ->setMethods(['search'])
188
            ->getMock();
189
190
        $serviceMock->expects($this->once())
191
            ->method('search')
192
            ->with(
193
                $this->equalTo('+term'),
194
                $this->anything(),
195
                $this->anything(),
196
                $this->equalTo([
197
                    'qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 '
198
                        . SearchUpdaterTest_Container::class . '_Field2^2.1 _text',
199
                    'fq' => '',
200
                ]),
201
                $this->anything()
202
            )->willReturn($this->getFakeRawSolrResponse());
203
204
        $index = new SolrIndexTest_BoostedIndex();
205
        $index->setService($serviceMock);
206
207
        $query = new SearchQuery();
208
        $query->addSearchTerm('term');
209
        $index->search($query);
210
    }
211
212
    public function testHighlightQueryOnBoost()
213
    {
214
        /** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */
215
        $serviceMock = $this->getMockBuilder(Solr3Service::class)
216
            ->setMethods(['search'])
217
            ->getMock();
218
219
        $serviceMock->expects($this->exactly(2))
220
            ->method('search')
221
            ->withConsecutive(
222
                [
223
                    $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
224
                    $this->anything(),
225
                    $this->anything(),
226
                    $this->logicalNot(
227
                        $this->arrayHasKey('hl.q')
228
                    ),
229
                    $this->anything()
230
                ],
231
                [
232
                    $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
233
                    $this->anything(),
234
                    $this->anything(),
235
                    $this->arrayHasKey('hl.q'),
236
                    $this->anything()
237
                ]
238
            )->willReturn($this->getFakeRawSolrResponse());
239
240
        $index = new SolrIndexTest_FakeIndex();
241
        $index->setService($serviceMock);
242
243
        // Search without highlighting
244
        $query = new SearchQuery();
245
        $query->addSearchTerm(
246
            'term',
247
            null,
248
            array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
249
        );
250
        $index->search($query);
251
252
        // Search with highlighting
253
        $query = new SearchQuery();
254
        $query->addSearchTerm(
255
            'term',
256
            null,
257
            array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
258
        );
259
        $index->search($query, -1, -1, array('hl' => true));
260
    }
261
262
    public function testIndexExcludesNullValues()
263
    {
264
        /** @var Solr3Service|ObjectProphecy $serviceMock */
265
        $serviceMock = $this->createMock(Solr3Service::class);
266
        $index = new SolrIndexTest_FakeIndex();
267
        $index->setService($serviceMock);
268
        $obj = new SearchUpdaterTest_Container();
269
270
        $obj->Field1 = 'Field1 val';
271
        $obj->Field2 = null;
272
        $obj->MyDate = null;
273
        $docs = $index->add($obj);
274
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field1');
275
        $this->assertEquals('Field1 val', $value['value'], 'Writes non-NULL string fields');
276
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field2');
277
        $this->assertFalse($value, 'Ignores string fields if they are NULL');
278
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate');
279
        $this->assertFalse($value, 'Ignores date fields if they are NULL');
280
281
        $obj->MyDate = '2010-12-30';
282
        $docs = $index->add($obj);
283
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate');
284
        $this->assertEquals('2010-12-30T00:00:00Z', $value['value'], 'Writes non-NULL dates');
285
    }
286
287
    public function testAddFieldExtraOptions()
288
    {
289
        Injector::inst()->get(Kernel::class)->setEnvironment('live');
290
291
        $index = new SolrIndexTest_FakeIndex();
292
293
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
294
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
295
        $this->assertEquals((string)$defField1[0]['stored'], 'false');
296
297
        $index->addFilterField('Field1', null, array('stored' => 'true'));
298
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
299
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
300
        $this->assertEquals((string)$defField1[0]['stored'], 'true');
301
    }
302
303
    public function testAddAnalyzer()
304
    {
305
        $index = new SolrIndexTest_FakeIndex();
306
307
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
308
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
309
        $analyzers = $defField1[0]->analyzer;
310
        $this->assertFalse((bool)$analyzers);
311
312
        $index->addAnalyzer('Field1', 'charFilter', array('class' => 'solr.HTMLStripCharFilterFactory'));
313
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
314
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
315
        $analyzers = $defField1[0]->analyzer;
316
        $this->assertTrue((bool)$analyzers);
317
        $this->assertEquals('solr.HTMLStripCharFilterFactory', $analyzers[0]->charFilter[0]['class']);
318
    }
319
320
    public function testAddCopyField()
321
    {
322
        $index = new SolrIndexTest_FakeIndex();
323
        $index->addCopyField('sourceField', 'destField');
324
325
        $defs = simplexml_load_string('<fields>' . $index->getCopyFieldDefinitions() . '</fields>');
326
        $copyField = $defs->xpath('copyField');
327
328
        $this->assertEquals('sourceField', $copyField[0]['source']);
329
        $this->assertEquals('destField', $copyField[0]['dest']);
330
    }
331
332
    /**
333
     * Tests the setting of the 'stored' flag
334
     */
335
    public function testStoredFields()
336
    {
337
        // Test two fields
338
        $index = new SolrIndexTest_FakeIndex2();
339
        $index->addStoredField('Field1');
340
        $index->addFulltextField('Field2');
341
        $schema = $index->getFieldDefinitions();
342
        $this->assertContains(
343
            "<field name='" . SearchUpdaterTest_Container::class . "_Field1' type='text' indexed='true' stored='true'",
344
            $schema
345
        );
346
        $this->assertContains(
347
            "<field name='" . SearchUpdaterTest_Container::class . "_Field2' type='text' indexed='true' stored='false'",
348
            $schema
349
        );
350
351
        // Test with addAllFulltextFields
352
        $index2 = new SolrIndexTest_FakeIndex2();
353
        $index2->addAllFulltextFields();
354
        $index2->addStoredField('Field2');
355
        $schema2 = $index2->getFieldDefinitions();
356
        $this->assertContains(
357
            "<field name='" . SearchUpdaterTest_Container::class . "_Field1' type='text' indexed='true' stored='false'",
358
            $schema2
359
        );
360
        $this->assertContains(
361
            "<field name='" . SearchUpdaterTest_Container::class . "_Field2' type='text' indexed='true' stored='true'",
362
            $schema2
363
        );
364
    }
365
366
    public function testSanitiseClassName()
367
    {
368
        $index = new SolrIndexTest_FakeIndex2;
369
370
        $this->assertSame(
371
            'SilverStripe\\\\FullTextSearch\\\\Tests\\\\SolrIndexTest',
372
            $index->sanitiseClassName(static::class)
373
        );
374
375
        $this->assertSame(
376
            'SilverStripe-FullTextSearch-Tests-SolrIndexTest',
377
            $index->sanitiseClassName(static::class, '-')
378
        );
379
    }
380
381
    public function testGetIndexName()
382
    {
383
        $index = new SolrIndexTest_FakeIndex2;
384
        $this->assertSame(
385
            'SilverStripe-FullTextSearch-Tests-SolrIndexTest-SolrIndexTest_FakeIndex2',
386
            $index->getIndexName()
387
        );
388
    }
389
390
    public function testGetIndexNameWithPrefixAndSuffixFromEnvironment()
391
    {
392
        $index = new SolrIndexTest_FakeIndex2;
393
394
        Environment::putEnv('SS_SOLR_INDEX_PREFIX="foo_"');
395
        Environment::putEnv('SS_SOLR_INDEX_SUFFIX="_bar"');
396
397
        $this->assertSame(
398
            'foo_SilverStripe-FullTextSearch-Tests-SolrIndexTest-SolrIndexTest_FakeIndex2_bar',
399
            $index->getIndexName()
400
        );
401
    }
402
403
    /**
404
     * Test that ShowInSearch and getShowInSearch() exclude DataObjects from being added to the index
405
     *
406
     * Note: this code path that really being tested here is SearchUpdateProcessor->prepareIndexes()
407
     * This code path is used for 'inlet' filtering on CMS->save()
408
     * The results of this will show-up in SolrIndex->_addAs()
409
     */
410
    public function testShowInSearch()
411
    {
412
        $defaultMode = Versioned::get_reading_mode();
413
        Versioned::set_reading_mode('Stage.' . Versioned::DRAFT);
414
415
        $serviceMock = $this->getMockBuilder(Solr4Service::class)
416
            ->setMethods(['addDocument', 'deleteById'])
417
            ->getMock();
418
419
        $index = new SolrIndexTest_ShowInSearchIndex();
420
        $index->setService($serviceMock);
421
        FullTextSearch::force_index_list($index);
422
423
        // will get added
424
        $pageA = new Page();
425
        $pageA->Title = 'Test Page true';
426
        $pageA->ShowInSearch = true;
427
        $pageA->write();
428
429
        // will get filtered out
430
        $page = new Page();
431
        $page->Title = 'Test Page false';
432
        $page->ShowInSearch = false;
433
        $page->write();
434
435
        // will get added
436
        $fileA = new File();
437
        $fileA->Title = 'Test File true';
438
        $fileA->ShowInSearch = true;
0 ignored issues
show
Documentation Bug introduced by
The property $ShowInSearch was declared of type string, but true is of type true. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
439
        $fileA->write();
440
441
        // will get filtered out
442
        $file = new File();
443
        $file->Title = 'Test File false';
444
        $file->ShowInSearch = false;
0 ignored issues
show
Documentation Bug introduced by
The property $ShowInSearch was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
445
        $file->write();
446
447
        // will get added
448
        $objOneA = new SolrIndexTest_MyDataObjectOne();
449
        $objOneA->Title = 'Test MyDataObjectOne true';
450
        $objOneA->ShowInSearch = true;
0 ignored issues
show
Bug Best Practice introduced by
The property ShowInSearch does not exist on SilverStripe\FullTextSea...dexTest_MyDataObjectOne. Since you implemented __set, consider adding a @property annotation.
Loading history...
451
        $objOneA->write();
452
453
        // will get filtered out
454
        $objOne = new SolrIndexTest_MyDataObjectOne();
455
        $objOne->Title = 'Test MyDataObjectOne false';
456
        $objOne->ShowInSearch = false;
457
        $objOne->write();
458
459
        // will get added
460
        // this class has a getShowInSearch() == true, which will override $mypage->ShowInSearch = false
461
        $objTwoA = new SolrIndexTest_MyDataObjectTwo();
462
        $objTwoA->Title = 'Test MyDataObjectTwo false';
463
        $objTwoA->ShowInSearch = false;
0 ignored issues
show
Bug Best Practice introduced by
The property ShowInSearch does not exist on SilverStripe\FullTextSea...dexTest_MyDataObjectTwo. Since you implemented __set, consider adding a @property annotation.
Loading history...
464
        $objTwoA->write();
465
466
        // will get added
467
        // this class has a getShowInSearch() == true, which will override $mypage->ShowInSearch = false
468
        $myPageA = new SolrIndexTest_MyPage();
469
        $myPageA->Title = 'Test MyPage false';
470
        $myPageA->ShowInSearch = false;
471
        $myPageA->write();
472
473
        $callback = function (Apache_Solr_Document $doc) use ($pageA, $myPageA, $fileA, $objOneA, $objTwoA): bool {
474
            $validKeys = [
475
                Page::class . $pageA->ID,
476
                SolrIndexTest_MyPage::class . $myPageA->ID,
477
                File::class . $fileA->ID,
478
                SolrIndexTest_MyDataObjectOne::class . $objOneA->ID,
479
                SolrIndexTest_MyDataObjectTwo::class . $objTwoA->ID
480
            ];
481
            return in_array($this->createSolrDocKey($doc), $validKeys);
482
        };
483
484
        $serviceMock
485
            ->expects($this->exactly(5))
486
            ->method('addDocument')
487
            ->withConsecutive(
488
                [$this->callback($callback)],
489
                [$this->callback($callback)],
490
                [$this->callback($callback)],
491
                [$this->callback($callback)],
492
                [$this->callback($callback)]
493
            );
494
495
        // This is what actually triggers all the solr stuff
496
        SearchUpdater::flush_dirty_indexes();
497
498
        // delete a solr doc by setting ShowInSearch to false
499
        $pageA->ShowInSearch = false;
500
        $pageA->write();
501
502
        $serviceMock
503
            ->expects($this->exactly(1))
504
            ->method('deleteById')
505
            ->withConsecutive(
506
                [$this->callback(function (string $docID) use ($pageA): bool {
507
                    return strpos($docID, $pageA->ID . '-' . SiteTree::class) !== false;
508
                })]
509
            );
510
511
        IndexableService::singleton()->clearCache();
512
        SearchUpdater::flush_dirty_indexes();
513
514
        Versioned::set_reading_mode($defaultMode);
515
    }
516
517
    protected function createSolrDocKey(Apache_Solr_Document $doc)
518
    {
519
        return $doc->getField('ClassName')['value'] . $doc->getField('ID')['value'];
520
    }
521
522
    protected function getFakeRawSolrResponse()
523
    {
524
        return new \Apache_Solr_Response(
525
            new \Apache_Solr_HttpTransport_Response(
526
                null,
527
                null,
528
                '{}'
529
            )
530
        );
531
    }
532
}
533