diff --git a/src/test/java/org/folio/dcb/service/impl/ShadowLocationServiceImplTest.java b/src/test/java/org/folio/dcb/service/impl/ShadowLocationServiceImplTest.java index 71f1b077..0a084675 100644 --- a/src/test/java/org/folio/dcb/service/impl/ShadowLocationServiceImplTest.java +++ b/src/test/java/org/folio/dcb/service/impl/ShadowLocationServiceImplTest.java @@ -10,6 +10,7 @@ import static org.folio.dcb.domain.dto.RefreshLocationStatusType.ERROR; import static org.folio.dcb.domain.dto.RefreshLocationStatusType.SKIPPED; import static org.folio.dcb.domain.dto.RefreshLocationStatusType.SUCCESS; +import static org.folio.dcb.utils.CqlQuery.exactMatchByNameAndCode; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -35,7 +36,6 @@ import org.folio.dcb.integration.invstorage.model.Location; import org.folio.dcb.integration.invstorage.model.LocationUnit; import org.folio.dcb.service.entities.DcbEntityServiceFacade; -import org.folio.dcb.utils.CqlQuery; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -374,6 +374,141 @@ void createShadowLocations_negative_serviceExceptionThrown() { .hasMessage("Failed to create shadow locations"); } + @Test + void createShadowLocations_positive_partialExistenceHierarchyReuse() { + // TestMate-34ec793e0eaae755ccfec6a1494f9d1b + when(dcbFeatureProperties.isFlexibleCirculationRulesEnabled()).thenReturn(true); + when(dcbEntityServiceFacade.findOrCreateServicePoint()).thenReturn(servicePoint()); + when(locationUnitClient.findInstitutionsByQuery(agencySql(), true, 10, 0)).thenReturn(asSinglePage(institution())); + when(locationUnitClient.findCampusesByQuery(agencySql(), true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.findLibrariesByQuery(agencySql(), true, 10, 0)).thenReturn(empty()); + when(locationsClient.findLocationByQuery(locationSql(), true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.createCampus(luCaptor.capture())).then(returningFirstArgument()); + when(locationUnitClient.createLibrary(luCaptor.capture())).then(returningFirstArgument()); + when(locationsClient.createLocation(locCaptor.capture())).then(returningFirstArgument()); + var refreshRequest = refreshRequest(List.of(dcbLocation()), emptyList()); + + var result = dcbHubLocationService.createShadowLocations(refreshRequest); + + assertThat(result).isEqualTo(new RefreshShadowLocationResponse() + .addLocationsItem(refreshLocationStatus(SUCCESS)) + .locationUnits(new RefreshLocationUnitsStatus() + .addInstitutionsItem(refreshAgencyStatus(SKIPPED)) + .addCampusesItem(refreshAgencyStatus(SUCCESS)) + .addLibrariesItem(refreshAgencyStatus(SUCCESS)))); + verify(locationUnitClient, never()).createInstitution(any()); + verify(locationUnitClient).createCampus(any()); + verify(locationUnitClient).createLibrary(any()); + verify(locationsClient).createLocation(any()); + LocationUnit capturedCampus = luCaptor.getAllValues().stream() + .filter(lu -> lu.getInstitutionId() != null && lu.getCampusId() == null) + .findFirst() + .orElseThrow(); + assertThat(capturedCampus.getInstitutionId()).isEqualTo(INSTITUTION_ID); + } + + @Test + void createShadowLocations_positive_combinedRequestGrouping() { + // TestMate-94fcb8ae859525449cb6b22ac8ffa5f8 + var loc1Name = "Location 1"; + var loc1Code = "LOC-1"; + var loc2Name = "Location 2"; + var loc2Code = "LOC-2"; + var loc1Sql = exactMatchByNameAndCode(loc1Name, loc1Code).getQuery(); + var loc2Sql = exactMatchByNameAndCode(loc2Name, loc2Code).getQuery(); + when(dcbFeatureProperties.isFlexibleCirculationRulesEnabled()).thenReturn(true); + when(dcbEntityServiceFacade.findOrCreateServicePoint()).thenReturn(servicePoint()); + when(locationUnitClient.findInstitutionsByQuery(agencySql(), true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.findCampusesByQuery(agencySql(), true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.findLibrariesByQuery(agencySql(), true, 10, 0)).thenReturn(empty()); + when(locationsClient.findLocationByQuery(loc1Sql, true, 10, 0)).thenReturn(empty()); + when(locationsClient.findLocationByQuery(loc2Sql, true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.createInstitution(luCaptor.capture())).then(returningFirstArgument()); + when(locationUnitClient.createCampus(luCaptor.capture())).then(returningFirstArgument()); + when(locationUnitClient.createLibrary(luCaptor.capture())).then(returningFirstArgument()); + when(locationsClient.createLocation(locCaptor.capture())).then(returningFirstArgument()); + var agency = dcbAgency(); + var location1 = dcbLocation(loc1Name, loc1Code, agency); + var location2 = dcbLocation(loc2Name, loc2Code, agency); + var refreshRequest = refreshRequest(List.of(location1, location2), List.of()); + + var result = dcbHubLocationService.createShadowLocations(refreshRequest); + + assertThat(result).isEqualTo(new RefreshShadowLocationResponse() + .addLocationsItem(refreshLocationStatus(SUCCESS).code(loc1Code)) + .addLocationsItem(refreshLocationStatus(SUCCESS).code(loc2Code)) + .locationUnits(new RefreshLocationUnitsStatus() + .addInstitutionsItem(refreshAgencyStatus(SUCCESS)) + .addCampusesItem(refreshAgencyStatus(SUCCESS)) + .addLibrariesItem(refreshAgencyStatus(SUCCESS)))); + verify(locationUnitClient, times(1)).createInstitution(any()); + verify(locationUnitClient, times(1)).createCampus(any()); + verify(locationUnitClient, times(1)).createLibrary(any()); + verify(locationsClient, times(2)).createLocation(any()); + var capturedLocations = locCaptor.getAllValues(); + assertThat(capturedLocations) + .extracting(Location::getCode, Location::getName) + .containsExactlyInAnyOrder(tuple(loc1Code, loc1Name), tuple(loc2Code, loc2Name)); + var sharedInstitutionId = capturedLocations.get(0).getInstitutionId(); + var sharedCampusId = capturedLocations.get(0).getCampusId(); + var sharedLibraryId = capturedLocations.get(0).getLibraryId(); + assertThat(capturedLocations.get(1).getInstitutionId()).isEqualTo(sharedInstitutionId); + assertThat(capturedLocations.get(1).getCampusId()).isEqualTo(sharedCampusId); + assertThat(capturedLocations.get(1).getLibraryId()).isEqualTo(sharedLibraryId); + } + + @Test + void createShadowLocations_positive_partialSuccessMultipleAgencies() { + // TestMate-f3af2b8f3b8782a468074ae1dee25408 + var agency1Name = "Agency Fail"; + var agency1Code = "AG-FAIL"; + var agency2Name = "Agency Success"; + var agency2Code = "AG-SUCCESS"; + var agency1Sql = exactMatchByNameAndCode(agency1Name, agency1Code).getQuery(); + when(dcbFeatureProperties.isFlexibleCirculationRulesEnabled()).thenReturn(true); + when(dcbEntityServiceFacade.findOrCreateServicePoint()).thenReturn(servicePoint()); + when(locationUnitClient.findInstitutionsByQuery(agency1Sql, true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.createInstitution(any())).thenAnswer(invocation -> { + var lu = invocation.getArgument(0); + if (agency1Code.equals(lu.getCode())) { + throw badRequestError("/institutions"); + } + return lu; + }); + + var agency2Sql = exactMatchByNameAndCode(agency2Name, agency2Code).getQuery(); + when(locationUnitClient.findInstitutionsByQuery(agency2Sql, true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.findCampusesByQuery(agency2Sql, true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.findLibrariesByQuery(agency2Sql, true, 10, 0)).thenReturn(empty()); + when(locationsClient.findLocationByQuery(agency2Sql, true, 10, 0)).thenReturn(empty()); + when(locationUnitClient.createCampus(luCaptor.capture())).then(returningFirstArgument()); + when(locationUnitClient.createLibrary(luCaptor.capture())).then(returningFirstArgument()); + when(locationsClient.createLocation(locCaptor.capture())).then(returningFirstArgument()); + var agency1 = new DcbAgency().name(agency1Name).code(agency1Code); + var agency2 = new DcbAgency().name(agency2Name).code(agency2Code); + var refreshRequest = refreshRequest(emptyList(), List.of(agency1, agency2)); + + var result = dcbHubLocationService.createShadowLocations(refreshRequest); + assertThat(result.getLocationUnits().getInstitutions()) + .extracting(RefreshLocationStatus::getCode, RefreshLocationStatus::getStatus) + .containsExactlyInAnyOrder(tuple(agency1Code, ERROR), tuple(agency2Code, SUCCESS)); + + assertThat(result.getLocationUnits().getCampuses()) + .extracting(RefreshLocationStatus::getCode, RefreshLocationStatus::getStatus) + .containsExactlyInAnyOrder(tuple(agency1Code, SKIPPED), tuple(agency2Code, SUCCESS)); + + assertThat(result.getLocations()) + .extracting(RefreshLocationStatus::getCode, RefreshLocationStatus::getStatus) + .containsExactlyInAnyOrder(tuple(agency1Code, SKIPPED), tuple(agency2Code, SUCCESS)); + + verify(locationUnitClient, times(2)).createInstitution(any()); + verify(locationUnitClient, times(1)).createCampus(any()); + verify(locationsClient, times(1)).createLocation(any()); + assertThat(locCaptor.getAllValues()) + .extracting(Location::getCode, Location::getName) + .containsExactly(tuple(agency2Code, agency2Name)); + } + private static ShadowLocationRefreshBody refreshRequest(List locations, List agencies) { return new ShadowLocationRefreshBody() .locations(locations) @@ -401,11 +536,11 @@ private static ServicePointRequest servicePoint() { } private static String agencySql() { - return CqlQuery.exactMatchByNameAndCode(AGENCY_NAME, AGENCY_CODE).getQuery(); + return exactMatchByNameAndCode(AGENCY_NAME, AGENCY_CODE).getQuery(); } private static String locationSql() { - return CqlQuery.exactMatchByNameAndCode(LOCATION_NAME, LOCATION_CODE).getQuery(); + return exactMatchByNameAndCode(LOCATION_NAME, LOCATION_CODE).getQuery(); } private static Answer returningFirstArgument() {