|
34 | 34 | import static org.mockito.Mockito.never; |
35 | 35 | import static org.mockito.Mockito.times; |
36 | 36 | import static org.mockito.Mockito.verify; |
| 37 | +import static org.mockito.Mockito.verifyNoInteractions; |
37 | 38 | import static org.mockito.Mockito.when; |
38 | 39 |
|
39 | 40 | import java.lang.reflect.InvocationTargetException; |
@@ -385,6 +386,66 @@ void processBatchWritesEntitiesAndRecordsReaderFailures() throws Exception { |
385 | 386 | assertEquals(statsTracker, contextCaptor.getValue().get(BulkSink.STATS_TRACKER_CONTEXT_KEY)); |
386 | 387 | } |
387 | 388 |
|
| 389 | + @Test |
| 390 | + void processBatchExtractsIdFromEntityInterfaceForReaderFailure() throws Exception { |
| 391 | + IndexingFailureRecorder failureRecorder = mock(IndexingFailureRecorder.class); |
| 392 | + StageStatsTracker statsTracker = mock(StageStatsTracker.class); |
| 393 | + PartitionWorker batchWorker = |
| 394 | + new PartitionWorker(coordinator, bulkSink, BATCH_SIZE, null, false, failureRecorder); |
| 395 | + |
| 396 | + UUID errorEntityId = UUID.randomUUID(); |
| 397 | + EntityInterface failingEntity = mock(EntityInterface.class); |
| 398 | + when(failingEntity.getId()).thenReturn(errorEntityId); |
| 399 | + EntityInterface successEntity = mock(EntityInterface.class); |
| 400 | + |
| 401 | + ResultList<EntityInterface> resultList = new ResultList<>(); |
| 402 | + resultList.setData(List.of(successEntity)); |
| 403 | + resultList.setErrors( |
| 404 | + List.of(new EntityError().withEntity(failingEntity).withMessage("reader failure"))); |
| 405 | + resultList.setWarningsCount(0); |
| 406 | + resultList.setPaging(new Paging().withAfter("next-cursor")); |
| 407 | + |
| 408 | + try (MockedConstruction<PaginatedEntitiesSource> ignored = |
| 409 | + mockConstruction( |
| 410 | + PaginatedEntitiesSource.class, |
| 411 | + (mock, context) -> doReturn(resultList).when(mock).readNextKeyset("cursor-1"))) { |
| 412 | + |
| 413 | + invokeProcessBatch(batchWorker, "table", "cursor-1", 2, statsTracker); |
| 414 | + } |
| 415 | + |
| 416 | + verify(failureRecorder) |
| 417 | + .recordReaderEntityFailure("table", errorEntityId.toString(), null, "reader failure"); |
| 418 | + } |
| 419 | + |
| 420 | + @Test |
| 421 | + void processBatchSkipsReaderFailureWhenEntityInterfaceHasNullId() throws Exception { |
| 422 | + IndexingFailureRecorder failureRecorder = mock(IndexingFailureRecorder.class); |
| 423 | + StageStatsTracker statsTracker = mock(StageStatsTracker.class); |
| 424 | + PartitionWorker batchWorker = |
| 425 | + new PartitionWorker(coordinator, bulkSink, BATCH_SIZE, null, false, failureRecorder); |
| 426 | + |
| 427 | + EntityInterface failingEntity = mock(EntityInterface.class); |
| 428 | + when(failingEntity.getId()).thenReturn(null); |
| 429 | + EntityInterface successEntity = mock(EntityInterface.class); |
| 430 | + |
| 431 | + ResultList<EntityInterface> resultList = new ResultList<>(); |
| 432 | + resultList.setData(List.of(successEntity)); |
| 433 | + resultList.setErrors( |
| 434 | + List.of(new EntityError().withEntity(failingEntity).withMessage("reader failure"))); |
| 435 | + resultList.setWarningsCount(0); |
| 436 | + resultList.setPaging(new Paging().withAfter("next-cursor")); |
| 437 | + |
| 438 | + try (MockedConstruction<PaginatedEntitiesSource> ignored = |
| 439 | + mockConstruction( |
| 440 | + PaginatedEntitiesSource.class, |
| 441 | + (mock, context) -> doReturn(resultList).when(mock).readNextKeyset("cursor-1"))) { |
| 442 | + |
| 443 | + invokeProcessBatch(batchWorker, "table", "cursor-1", 2, statsTracker); |
| 444 | + } |
| 445 | + |
| 446 | + verifyNoInteractions(failureRecorder); |
| 447 | + } |
| 448 | + |
388 | 449 | @Test |
389 | 450 | void processBatchWrapsSinkFailuresAsSearchIndexException() throws Exception { |
390 | 451 | PartitionWorker batchWorker = |
|
0 commit comments