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
|
|||
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 |
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.