From e0195a42249d1c8ee843a42a017b59ba4eb77f3f Mon Sep 17 00:00:00 2001 From: Viacheslav Kolesnyk <94473337+viacheslavkol@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:03:45 +0100 Subject: [PATCH] feat(reindex) Implement endpoint to run merge reindex stage only for failed ranges (#721) * feat(reindex): Extend range tables with the status column - add status, failCause columns to merge/upload range tables - implement status population logic Closes: MSEARCH-870 --- NEWS.md | 3 +- descriptors/ModuleDescriptor-template.json | 22 ++++++- .../controller/IndexManagementController.java | 6 ++ .../ReindexMergeRangeIndexService.java | 4 ++ .../service/reindex/ReindexService.java | 39 +++++++++++-- .../service/reindex/ReindexStatusService.java | 6 ++ .../reindex/jdbc/MergeRangeRepository.java | 8 +++ .../reindex/jdbc/ReindexStatusRepository.java | 11 ++++ .../resources/swagger.api/mod-search.yaml | 3 + ...reindex-instance-records-merge-failed.yaml | 15 +++++ .../IndexManagementControllerTest.java | 20 +++++-- .../ReindexMergeRangeIndexServiceTest.java | 9 +++ .../service/reindex/ReindexServiceTest.java | 58 +++++++++++++++++++ .../reindex/ReindexStatusServiceTest.java | 14 +++++ .../jdbc/MergeRangeRepositoriesIT.java | 23 ++++++-- .../jdbc/ReindexStatusRepositoryIT.java | 21 ++++++- .../jdbc/UploadRangeRepositoriesIT.java | 6 +- .../search/support/base/ApiEndpoints.java | 4 ++ .../resources/sql/populate-merge-ranges.sql | 10 ++-- 19 files changed, 256 insertions(+), 26 deletions(-) create mode 100644 src/main/resources/swagger.api/paths/reindex-instance-records/reindex-instance-records-merge-failed.yaml diff --git a/NEWS.md b/NEWS.md index 8f36a91b4..2d034a3a2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ * Description ([ISSUE](https://folio-org.atlassian.net/browse/ISSUE)) ### New APIs versions -* Provides `API_NAME vX.Y` +* Provides `indices v1.1` * Requires `API_NAME vX.Y` ### Features @@ -11,6 +11,7 @@ * Update reindex merge failed status only for failed entity type ([MSEARCH-909](https://folio-org.atlassian.net/browse/MSEARCH-909)) * Extend reindex range tables with status, fail_cause columns ([MSEARCH-870](https://folio-org.atlassian.net/browse/MSEARCH-870)) * Implement scheduled indexing for instance sub-resources ([MSEARCH-922](https://folio-org.atlassian.net/browse/MSEARCH-922)) +* Implement endpoint to run merge reindex stage only for failed ranges ([MSEARCH-906](https://folio-org.atlassian.net/browse/MSEARCH-906)) ### Bug fixes * Remove shelving order calculation for local call-number types diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index 283a3caae..8ec685074 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -4,7 +4,7 @@ "provides": [ { "id": "indices", - "version": "1.0", + "version": "1.1", "handlers": [ { "methods": [ @@ -111,6 +111,18 @@ "modulePermissions": [ "user-tenants.collection.get" ] + }, + { + "methods": [ + "POST" + ], + "pathPattern": "/search/index/instance-records/reindex/merge/failed", + "permissionsRequired": [ + "search.index.instance-records.reindex.merge.failed.post" + ], + "modulePermissions": [ + "user-tenants.collection.get" + ] } ] }, @@ -696,6 +708,11 @@ "displayName": "Search - starts inventory instance records reindex upload operation", "description": "Starts inventory instance records reindex upload operation" }, + { + "permissionName": "search.index.instance-records.reindex.merge.failed.post", + "displayName": "Search - starts inventory instance records reindex merge failed operation", + "description": "Starts inventory instance records reindexing for failed merge ranges" + }, { "permissionName": "search.instances.collection.get", "displayName": "Search - searches instances by given query", @@ -896,7 +913,8 @@ "subPermissions": [ "search.index.instance-records.reindex.status.get", "search.index.instance-records.reindex.full.post", - "search.index.instance-records.reindex.upload.post" + "search.index.instance-records.reindex.upload.post", + "search.index.instance-records.reindex.failed.post" ] } diff --git a/src/main/java/org/folio/search/controller/IndexManagementController.java b/src/main/java/org/folio/search/controller/IndexManagementController.java index 146e06fcd..366459522 100644 --- a/src/main/java/org/folio/search/controller/IndexManagementController.java +++ b/src/main/java/org/folio/search/controller/IndexManagementController.java @@ -63,6 +63,12 @@ public ResponseEntity reindexUploadInstanceRecords(String tenantId, Reinde return ResponseEntity.ok().build(); } + @Override + public ResponseEntity reindexFailedMergeRanges(String tenantId) { + reindexService.submitFailedMergeRangesReindex(tenantId); + return ResponseEntity.ok().build(); + } + @Override public ResponseEntity reindexInventoryRecords(String tenantId, ReindexRequest request) { log.info("Attempting to start reindex for inventory [tenant: {}]", tenantId); diff --git a/src/main/java/org/folio/search/service/reindex/ReindexMergeRangeIndexService.java b/src/main/java/org/folio/search/service/reindex/ReindexMergeRangeIndexService.java index dfd60172f..bdb76e253 100644 --- a/src/main/java/org/folio/search/service/reindex/ReindexMergeRangeIndexService.java +++ b/src/main/java/org/folio/search/service/reindex/ReindexMergeRangeIndexService.java @@ -68,6 +68,10 @@ public List fetchMergeRanges(ReindexEntityType entityType) { return repositories.get(entityType).getMergeRanges(); } + public List fetchFailedMergeRanges() { + return repositories.values().iterator().next().getFailedMergeRanges(); + } + public void updateStatus(ReindexEntityType entityType, String rangeId, ReindexRangeStatus status, String failCause) { var repository = repositories.get(entityType); repository.updateRangeStatus(UUID.fromString(rangeId), Timestamp.from(Instant.now()), status, failCause); diff --git a/src/main/java/org/folio/search/service/reindex/ReindexService.java b/src/main/java/org/folio/search/service/reindex/ReindexService.java index cf2ab1e79..761dd0fae 100644 --- a/src/main/java/org/folio/search/service/reindex/ReindexService.java +++ b/src/main/java/org/folio/search/service/reindex/ReindexService.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; +import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.CollectionUtils; @@ -66,7 +67,7 @@ public ReindexService(ConsortiumTenantService consortiumService, public CompletableFuture submitFullReindex(String tenantId, IndexSettings indexSettings) { log.info("submitFullReindex:: for [tenantId: {}]", tenantId); - validateTenant(tenantId); + validateTenant("submitFullReindex", tenantId); reindexCommonService.deleteAllRecords(); statusService.recreateMergeStatusRecords(); @@ -140,6 +141,36 @@ private CompletableFuture submitUploadReindex(String tenantId, return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); } + public CompletableFuture submitFailedMergeRangesReindex(String tenantId) { + log.info("submitFailedMergeRangesReindex:: for [tenantId: {}]", tenantId); + + validateTenant("submitFailedMergeRangesReindex", tenantId); + + var failedRanges = mergeRangeService.fetchFailedMergeRanges(); + if (CollectionUtils.isEmpty(failedRanges)) { + log.info("submitFailedMergeRangesReindex:: no failed ranges found"); + return CompletableFuture.completedFuture(null); + } + + log.info("submitFailedMergeRangesReindex:: for [tenantId: {}, count: {}]", tenantId, failedRanges.size()); + var entityTypes = failedRanges.stream() + .map(MergeRangeEntity::getEntityType) + .collect(Collectors.toSet()); + statusService.updateReindexMergeInProgress(entityTypes); + + var futures = new ArrayList<>(); + for (var rangeEntity : failedRanges) { + var future = CompletableFuture.runAsync(() -> + executionService.executeSystemUserScoped(rangeEntity.getTenantId(), () -> { + inventoryService.publishReindexRecordsRange(rangeEntity); + return null; + }), reindexPublisherExecutor); + futures.add(future); + } + + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + } + private void recreateIndices(String tenantId, List entityTypes, IndexSettings indexSettings) { for (var reindexEntityType : entityTypes) { reindexCommonService.recreateIndex(reindexEntityType, tenantId, indexSettings); @@ -180,7 +211,7 @@ private void publishRecordsRange(String tenantId) { } private void validateUploadReindex(String tenantId, List entityTypes) { - validateTenant(tenantId); + validateTenant("submitUploadReindex", tenantId); var statusesByType = statusService.getStatusesByType(); @@ -207,10 +238,10 @@ private void validateUploadReindex(String tenantId, List enti } } - private void validateTenant(String tenantId) { + private void validateTenant(String operation, String tenantId) { var central = consortiumService.getCentralTenant(tenantId); if (central.isPresent() && !central.get().equals(tenantId)) { - log.info("initFullReindex:: could not be started for consortium member tenant [tenantId: {}]", tenantId); + log.info("{}:: could not be started for consortium member tenant [tenantId: {}]", operation, tenantId); throw RequestValidationException.memberTenantNotAllowedException(tenantId); } } diff --git a/src/main/java/org/folio/search/service/reindex/ReindexStatusService.java b/src/main/java/org/folio/search/service/reindex/ReindexStatusService.java index 7e7dc64c7..e23cb2754 100644 --- a/src/main/java/org/folio/search/service/reindex/ReindexStatusService.java +++ b/src/main/java/org/folio/search/service/reindex/ReindexStatusService.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import lombok.extern.log4j.Log4j2; import org.folio.search.converter.ReindexStatusMapper; @@ -93,6 +94,11 @@ public void updateReindexMergeStarted(ReindexEntityType entityType, int totalMer statusRepository.setMergeReindexStarted(entityType, totalMergeRanges); } + public void updateReindexMergeInProgress(Set entityTypes) { + log.info("updateReindexMergeInProgress:: for [entityTypes: {}]", entityTypes); + statusRepository.setMergeInProgress(entityTypes); + } + public void updateReindexUploadStarted(ReindexEntityType entityType, int totalUploadRanges) { log.info("updateReindexUploadStarted:: for [entityType: {}, totalMergeRanges: {}]", entityType, totalUploadRanges); statusRepository.setUploadReindexStarted(entityType, totalUploadRanges); diff --git a/src/main/java/org/folio/search/service/reindex/jdbc/MergeRangeRepository.java b/src/main/java/org/folio/search/service/reindex/jdbc/MergeRangeRepository.java index 150ac6a95..c6f7fee82 100644 --- a/src/main/java/org/folio/search/service/reindex/jdbc/MergeRangeRepository.java +++ b/src/main/java/org/folio/search/service/reindex/jdbc/MergeRangeRepository.java @@ -35,6 +35,8 @@ public abstract class MergeRangeRepository extends ReindexJdbcRepository { private static final String SELECT_MERGE_RANGES_BY_ENTITY_TYPE = "SELECT * FROM %s WHERE entity_type = ?;"; + private static final String SELECT_FAILED_MERGE_RANGES = "SELECT * FROM %s WHERE status = 'FAIL';"; + protected MergeRangeRepository(JdbcTemplate jdbcTemplate, JsonConverter jsonConverter, FolioExecutionContext context) { @@ -62,6 +64,12 @@ public List getMergeRanges() { return jdbcTemplate.query(sql, mergeRangeEntityRowMapper(), entityType().getType()); } + public List getFailedMergeRanges() { + var fullTableName = getFullTableName(context, MERGE_RANGE_TABLE); + var sql = SELECT_FAILED_MERGE_RANGES.formatted(fullTableName); + return jdbcTemplate.query(sql, mergeRangeEntityRowMapper()); + } + public void truncateMergeRanges() { JdbcUtils.truncateTable(MERGE_RANGE_TABLE, jdbcTemplate, context); } diff --git a/src/main/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepository.java b/src/main/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepository.java index ee4486db5..032716606 100644 --- a/src/main/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepository.java +++ b/src/main/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepository.java @@ -15,6 +15,7 @@ import java.sql.Timestamp; import java.time.Instant; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.folio.search.model.reindex.ReindexStatusEntity; @@ -124,6 +125,16 @@ public void setMergeReindexFailed(List entityTypes) { jdbcTemplate.update(sql, ReindexStatus.MERGE_FAILED.name(), Timestamp.from(Instant.now())); } + public void setMergeInProgress(Set entityTypes) { + var inTypes = entityTypes.stream() + .map(entityType -> "'%s'".formatted(entityType.name())) + .collect(Collectors.joining(",")); + var fullTableName = getFullTableName(context, REINDEX_STATUS_TABLE); + var sql = UPDATE_FOR_ENTITIES_SQL.formatted(fullTableName, STATUS_COLUMN + " = ?", inTypes); + + jdbcTemplate.update(sql, ReindexStatus.MERGE_IN_PROGRESS.name()); + } + public void saveReindexStatusRecords(List statusRecords) { var fullTableName = getFullTableName(context, REINDEX_STATUS_TABLE); jdbcTemplate.batchUpdate(INSERT_REINDEX_STATUS_SQL.formatted(fullTableName), statusRecords, 10, diff --git a/src/main/resources/swagger.api/mod-search.yaml b/src/main/resources/swagger.api/mod-search.yaml index 913d8cdf3..ce70edfd2 100644 --- a/src/main/resources/swagger.api/mod-search.yaml +++ b/src/main/resources/swagger.api/mod-search.yaml @@ -121,6 +121,9 @@ paths: /search/index/instance-records/reindex/upload: $ref: 'paths/reindex-instance-records/reindex-instance-records-upload.yaml' + /search/index/instance-records/reindex/merge/failed: + $ref: 'paths/reindex-instance-records/reindex-instance-records-merge-failed.yaml' + /search/config/languages: $ref: 'paths/search-config/search-config-languages.yaml' diff --git a/src/main/resources/swagger.api/paths/reindex-instance-records/reindex-instance-records-merge-failed.yaml b/src/main/resources/swagger.api/paths/reindex-instance-records/reindex-instance-records-merge-failed.yaml new file mode 100644 index 000000000..9dca0cf59 --- /dev/null +++ b/src/main/resources/swagger.api/paths/reindex-instance-records/reindex-instance-records-merge-failed.yaml @@ -0,0 +1,15 @@ +post: + operationId: reindexFailedMergeRanges + summary: Failed Merge Ranges Re-Index + description: Initiates reindexing of failed merge ranges for inventory instance records + tags: + - index-management + parameters: + - $ref: '../../parameters/x-okapi-tenant-header.yaml' + responses: + '200': + description: Reindexing of failed merge ranges has been started + '400': + $ref: '../../responses/badRequestResponse.yaml' + '500': + $ref: '../../responses/internalServerErrorResponse.yaml' diff --git a/src/test/java/org/folio/search/controller/IndexManagementControllerTest.java b/src/test/java/org/folio/search/controller/IndexManagementControllerTest.java index e9e92b18d..5e5c4dc63 100644 --- a/src/test/java/org/folio/search/controller/IndexManagementControllerTest.java +++ b/src/test/java/org/folio/search/controller/IndexManagementControllerTest.java @@ -1,6 +1,7 @@ package org.folio.search.controller; import static org.folio.search.support.base.ApiEndpoints.createIndicesPath; +import static org.folio.search.support.base.ApiEndpoints.reindexFailedPath; import static org.folio.search.support.base.ApiEndpoints.reindexFullPath; import static org.folio.search.support.base.ApiEndpoints.reindexInstanceRecordsStatus; import static org.folio.search.support.base.ApiEndpoints.reindexUploadPath; @@ -55,8 +56,8 @@ import org.opensearch.core.index.Index; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; @@ -71,13 +72,13 @@ class IndexManagementControllerTest { @Autowired private MockMvc mockMvc; - @MockBean + @MockitoBean private IndexService indexService; - @MockBean + @MockitoBean private ResourceService resourceService; - @MockBean + @MockitoBean private ReindexService reindexService; - @MockBean + @MockitoBean private ReindexStatusService reindexStatusService; @Test @@ -121,6 +122,15 @@ void submitReindexUpload_positive_withSettings() throws Exception { .andExpect(status().isOk()); } + @Test + void submitReindexMergeFailed_positive() throws Exception { + when(reindexService.submitFailedMergeRangesReindex(TENANT_ID)).thenReturn(new CompletableFuture<>()); + + mockMvc.perform(post(reindexFailedPath()) + .header(XOkapiHeaders.TENANT, TENANT_ID)) + .andExpect(status().isOk()); + } + @Test void createIndex_positive() throws Exception { when(indexService.createIndex(RESOURCE, TENANT_ID)) diff --git a/src/test/java/org/folio/search/service/reindex/ReindexMergeRangeIndexServiceTest.java b/src/test/java/org/folio/search/service/reindex/ReindexMergeRangeIndexServiceTest.java index 0febc507a..612bb4f50 100644 --- a/src/test/java/org/folio/search/service/reindex/ReindexMergeRangeIndexServiceTest.java +++ b/src/test/java/org/folio/search/service/reindex/ReindexMergeRangeIndexServiceTest.java @@ -133,4 +133,13 @@ void saveEntities(ReindexRecordsEvent.ReindexRecordType recordType) { verifyNoInteractions(instanceChildrenResourceService); } } + + @Test + void fetchFailedMergeRanges() { + // act + service.fetchFailedMergeRanges(); + + // assert + verify(repositoryMap.values().iterator().next()).getFailedMergeRanges(); + } } diff --git a/src/test/java/org/folio/search/service/reindex/ReindexServiceTest.java b/src/test/java/org/folio/search/service/reindex/ReindexServiceTest.java index a79c03466..906cceca6 100644 --- a/src/test/java/org/folio/search/service/reindex/ReindexServiceTest.java +++ b/src/test/java/org/folio/search/service/reindex/ReindexServiceTest.java @@ -1,5 +1,6 @@ package org.folio.search.service.reindex; +import static java.util.Collections.emptyList; import static org.folio.search.exception.RequestValidationException.REQUEST_NOT_ALLOWED_MSG; import static org.folio.search.model.types.ReindexEntityType.HOLDINGS; import static org.folio.search.model.types.ReindexEntityType.INSTANCE; @@ -14,6 +15,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -23,9 +25,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; +import lombok.SneakyThrows; import org.apache.commons.lang3.ThreadUtils; import org.folio.search.converter.ReindexEntityTypeMapper; import org.folio.search.domain.dto.IndexSettings; @@ -238,4 +242,58 @@ void submitUploadReindex_negative_failedToPrepareUploadRangesAndSendThem() { verify(statusService).updateReindexUploadFailed(INSTANCE); } + + @Test + void submitFailedMergeRangesReindex_negative_shouldFailForEcsMemberTenant() { + when(consortiumService.getCentralTenant(TENANT_ID)).thenReturn(Optional.of("central")); + + assertThrows(RequestValidationException.class, () -> reindexService.submitFailedMergeRangesReindex(TENANT_ID), + REQUEST_NOT_ALLOWED_MSG); + } + + @Test + @SneakyThrows + void submitFailedMergeRangesReindex_negative_noFailedRanges() { + when(consortiumService.getCentralTenant(TENANT_ID)).thenReturn(Optional.of(TENANT_ID)); + when(mergeRangeService.fetchFailedMergeRanges()).thenReturn(emptyList()); + + reindexService.submitFailedMergeRangesReindex(TENANT_ID).get(); + + verifyNoInteractions(statusService); + verifyNoInteractions(inventoryService); + } + + @Test + @SneakyThrows + void submitFailedMergeRangesReindex_positive() { + var failedRanges = List.of( + createMergeRangeEntity(ReindexEntityType.ITEM), + createMergeRangeEntity(ReindexEntityType.HOLDINGS), + createMergeRangeEntity(ReindexEntityType.HOLDINGS), + createMergeRangeEntity(ReindexEntityType.INSTANCE), + createMergeRangeEntity(ReindexEntityType.INSTANCE), + createMergeRangeEntity(ReindexEntityType.INSTANCE)); + + when(consortiumService.getCentralTenant(TENANT_ID)).thenReturn(Optional.of(TENANT_ID)); + when(mergeRangeService.fetchFailedMergeRanges()).thenReturn(failedRanges); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(reindexExecutor).execute(any()); + doAnswer(invocation -> ((Callable) invocation.getArgument(1)).call()) + .when(executionService).executeSystemUserScoped(any(), any()); + + reindexService.submitFailedMergeRangesReindex(TENANT_ID).get(); + + verify(statusService).updateReindexMergeInProgress( + Set.of(ReindexEntityType.ITEM, ReindexEntityType.HOLDINGS, ReindexEntityType.INSTANCE)); + failedRanges.forEach(range -> + verify(inventoryService).publishReindexRecordsRange(range)); + } + + private MergeRangeEntity createMergeRangeEntity(ReindexEntityType entityType) { + var id = UUID.randomUUID(); + return new MergeRangeEntity(id, entityType, TENANT_ID, id.toString(), id.toString(), + Timestamp.from(Instant.now()), null, null); + } } diff --git a/src/test/java/org/folio/search/service/reindex/ReindexStatusServiceTest.java b/src/test/java/org/folio/search/service/reindex/ReindexStatusServiceTest.java index e8ef68f36..cddca3f3b 100644 --- a/src/test/java/org/folio/search/service/reindex/ReindexStatusServiceTest.java +++ b/src/test/java/org/folio/search/service/reindex/ReindexStatusServiceTest.java @@ -3,6 +3,7 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.folio.search.exception.RequestValidationException.REQUEST_NOT_ALLOWED_MSG; +import static org.folio.search.model.types.ReindexEntityType.HOLDINGS; import static org.folio.search.model.types.ReindexEntityType.INSTANCE; import static org.folio.search.utils.TestConstants.TENANT_ID; import static org.mockito.Mockito.verify; @@ -10,6 +11,7 @@ import static org.mockito.Mockito.when; import java.util.List; +import java.util.Set; import org.assertj.core.api.Condition; import org.folio.search.converter.ReindexStatusMapper; import org.folio.search.domain.dto.ReindexStatusItem; @@ -162,4 +164,16 @@ void shouldRecreateMergeReindexStatusEntities() { .are(new Condition<>(statusEntity -> ReindexStatus.MERGE_IN_PROGRESS.equals(statusEntity.getStatus()), "merge status entity")); } + + @Test + void updateReindexMergeInProgress() { + // given + var entityTypes = Set.of(INSTANCE, HOLDINGS); + + // act + service.updateReindexMergeInProgress(entityTypes); + + // assert + verify(statusRepository).setMergeInProgress(entityTypes); + } } diff --git a/src/test/java/org/folio/search/service/reindex/jdbc/MergeRangeRepositoriesIT.java b/src/test/java/org/folio/search/service/reindex/jdbc/MergeRangeRepositoriesIT.java index 02ada1612..4405ae67c 100644 --- a/src/test/java/org/folio/search/service/reindex/jdbc/MergeRangeRepositoriesIT.java +++ b/src/test/java/org/folio/search/service/reindex/jdbc/MergeRangeRepositoriesIT.java @@ -30,8 +30,8 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.boot.test.autoconfigure.json.AutoConfigureJson; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.jdbc.Sql; @IntegrationTest @@ -42,9 +42,9 @@ class MergeRangeRepositoriesIT { private @Autowired JdbcTemplate jdbcTemplate; - private @MockBean FolioExecutionContext context; - private @MockBean ConsortiumTenantProvider tenantProvider; - private @MockBean ReindexConfigurationProperties reindexConfig; + private @MockitoBean FolioExecutionContext context; + private @MockitoBean ConsortiumTenantProvider tenantProvider; + private @MockitoBean ReindexConfigurationProperties reindexConfig; private HoldingRepository holdingRepository; private ItemRepository itemRepository; private MergeInstanceRepository instanceRepository; @@ -138,6 +138,21 @@ void saveMergeRanges_savesRanges_whenProvidedListOfMergeRangeEntities() { .isEqualTo(instanceRanges); } + @Test + @Sql("/sql/populate-merge-ranges.sql") + void getFailedMergeRanges() { + // act + var failedRanges = instanceRepository.getFailedMergeRanges(); + + // assert + assertThat(failedRanges) + .hasSize(3) + .anyMatch(range -> range.getEntityType() == ReindexEntityType.INSTANCE + || range.getEntityType() == ReindexEntityType.HOLDINGS) + .allMatch(range -> range.getStatus() == ReindexRangeStatus.FAIL + && "Some error".equals(range.getFailCause())); + } + @Test @SuppressWarnings("unchecked") void saveEntities() { diff --git a/src/test/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepositoryIT.java b/src/test/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepositoryIT.java index 629325c82..767e3c337 100644 --- a/src/test/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepositoryIT.java +++ b/src/test/java/org/folio/search/service/reindex/jdbc/ReindexStatusRepositoryIT.java @@ -7,6 +7,7 @@ import static org.folio.search.model.types.ReindexEntityType.INSTANCE; import static org.folio.search.model.types.ReindexEntityType.SUBJECT; import static org.folio.search.model.types.ReindexStatus.MERGE_COMPLETED; +import static org.folio.search.model.types.ReindexStatus.MERGE_IN_PROGRESS; import static org.folio.search.model.types.ReindexStatus.UPLOAD_COMPLETED; import static org.folio.search.model.types.ReindexStatus.UPLOAD_FAILED; import static org.folio.search.model.types.ReindexStatus.UPLOAD_IN_PROGRESS; @@ -14,6 +15,7 @@ import static org.mockito.Mockito.when; import java.sql.Timestamp; +import java.util.Set; import org.assertj.core.api.Condition; import org.folio.search.model.reindex.ReindexStatusEntity; import org.folio.spring.FolioExecutionContext; @@ -26,8 +28,8 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.boot.test.autoconfigure.json.AutoConfigureJson; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.jdbc.Sql; @IntegrationTest @@ -38,7 +40,7 @@ class ReindexStatusRepositoryIT { private @Autowired JdbcTemplate jdbcTemplate; - private @MockBean FolioExecutionContext context; + private @MockitoBean FolioExecutionContext context; private ReindexStatusRepository repository; @BeforeEach @@ -121,4 +123,19 @@ void addReindexCounts_shouldChangeStatus() { .anyMatch(reindexStatus -> UPLOAD_COMPLETED.equals(reindexStatus.getStatus()) && reindexStatus.getEndTimeUpload() != null); } + + @Test + @Sql("/sql/populate-reindex-status.sql") + void setMergeInProgress() { + var entityTypes = Set.of(INSTANCE); + + repository.setMergeInProgress(entityTypes); + + var statuses = repository.getReindexStatuses(); + assertThat(statuses) + .hasSize(4) + .filteredOn(reindexStatus -> entityTypes.contains(reindexStatus.getEntityType())) + .hasSize(1) + .allMatch(reindexStatus -> reindexStatus.getStatus() == MERGE_IN_PROGRESS); + } } diff --git a/src/test/java/org/folio/search/service/reindex/jdbc/UploadRangeRepositoriesIT.java b/src/test/java/org/folio/search/service/reindex/jdbc/UploadRangeRepositoriesIT.java index a92a3e458..000f1cfbf 100644 --- a/src/test/java/org/folio/search/service/reindex/jdbc/UploadRangeRepositoriesIT.java +++ b/src/test/java/org/folio/search/service/reindex/jdbc/UploadRangeRepositoriesIT.java @@ -17,8 +17,8 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.boot.test.autoconfigure.json.AutoConfigureJson; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.jdbc.Sql; @IntegrationTest @@ -29,8 +29,8 @@ class UploadRangeRepositoriesIT { private @Autowired JdbcTemplate jdbcTemplate; - private @MockBean FolioExecutionContext context; - private @MockBean ReindexConfigurationProperties reindexConfig; + private @MockitoBean FolioExecutionContext context; + private @MockitoBean ReindexConfigurationProperties reindexConfig; private UploadInstanceRepository uploadRepository; @BeforeEach diff --git a/src/test/java/org/folio/search/support/base/ApiEndpoints.java b/src/test/java/org/folio/search/support/base/ApiEndpoints.java index da6f695b0..b30f23505 100644 --- a/src/test/java/org/folio/search/support/base/ApiEndpoints.java +++ b/src/test/java/org/folio/search/support/base/ApiEndpoints.java @@ -190,6 +190,10 @@ public static String reindexUploadPath() { return "/search/index/instance-records/reindex/upload"; } + public static String reindexFailedPath() { + return "/search/index/instance-records/reindex/merge/failed"; + } + public static String allRecordsSortedBy(String sort, CqlSort order) { return String.format("cql.allRecords=1 sortBy %s/sort.%s", sort, order); } diff --git a/src/test/resources/sql/populate-merge-ranges.sql b/src/test/resources/sql/populate-merge-ranges.sql index 52ded657d..1afbe552f 100644 --- a/src/test/resources/sql/populate-merge-ranges.sql +++ b/src/test/resources/sql/populate-merge-ranges.sql @@ -1,6 +1,6 @@ -INSERT INTO merge_range (id, entity_type, tenant_id, lower, upper, created_at, finished_at) +INSERT INTO merge_range (id, entity_type, tenant_id, lower, upper, created_at, finished_at, status, fail_cause) VALUES - ('b7df83a1-8b15-46c1-9a4c-9d2dbb3cf4d6', 'holdings', 'consortium', 'cafc64298e7c488cbe9decc45e7659ec', '84aac856c4ab426c83029ab0e6a295c0', current_timestamp, current_timestamp), - ('dfb20d52-7f1f-4b5b-a492-2e47d2c0ac59', 'holdings', 'member_tenant', '9c2c968dc6424403a4492ec40afcd736', '8751df7ca5884d8682688c153bb98b16', current_timestamp, current_timestamp), - ('2f23b9fa-9e1a-44ff-a30f-61ec5f3adcc8', 'item', 'member_tenant', '9c2c968dc6424403a4492ec40afcd736', '8751df7ca5884d8682688c153bb98b16', current_timestamp, current_timestamp), - ('9f8febd1-e96c-46c4-a5f4-84a45cc499a2', 'instance', 'consortium', '9c2c968dc6424403a4492ec40afcd736', '8751df7ca5884d8682688c153bb98b16', current_timestamp, null); + ('b7df83a1-8b15-46c1-9a4c-9d2dbb3cf4d6', 'holdings', 'consortium', 'cafc64298e7c488cbe9decc45e7659ec', '84aac856c4ab426c83029ab0e6a295c0', current_timestamp, current_timestamp, 'FAIL', 'Some error'), + ('dfb20d52-7f1f-4b5b-a492-2e47d2c0ac59', 'holdings', 'member_tenant', '9c2c968dc6424403a4492ec40afcd736', '8751df7ca5884d8682688c153bb98b16', current_timestamp, current_timestamp, 'FAIL', 'Some error'), + ('2f23b9fa-9e1a-44ff-a30f-61ec5f3adcc8', 'item', 'member_tenant', '9c2c968dc6424403a4492ec40afcd736', '8751df7ca5884d8682688c153bb98b16', current_timestamp, current_timestamp, 'SUCCESS', null), + ('9f8febd1-e96c-46c4-a5f4-84a45cc499a2', 'instance', 'consortium', '9c2c968dc6424403a4492ec40afcd736', '8751df7ca5884d8682688c153bb98b16', current_timestamp, null, 'FAIL', 'Some error');