13
13
use Algolia \AlgoliaSearch \Model \IndicesConfigurator ;
14
14
use Algolia \AlgoliaSearch \Registry \ReplicaState ;
15
15
use Algolia \AlgoliaSearch \Service \IndexNameFetcher ;
16
+ use Algolia \AlgoliaSearch \Service \Product \ReplicaManager ;
16
17
use Algolia \AlgoliaSearch \Service \Product \SortingTransformer ;
17
18
use Algolia \AlgoliaSearch \Service \StoreNameFetcher ;
18
19
use Algolia \AlgoliaSearch \Test \Integration \TestCase ;
19
20
use Algolia \AlgoliaSearch \Validator \VirtualReplicaValidatorFactory ;
21
+ use Magento \Framework \App \State as AppState ;
22
+ use Magento \Framework \Setup \ModuleDataSetupInterface ;
20
23
use Magento \Store \Model \StoreManagerInterface ;
24
+ use PHPUnit \Framework \MockObject \MockObject ;
25
+ use Psr \Log \LoggerInterface ;
21
26
22
27
class ReplicaIndexingTest extends TestCase
23
28
{
@@ -28,6 +33,8 @@ class ReplicaIndexingTest extends TestCase
28
33
29
34
protected ?string $ indexName = null ;
30
35
36
+ protected ?int $ patchRetries = 3 ;
37
+
31
38
protected function setUp (): void
32
39
{
33
40
parent ::setUp ();
@@ -245,7 +252,7 @@ public function testReplicaDelete(): void
245
252
}
246
253
247
254
/**
248
- * Test
255
+ * Test failure to clear index replica setting
249
256
* @magentoConfigFixture current_store algoliasearch_instant/instant/is_instant_enabled 1
250
257
*/
251
258
public function testReplicaDeleteUnreliable (): void
@@ -260,7 +267,7 @@ public function testReplicaDeleteUnreliable(): void
260
267
261
268
$ this ->assertEquals (count ($ sorting ), count ($ replicas ));
262
269
263
- $ this ->getCrippledReplicaManager ()->deleteReplicasFromAlgolia (1 );
270
+ $ this ->getMustPrevalidateMockReplicaManager ()->deleteReplicasFromAlgolia (1 );
264
271
265
272
$ newSettings = $ this ->algoliaHelper ->getSettings ($ primaryIndexName );
266
273
$ this ->assertArrayNotHasKey ('replicas ' , $ newSettings );
@@ -269,6 +276,33 @@ public function testReplicaDeleteUnreliable(): void
269
276
}
270
277
}
271
278
279
+ /**
280
+ * @magentoConfigFixture current_store algoliasearch_instant/instant/is_instant_enabled 1
281
+ */
282
+ public function testReplicaRebuildPatch (): void
283
+ {
284
+ $ primaryIndexName = $ this ->indexName ;
285
+ $ sorting = $ this ->populateReplicas (1 );
286
+ $ currentSettings = $ this ->algoliaHelper ->getSettings ($ primaryIndexName );
287
+ $ this ->assertArrayHasKey ('replicas ' , $ currentSettings );
288
+ $ replicas = $ currentSettings ['replicas ' ];
289
+
290
+ $ this ->assertTrue ($ this ->configHelper ->credentialsAreConfigured ());
291
+
292
+ $ patch = new \Algolia \AlgoliaSearch \Setup \Patch \Data \RebuildReplicasPatch (
293
+ $ this ->objectManager ->get (ModuleDataSetupInterface::class),
294
+ $ this ->objectManager ->get (StoreManagerInterface::class),
295
+ $ this ->getTroublesomePatchReplicaManager (),
296
+ $ this ->objectManager ->get (ProductHelper::class),
297
+ $ this ->objectManager ->get (AppState::class),
298
+ $ this ->objectManager ->get (ReplicaState::class),
299
+ $ this ->configHelper ,
300
+ $ this ->objectManager ->get (LoggerInterface::class)
301
+ );
302
+
303
+ $ patch ->apply ();
304
+ }
305
+
272
306
protected function extractIndexFromReplicaSetting (string $ setting ): string {
273
307
return preg_replace ('/^virtual\((.*)\)$/ ' , '$1 ' , $ setting );
274
308
}
@@ -279,14 +313,56 @@ protected function extractIndexFromReplicaSetting(string $setting): string {
279
313
* This aims to reproduce this potential scenario by not disassociating the replica
280
314
*
281
315
*/
282
- protected function getCrippledReplicaManager (): ReplicaManagerInterface
316
+ protected function getMustPrevalidateMockReplicaManager (): ReplicaManagerInterface
283
317
{
284
- $ mockedClass = \Algolia \AlgoliaSearch \Service \Product \ReplicaManager::class;
285
318
$ mockedMethod = 'clearReplicasSettingInAlgolia ' ;
319
+
320
+ $ mock = $ this ->getMockReplicaManager ([
321
+ $ mockedMethod => function (...$ params ) {
322
+ //DO NOTHING
323
+ return ;
324
+ }
325
+ ]);
326
+ $ mock ->expects ($ this ->once ())->method ($ mockedMethod );
327
+ return $ mock ;
328
+ }
329
+
330
+ /**
331
+ * This mock is to recreate the scenario where a patch tries to apply up to 3 times but the replicas
332
+ * are never detached which throws a replica delete error until the last attempt which should succeed
333
+ */
334
+ protected function getTroublesomePatchReplicaManager (): ReplicaManager
335
+ {
336
+ $ mock = $ this ->getMockReplicaManager ([
337
+ 'clearReplicasSettingInAlgolia ' => null ,
338
+ 'deleteReplicas ' => null
339
+ ]);
340
+ $ mock
341
+ ->expects ($ this ->exactly ($ this ->patchRetries ))
342
+ ->method ('clearReplicasSettingInAlgolia ' )
343
+ ->willReturnCallback (function (...$ params ) use ($ mock ) {
344
+ if (--$ this ->patchRetries ) return ;
345
+ $ originalMethod = new \ReflectionMethod (ReplicaManager::class, 'clearReplicasSettingInAlgolia ' );
346
+ $ originalMethod ->invoke ($ mock , ...$ params );
347
+ });
348
+ $ mock
349
+ ->expects ($ this ->any ())
350
+ ->method ('deleteReplicas ' )
351
+ ->willReturnCallback (function (array $ replicasToDelete , ...$ params ) use ($ mock ) {
352
+ $ originalMethod = new \ReflectionMethod (ReplicaManager::class, 'deleteReplicas ' );
353
+ $ originalMethod ->invoke ($ mock , $ replicasToDelete , false , false );
354
+ });
355
+
356
+ return $ mock ;
357
+ }
358
+
359
+ protected function getMockReplicaManager ($ mockedMethods = array ()): MockObject & ReplicaManager
360
+ {
361
+ $ mockedClass = ReplicaManager::class;
286
362
$ mockedReplicaManager = $ this ->getMockBuilder ($ mockedClass )
287
363
->setConstructorArgs ([
288
- $ this ->objectManager -> get (ConfigHelper::class) ,
289
- $ this ->objectManager -> get (AlgoliaHelper::class) ,
364
+ $ this ->configHelper ,
365
+ $ this ->algoliaHelper ,
290
366
$ this ->objectManager ->get (ReplicaState::class),
291
367
$ this ->objectManager ->get (VirtualReplicaValidatorFactory::class),
292
368
$ this ->objectManager ->get (IndexNameFetcher::class),
@@ -295,23 +371,16 @@ protected function getCrippledReplicaManager(): ReplicaManagerInterface
295
371
$ this ->objectManager ->get (StoreManagerInterface::class),
296
372
$ this ->objectManager ->get (Logger::class)
297
373
])
298
- ->onlyMethods ([ $ mockedMethod ] )
374
+ ->onlyMethods (array_keys ( $ mockedMethods ) )
299
375
->getMock ();
300
- $ mockedReplicaManager
301
- ->expects ($ this ->once ())
302
- ->method ($ mockedMethod )
303
- ->willReturnCallback (
304
- function (...$ params )
305
- use ($ mockedClass , $ mockedMethod , $ mockedReplicaManager )
306
- {
307
- // DO NOTHING
308
- return ;
309
-
310
- // If aiming to test a throttle on retry invoke after a specified number of failures
311
- //$originalMethod = new \ReflectionMethod($mockedClass, $mockedMethod);
312
- //return $originalMethod->invoke($mockedReplicaManager, ...$params);
313
- }
314
- );
376
+
377
+ foreach ($ mockedMethods as $ method => $ callback ) {
378
+ if (!$ callback ) continue ;
379
+ $ mockedReplicaManager
380
+ ->method ($ method )
381
+ ->willReturnCallback ($ callback );
382
+ }
383
+
315
384
return $ mockedReplicaManager ;
316
385
}
317
386
0 commit comments