From 2e4945b1393f6cb875da3640660284adb3a31a5b Mon Sep 17 00:00:00 2001 From: Azizbek Khushvakov <113523904+azizbekxm@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:28:02 +0500 Subject: [PATCH] [MODCON - 71] - Implement endpoint to delete shared setting uuid from all tenants (#80) * [MODCON - 80] - Add shadow system user when adding tenant to consortia * [MODCON - 80] - Add shadow system user when adding tenant to consortia * [MODCON - 80] - Add shadow system user when adding tenant to consortia * [MODCON - 80] - Add shadow system user when adding tenant to consortia * [MODCON - 71] - Implement endpoint to delete shared setting uuid from all tenants * [MODCON - 71] - Implement endpoint to delete shared setting uuid from all tenants * [MODCON - 71] - Implement endpoint to delete shared setting uuid from all tenants * [MODCON - 71] - Increased code coverage * [MODCON - 71] - Minor improvements --- descriptors/ModuleDescriptor-template.json | 20 +++++- .../controller/SharingSettingController.java | 7 ++ .../repository/SharingSettingRepository.java | 7 ++ .../service/HttpRequestServiceImpl.java | 6 +- .../service/SharingSettingService.java | 9 +++ .../impl/SharingSettingServiceImpl.java | 50 +++++++++++-- .../permissions/system-user-permissions.csv | 17 +++++ .../swagger.api/schemas/sharingSetting.yaml | 13 +++- .../swagger.api/sharing_settings.yaml | 54 +++++++++----- .../controller/PublicationControllerTest.java | 6 +- .../SharingSettingControllerTest.java | 20 +++++- .../service/HttpRequestServiceImplTest.java | 8 +-- .../service/SharingSettingServiceTest.java | 71 +++++++++++++++++-- .../folio/consortia/utils/EntityUtils.java | 22 ++++-- ...aring_setting_request_without_payload.json | 4 ++ 15 files changed, 269 insertions(+), 45 deletions(-) create mode 100644 src/test/resources/mockdata/sharing_setting_request_without_payload.json diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index df1bb4cc..14870491 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -294,6 +294,16 @@ "consortia.sharing-settings.item.post" ], "modulePermissions": [] + }, + { + "methods": [ + "DELETE" + ], + "pathPattern": "/consortia/{consortiumId}/sharing/settings/{settingId}", + "permissionsRequired": [ + "consortia.sharing-settings.item.delete" + ], + "modulePermissions": [] } ] }, @@ -361,7 +371,8 @@ "consortia.publications.item.get", "consortia.publications.item.delete", "consortia.publications-results.item.get", - "consortia.sharing-settings.item.post" + "consortia.sharing-settings.item.post", + "consortia.sharing-settings.item.delete" ] }, { @@ -467,7 +478,12 @@ { "permissionName": "consortia.sharing-settings.item.post", "displayName": "post sharing setting", - "description": "create sharing setting" + "description": "Create sharing setting" + }, + { + "permissionName": "consortia.sharing-settings.item.delete", + "displayName": "delete sharing setting", + "description": "Delete sharing setting" } ], "launchDescriptor": { diff --git a/src/main/java/org/folio/consortia/controller/SharingSettingController.java b/src/main/java/org/folio/consortia/controller/SharingSettingController.java index 7325579c..66612eb6 100644 --- a/src/main/java/org/folio/consortia/controller/SharingSettingController.java +++ b/src/main/java/org/folio/consortia/controller/SharingSettingController.java @@ -4,6 +4,7 @@ import java.util.UUID; +import org.folio.consortia.domain.dto.SharingSettingDeleteResponse; import org.folio.consortia.domain.dto.SharingSettingRequest; import org.folio.consortia.domain.dto.SharingSettingResponse; import org.folio.consortia.rest.resource.SettingsApi; @@ -25,4 +26,10 @@ public class SharingSettingController implements SettingsApi { public ResponseEntity startSharingSetting(UUID consortiumId, SharingSettingRequest sharingSettingRequest) { return ResponseEntity.status(CREATED).body(sharingSettingService.start(consortiumId, sharingSettingRequest)); } + + @Override + public ResponseEntity deleteSharingSetting(UUID consortiumId, UUID settingId, + SharingSettingRequest sharingSettingRequest) { + return ResponseEntity.ok(sharingSettingService.delete(consortiumId, settingId, sharingSettingRequest)); + } } diff --git a/src/main/java/org/folio/consortia/repository/SharingSettingRepository.java b/src/main/java/org/folio/consortia/repository/SharingSettingRepository.java index ca607de7..b61adb56 100644 --- a/src/main/java/org/folio/consortia/repository/SharingSettingRepository.java +++ b/src/main/java/org/folio/consortia/repository/SharingSettingRepository.java @@ -5,6 +5,7 @@ import org.folio.consortia.domain.entity.SharingSettingEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -12,4 +13,10 @@ public interface SharingSettingRepository extends JpaRepository{ @Query("SELECT st.tenantId FROM SharingSettingEntity st WHERE st.settingId = ?1") Set findTenantsBySettingId(UUID settingId); + + boolean existsBySettingId(UUID settingId); + + @Modifying + @Query("DELETE FROM SharingSettingEntity st where st.settingId = ?1") + void deleteBySettingId(UUID settingId); } diff --git a/src/main/java/org/folio/consortia/service/HttpRequestServiceImpl.java b/src/main/java/org/folio/consortia/service/HttpRequestServiceImpl.java index 8f975e34..c297f5d9 100644 --- a/src/main/java/org/folio/consortia/service/HttpRequestServiceImpl.java +++ b/src/main/java/org/folio/consortia/service/HttpRequestServiceImpl.java @@ -35,7 +35,11 @@ public PublicationHttpResponse performRequest(String url, HttpMethod httpMethod, var absUrl = folioExecutionContext.getOkapiUrl() + url; log.debug("performRequest:: folio context header TENANT = {}" , folioExecutionContext.getOkapiHeaders().get(XOkapiHeaders.TENANT).iterator().next()); - var responseEntity = restTemplate.exchange(absUrl, httpMethod, httpEntity, Object.class); + var responseEntity = switch (httpMethod.toString()) { + case "GET" -> restTemplate.exchange(absUrl, httpMethod, httpEntity, Object.class); + case "POST", "PUT", "DELETE" -> restTemplate.exchange(absUrl, httpMethod, httpEntity, String.class); + default -> throw new IllegalStateException("Unexpected value: " + httpMethod); + }; return new PublicationHttpResponse(objectMapper.writeValueAsString(responseEntity.getBody()), responseEntity.getStatusCode()); } diff --git a/src/main/java/org/folio/consortia/service/SharingSettingService.java b/src/main/java/org/folio/consortia/service/SharingSettingService.java index f0af6b91..7487310b 100644 --- a/src/main/java/org/folio/consortia/service/SharingSettingService.java +++ b/src/main/java/org/folio/consortia/service/SharingSettingService.java @@ -2,6 +2,7 @@ import java.util.UUID; +import org.folio.consortia.domain.dto.SharingSettingDeleteResponse; import org.folio.consortia.domain.dto.SharingSettingRequest; import org.folio.consortia.domain.dto.SharingSettingResponse; @@ -15,4 +16,12 @@ public interface SharingSettingService { */ SharingSettingResponse start(UUID consortiumId, SharingSettingRequest sharingSettingRequest); + /** + * Delete sharing setting for all tenants + * @param consortiumId ID of consortium + * @param settingId ID of setting + * @param sharingSettingRequest the sharingSettingDTO (data transfer object) + * @return Sharing setting response for delete operation + */ + SharingSettingDeleteResponse delete(UUID consortiumId, UUID settingId, SharingSettingRequest sharingSettingRequest); } diff --git a/src/main/java/org/folio/consortia/service/impl/SharingSettingServiceImpl.java b/src/main/java/org/folio/consortia/service/impl/SharingSettingServiceImpl.java index 8547da67..cb64893f 100644 --- a/src/main/java/org/folio/consortia/service/impl/SharingSettingServiceImpl.java +++ b/src/main/java/org/folio/consortia/service/impl/SharingSettingServiceImpl.java @@ -12,11 +12,13 @@ import org.apache.commons.lang3.ObjectUtils; import org.folio.consortia.config.FolioExecutionContextHelper; import org.folio.consortia.domain.dto.PublicationRequest; +import org.folio.consortia.domain.dto.SharingSettingDeleteResponse; import org.folio.consortia.domain.dto.SharingSettingRequest; import org.folio.consortia.domain.dto.SharingSettingResponse; import org.folio.consortia.domain.dto.Tenant; import org.folio.consortia.domain.dto.TenantCollection; import org.folio.consortia.domain.entity.SharingSettingEntity; +import org.folio.consortia.exception.ResourceNotFoundException; import org.folio.consortia.repository.SharingSettingRepository; import org.folio.consortia.service.ConsortiumService; import org.folio.consortia.service.PublicationService; @@ -34,13 +36,13 @@ import com.fasterxml.jackson.databind.node.TextNode; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.log4j.Log4j2; @Service @Log4j2 @RequiredArgsConstructor public class SharingSettingServiceImpl implements SharingSettingService { - private final SharingSettingRepository sharingSettingRepository; private final TenantService tenantService; private final ConsortiumService consortiumService; @@ -99,6 +101,46 @@ public SharingSettingResponse start(UUID consortiumId, SharingSettingRequest sha } } + @Override + @Transactional + @SneakyThrows + public SharingSettingDeleteResponse delete(UUID consortiumId, UUID settingId, SharingSettingRequest sharingSettingRequest) { + log.debug("start:: Trying to delete sharing setting with consortiumId: {}, sharing settingId: {}", consortiumId, settingId); + validateSharingSettingRequestOrThrow(settingId, sharingSettingRequest); + consortiumService.checkConsortiumExistsOrThrow(consortiumId); + Set settingTenants = sharingSettingRepository.findTenantsBySettingId(settingId); + TenantCollection allTenants = tenantService.getAll(consortiumId); + PublicationRequest publicationDeleteRequest = createPublicationRequestForSetting(sharingSettingRequest, HttpMethod.DELETE.toString()); + + // By traverse through all tenants in db, + // we will add tenant to delete request publication tenant list, if it exists in setting tenant associations + for (Tenant tenant : allTenants.getTenants()) { + if (settingTenants.contains(tenant.getId())) { + publicationDeleteRequest.getTenants().add(tenant.getId()); + log.info("start:: tenant={} added to publication delete request for setting={}", tenant.getId(), settingId); + } + } + log.info("start:: tenants with size: {} successfully added to appropriate publication request for setting: {}", allTenants.getTotalRecords(), settingId); + sharingSettingRepository.deleteBySettingId(settingId); + log.info("start:: The Sharing Settings for settingId '{}' and '{}' unique tenant(s) were successfully deleted from the database", sharingSettingRequest.getSettingId(), publicationDeleteRequest.getTenants().size()); + + // we create PC request with POST and PUT Http method to create settings as a consortia-system-user + try (var ignored = new FolioExecutionContextSetter(contextHelper.getSystemUserFolioExecutionContext(folioExecutionContext.getTenantId()))) { + UUID pcId = publishRequest(consortiumId, publicationDeleteRequest); + return new SharingSettingDeleteResponse() + .pcId(pcId); + } + } + + private void validateSharingSettingRequestOrThrow(UUID settingId, SharingSettingRequest sharingSettingRequest) { + if (ObjectUtils.notEqual(sharingSettingRequest.getSettingId(), settingId)) { + throw new IllegalArgumentException("Mismatch id in path to settingId in request body"); + } + if (!sharingSettingRepository.existsBySettingId(settingId)) { + throw new ResourceNotFoundException("settingId", String.valueOf(settingId)); + } + } + private UUID publishRequest(UUID consortiumId, PublicationRequest publicationRequest) { if (CollectionUtils.isNotEmpty(publicationRequest.getTenants())) { return publicationService.publishRequest(consortiumId, publicationRequest).getId(); @@ -111,7 +153,7 @@ private void checkEqualsOfPayloadIdWithSettingId(SharingSettingRequest sharingSe String sharingSettingId = String.valueOf(sharingSettingRequest.getSettingId()); String payloadId = getPayloadId(sharingSettingRequest.getPayload()); if (ObjectUtils.notEqual(sharingSettingId, payloadId)) { - throw new IllegalArgumentException("id in payload is not equal to settingId"); + throw new IllegalArgumentException("Mismatch id in payload with settingId"); } } @@ -124,8 +166,8 @@ private PublicationRequest createPublicationRequestForSetting(SharingSettingRequ PublicationRequest publicationRequest = new PublicationRequest(); publicationRequest.setMethod(httpMethod); String url = sharingSettingRequest.getUrl(); - if (httpMethod.equals(HttpMethod.PUT.toString())) { - url += "/" + getPayloadId(sharingSettingRequest.getPayload()); + if (httpMethod.equals(HttpMethod.PUT.toString()) || httpMethod.equals(HttpMethod.DELETE.toString())) { + url += "/" + sharingSettingRequest.getSettingId(); } publicationRequest.setUrl(url); publicationRequest.setPayload(sharingSettingRequest.getPayload()); diff --git a/src/main/resources/permissions/system-user-permissions.csv b/src/main/resources/permissions/system-user-permissions.csv index d646142c..0f98d201 100644 --- a/src/main/resources/permissions/system-user-permissions.csv +++ b/src/main/resources/permissions/system-user-permissions.csv @@ -14,35 +14,52 @@ consortia.sync-primary-affiliations.item.post consortia.create-primary-affiliations.item.post departments.item.post departments.item.put +departments.item.delete usergroups.item.post usergroups.item.put +usergroups.item.delete inventory-storage.material-types.item.post inventory-storage.material-types.item.put +inventory-storage.material-types.item.delete inventory-storage.loan-types.item.post inventory-storage.loan-types.item.put +inventory-storage.loan-types.item.delete inventory-storage.item-note-types.item.post inventory-storage.item-note-types.item.put +inventory-storage.item-note-types.item.delete inventory-storage.electronic-access-relationships.item.post inventory-storage.electronic-access-relationships.item.put +inventory-storage.electronic-access-relationships.item.delete inventory-storage.statistical-codes.item.post inventory-storage.statistical-codes.item.put +inventory-storage.statistical-codes.item.delete inventory-storage.statistical-code-types.item.post inventory-storage.statistical-code-types.item.put +inventory-storage.statistical-code-types.item.delete inventory-storage.identifier-types.item.post inventory-storage.identifier-types.item.put +inventory-storage.identifier-types.item.delete inventory-storage.nature-of-content-terms.item.post inventory-storage.nature-of-content-terms.item.put +inventory-storage.nature-of-content-terms.item.delete inventory-storage.modes-of-issuance.item.post inventory-storage.modes-of-issuance.item.put +inventory-storage.modes-of-issuance.item.delete inventory-storage.instance-statuses.item.post inventory-storage.instance-statuses.item.put +inventory-storage.instance-statuses.item.delete inventory-storage.instance-note-types.item.post inventory-storage.instance-note-types.item.put +inventory-storage.instance-note-types.item.delete inventory-storage.instance-formats.item.post inventory-storage.instance-formats.item.put +inventory-storage.instance-formats.item.delete inventory-storage.contributor-types.item.post inventory-storage.contributor-types.item.put +inventory-storage.contributor-types.item.delete inventory-storage.alternative-title-types.item.post inventory-storage.alternative-title-types.item.put +inventory-storage.alternative-title-types.item.delete circulation-storage.cancellation-reasons.item.post circulation-storage.cancellation-reasons.item.put +circulation-storage.cancellation-reasons.item.delete diff --git a/src/main/resources/swagger.api/schemas/sharingSetting.yaml b/src/main/resources/swagger.api/schemas/sharingSetting.yaml index 91dcf153..0016b838 100644 --- a/src/main/resources/swagger.api/schemas/sharingSetting.yaml +++ b/src/main/resources/swagger.api/schemas/sharingSetting.yaml @@ -14,7 +14,7 @@ SharingSettingRequest: type: object additionalProperties: false required: - - id + - settingId - url SharingSettingResponse: @@ -31,3 +31,14 @@ SharingSettingResponse: required: - createSettingsPCId - updateSettingsPCId + +SharingSettingDeleteResponse: + description: "A JSON schema for the Sharing settings object response for delete request" + type: object + properties: + pcId: + type: string + format: uuid + additionalProperties: false + required: + - pcId diff --git a/src/main/resources/swagger.api/sharing_settings.yaml b/src/main/resources/swagger.api/sharing_settings.yaml index 12d593ca..66bdb819 100644 --- a/src/main/resources/swagger.api/sharing_settings.yaml +++ b/src/main/resources/swagger.api/sharing_settings.yaml @@ -27,15 +27,30 @@ paths: $ref: "#/components/responses/Conflict" "500": $ref: "#/components/responses/InternalServerError" + /settings/{settingId}: + delete: + summary: delete sharing setting + operationId: deleteSharingSetting + parameters: + - $ref: "#/components/parameters/consortiumId" + - $ref: "#/components/parameters/settingId" + requestBody: + $ref: "#/components/requestBodies/SharingSettingBody" + responses: + "200": + $ref: "#/components/responses/SharingSettingDeleteResponse" + "400": + $ref: "#/components/responses/BadRequest" + "404": + $ref: "#/components/responses/NotFound" + "409": + $ref: "#/components/responses/Conflict" + "422": + $ref: "#/components/responses/Conflict" + "500": + $ref: "#/components/responses/InternalServerError" components: requestBodies: - SharingInstanceBody: - description: Sharing Instance object - required: true - content: - application/json: - schema: - $ref: "schemas/sharingInstance.yaml#/SharingInstance" SharingSettingBody: description: Sharing settings object required: true @@ -44,24 +59,18 @@ components: schema: $ref: "schemas/sharingSetting.yaml#/SharingSettingRequest" responses: - SharingInstance: - description: Returns a sharing instance object object - content: - application/json: - schema: - $ref: "schemas/sharingInstance.yaml#/SharingInstance" - SharingInstanceCollection: - description: Returns list of sharing instances + SharingSettingResponse: + description: Returns a sharing setting object response for post operation content: application/json: schema: - $ref: "schemas/sharingInstance.yaml#/SharingInstanceCollection" - SharingSettingResponse: - description: Returns a sharing instance object object + $ref: "schemas/sharingSetting.yaml#/SharingSettingResponse" + SharingSettingDeleteResponse: + description: Returns a sharing setting response for delete operation content: application/json: schema: - $ref: "schemas/sharingSetting.yaml#/SharingSettingResponse" + $ref: "schemas/sharingSetting.yaml#/SharingSettingDeleteResponse" NoContent: description: No content Conflict: @@ -107,3 +116,10 @@ components: $ref: "schemas/common.yaml#/uuid" required: true description: The ID of consortium + settingId: + in: path + name: settingId + schema: + $ref: "schemas/common.yaml#/uuid" + required: true + description: The ID of setting diff --git a/src/test/java/org/folio/consortia/controller/PublicationControllerTest.java b/src/test/java/org/folio/consortia/controller/PublicationControllerTest.java index 905793be..6d3982c0 100644 --- a/src/test/java/org/folio/consortia/controller/PublicationControllerTest.java +++ b/src/test/java/org/folio/consortia/controller/PublicationControllerTest.java @@ -248,10 +248,10 @@ void parallelTenantRequestsTest(int tenantsAmount, int chunkSize) throws JsonPro .map(val -> "tenant_" + val) .toList(); - ResponseEntity restTemplateResponse = new ResponseEntity<>(ptreAsString, HttpStatusCode.valueOf(201)); + ResponseEntity restTemplateResponse = new ResponseEntity<>(ptreAsString, HttpStatusCode.valueOf(201)); ArgumentCaptor> entityCaptor = ArgumentCaptor.forClass(HttpEntity.class); - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), entityCaptor.capture(), eq(Object.class))).thenReturn(restTemplateResponse); + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), entityCaptor.capture(), eq(String.class))).thenReturn(restTemplateResponse); // split list of tenants into chunks and make parallel API calls StreamEx.ofSubLists(listOfTenantNames, chunkSize) @@ -282,7 +282,7 @@ void parallelTenantRequestsTest(int tenantsAmount, int chunkSize) throws JsonPro .sorted() .toList(); - verify(restTemplate, times(listOfTenantNames.size())).exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Object.class)); + verify(restTemplate, times(listOfTenantNames.size())).exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); // check if all 'x-okapi-tenant' values match with the initial list of expected tenant names Assertions.assertTrue(CollectionUtils.isEqualCollection(capturedTenantHeaders, listOfTenantNames)); } diff --git a/src/test/java/org/folio/consortia/controller/SharingSettingControllerTest.java b/src/test/java/org/folio/consortia/controller/SharingSettingControllerTest.java index 619c3b6c..f870f441 100644 --- a/src/test/java/org/folio/consortia/controller/SharingSettingControllerTest.java +++ b/src/test/java/org/folio/consortia/controller/SharingSettingControllerTest.java @@ -2,12 +2,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.UUID; +import org.folio.consortia.domain.dto.SharingSettingDeleteResponse; import org.folio.consortia.domain.dto.SharingSettingResponse; import org.folio.consortia.service.SharingSettingService; import org.folio.consortia.support.BaseIT; @@ -17,7 +19,6 @@ import org.springframework.http.MediaType; class SharingSettingControllerTest extends BaseIT { - @MockBean SharingSettingService sharingSettingService; @@ -42,4 +43,21 @@ void shouldStartSharingSetting3(String body) throws Exception { .andExpect(jsonPath("$.createSettingsPCId").value(String.valueOf(createSettingsPcId))) .andExpect(jsonPath("$.updateSettingsPCId").value(String.valueOf(updateSettingsPcId))); } + + @ParameterizedTest + @ValueSource(strings = {"{\"settingId\":\"1844767a-8367-4926-9999-514c35840399\",\"url\":\"/organizations-storage/organizations\"}" }) + void shouldDeleteSharingSetting(String body) throws Exception { + var headers = defaultHeaders(); + UUID pcId = UUID.randomUUID(); + SharingSettingDeleteResponse sharingSettingDeleteResponse = new SharingSettingDeleteResponse().pcId(pcId); + + when(sharingSettingService.delete(any(), any(), any())).thenReturn(sharingSettingDeleteResponse); + + this.mockMvc.perform( + delete("/consortia/7698e46-c3e3-11ed-afa1-0242ac120002/sharing/settings/1844767a-8367-4926-9999-514c35840399") + .headers(headers) + .content(body) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()); + } } diff --git a/src/test/java/org/folio/consortia/service/HttpRequestServiceImplTest.java b/src/test/java/org/folio/consortia/service/HttpRequestServiceImplTest.java index 9444d2de..e0a42b72 100644 --- a/src/test/java/org/folio/consortia/service/HttpRequestServiceImplTest.java +++ b/src/test/java/org/folio/consortia/service/HttpRequestServiceImplTest.java @@ -32,9 +32,9 @@ class HttpRequestServiceImplTest extends BaseUnitTest { ObjectMapper objectMapper; @Test void performRequestSuccess() throws JsonProcessingException { - Object payload = RandomStringUtils.random(10); + String payload = RandomStringUtils.random(10); - ResponseEntity restTemplateResponse = new ResponseEntity<>(payload, HttpStatusCode.valueOf(201)); + ResponseEntity restTemplateResponse = new ResponseEntity<>(payload, HttpStatusCode.valueOf(201)); when(folioExecutionContext.getTenantId()).thenReturn(CENTRAL_TENANT_NAME); when(folioExecutionContext.getOkapiHeaders()).thenReturn(defaultHeaders()); when(folioExecutionContext.getAllHeaders()).thenReturn(defaultHeaders()); @@ -42,9 +42,9 @@ void performRequestSuccess() throws JsonProcessingException { anyString(), eq(HttpMethod.POST), Mockito.any(HttpEntity.class), - Mockito.eq(Object.class)) + Mockito.eq(String.class)) ).thenReturn(restTemplateResponse); - when(objectMapper.writeValueAsString(any())).thenReturn((String) payload); + when(objectMapper.writeValueAsString(any())).thenReturn(payload); var response = httpRequestService.performRequest(RandomStringUtils.random(10), HttpMethod.POST, new Object()); Assertions.assertEquals(payload, response.getBody()); diff --git a/src/test/java/org/folio/consortia/service/SharingSettingServiceTest.java b/src/test/java/org/folio/consortia/service/SharingSettingServiceTest.java index b1280891..015ab5cc 100644 --- a/src/test/java/org/folio/consortia/service/SharingSettingServiceTest.java +++ b/src/test/java/org/folio/consortia/service/SharingSettingServiceTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.folio.consortia.utils.EntityUtils.createPublicationRequestForSetting; import static org.folio.consortia.utils.EntityUtils.createSharingSettingResponse; +import static org.folio.consortia.utils.EntityUtils.createSharingSettingResponseForDelete; import static org.folio.consortia.utils.EntityUtils.createTenant; import static org.folio.consortia.utils.EntityUtils.createTenantCollection; import static org.folio.consortia.utils.InputOutputTestUtils.getMockDataObject; @@ -36,6 +37,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpMethod; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -44,7 +46,7 @@ @SpringBootTest class SharingSettingServiceTest { private static final String SHARING_SETTING_REQUEST_SAMPLE = "mockdata/sharing_setting_request.json"; - + private static final String SHARING_SETTING_REQUEST_SAMPLE_WITHOUT_PAYLOAD = "mockdata/sharing_setting_request_without_payload.json"; @InjectMocks private SharingSettingServiceImpl sharingSettingService; @Mock @@ -79,13 +81,13 @@ void shouldStartSharingSetting() throws JsonProcessingException { payload.put("name", "ORG-NAME"); payload.put("source", "local"); - // "tenant1" exists in tenant setting association so that tenant1 is in PUT method publication, + // "tenant1" exists in tenant setting association so that tenant1 is in PUT request publication, // "tenant2" is in POST method publication - var publicationRequestPut = createPublicationRequestForSetting(sharingSettingRequest, "PUT"); + var publicationRequestPut = createPublicationRequestForSetting(sharingSettingRequest, HttpMethod.PUT.toString()); publicationRequestPut.setMethod("PUT"); publicationRequestPut.setTenants(Set.of("tenant1")); publicationRequestPut.setUrl("/organizations-storage/organizations/1844767a-8367-4926-9999-514c35840399"); - var publicationRequestPost = createPublicationRequestForSetting(sharingSettingRequest, "POST"); + var publicationRequestPost = createPublicationRequestForSetting(sharingSettingRequest, HttpMethod.POST.toString()); publicationRequestPost.setMethod("POST"); publicationRequestPost.setTenants(Set.of("tenant2")); @@ -111,6 +113,40 @@ void shouldStartSharingSetting() throws JsonProcessingException { verify(publicationService, times(2)).publishRequest(any(), any()); } + @Test + void shouldDeleteSharingSetting() { + UUID consortiumId = UUID.randomUUID(); + UUID pcId = UUID.randomUUID(); + UUID settingId = UUID.fromString("1844767a-8367-4926-9999-514c35840399"); + Tenant tenant1 = createTenant("tenant1", "tenant1"); + Tenant tenant2 = createTenant("tenant2", "tenant2"); + Set tenantAssociationsWithSetting = Set.of("tenant1"); + TenantCollection tenantCollection = createTenantCollection(List.of(tenant1, tenant2)); + var sharingSettingRequest = getMockDataObject(SHARING_SETTING_REQUEST_SAMPLE_WITHOUT_PAYLOAD, SharingSettingRequest.class); + + // "tenant1" exists in tenant setting association so that tenant1 is in DELETE request publication, + var publicationRequestDelete = createPublicationRequestForSetting(sharingSettingRequest, HttpMethod.DELETE.toString()); + publicationRequestDelete.setTenants(Set.of("tenant1")); + publicationRequestDelete.setUrl("/organizations-storage/organizations/1844767a-8367-4926-9999-514c35840399"); + + var publicationResponse = new PublicationResponse().id(pcId); + + when(consortiumRepository.existsById(consortiumId)).thenReturn(true); + when(sharingSettingRepository.existsBySettingId(settingId)).thenReturn(true); + when(publicationService.publishRequest(consortiumId, publicationRequestDelete)).thenReturn(publicationResponse); + when(tenantService.getAll(consortiumId)).thenReturn(tenantCollection); + when(sharingSettingRepository.findTenantsBySettingId(sharingSettingRequest.getSettingId())).thenReturn(tenantAssociationsWithSetting); + when(folioExecutionContext.getTenantId()).thenReturn("mobius"); + doReturn(folioExecutionContext).when(contextHelper).getSystemUserFolioExecutionContext(anyString()); + + var expectedResponse = createSharingSettingResponseForDelete(pcId); + var actualResponse = sharingSettingService.delete(consortiumId, settingId, sharingSettingRequest); + + assertThat(actualResponse.getPcId()).isEqualTo(expectedResponse.getPcId()); + + verify(publicationService, times(1)).publishRequest(any(), any()); + } + // Negative cases @Test void shouldThrowErrorForNotEqualSettingIdWithPayloadId() throws JsonProcessingException { @@ -131,6 +167,33 @@ void shouldThrowErrorForNotEqualSettingIdWithPayloadId() throws JsonProcessingEx verify(publicationService, times(0)).publishRequest(any(), any()); } + @Test + void shouldThrowErrorForNotEqualSettingIdPathId() { + UUID consortiumId = UUID.randomUUID(); + UUID settingId = UUID.fromString("999999-8367-4926-9999-514c35840399"); + + var sharingSettingRequest = getMockDataObject(SHARING_SETTING_REQUEST_SAMPLE_WITHOUT_PAYLOAD, SharingSettingRequest.class); + + when(consortiumRepository.existsById(consortiumId)).thenReturn(true); + + assertThrows(java.lang.IllegalArgumentException.class, () -> sharingSettingService.delete(consortiumId, settingId, sharingSettingRequest)); + verify(publicationService, times(0)).publishRequest(any(), any()); + } + + @Test + void shouldThrowErrorForNotFound() { + UUID consortiumId = UUID.randomUUID(); + UUID settingId = UUID.fromString("1844767a-8367-4926-9999-514c35840399"); + + var sharingSettingRequest = getMockDataObject(SHARING_SETTING_REQUEST_SAMPLE_WITHOUT_PAYLOAD, SharingSettingRequest.class); + + when(consortiumRepository.existsById(consortiumId)).thenReturn(true); + when(sharingSettingRepository.existsBySettingId(settingId)).thenReturn(false); + + assertThrows(org.folio.consortia.exception.ResourceNotFoundException.class, () -> sharingSettingService.delete(consortiumId, settingId, sharingSettingRequest)); + verify(publicationService, times(0)).publishRequest(any(), any()); + } + public JsonNode createJsonNode() throws JsonProcessingException { Map payload = new HashMap<>(); payload.put("id", "1844767a-8367-4926-9999-514c35840399"); diff --git a/src/test/java/org/folio/consortia/utils/EntityUtils.java b/src/test/java/org/folio/consortia/utils/EntityUtils.java index 747adcd7..dbbfbc52 100644 --- a/src/test/java/org/folio/consortia/utils/EntityUtils.java +++ b/src/test/java/org/folio/consortia/utils/EntityUtils.java @@ -9,6 +9,7 @@ import org.folio.consortia.domain.dto.PublicationRequest; import org.folio.consortia.domain.dto.PublicationStatus; import org.folio.consortia.domain.dto.SharingInstance; +import org.folio.consortia.domain.dto.SharingSettingDeleteResponse; import org.folio.consortia.domain.dto.SharingSettingRequest; import org.folio.consortia.domain.dto.SharingSettingResponse; import org.folio.consortia.domain.dto.Tenant; @@ -22,6 +23,8 @@ import org.folio.consortia.domain.entity.SharingInstanceEntity; import org.folio.consortia.domain.entity.TenantEntity; import org.folio.consortia.domain.entity.UserTenantEntity; +import org.springframework.http.HttpMethod; +import org.testcontainers.shaded.org.apache.commons.lang3.ObjectUtils; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import com.fasterxml.jackson.databind.JsonNode; @@ -190,6 +193,10 @@ public static SharingSettingResponse createSharingSettingResponse(UUID createSet return new SharingSettingResponse().createSettingsPCId(createSettingsPcId).updateSettingsPCId(updateSettingsPcId); } + public static SharingSettingDeleteResponse createSharingSettingResponseForDelete(UUID pcId) { + return new SharingSettingDeleteResponse().pcId(pcId); + } + public static TenantCollection createTenantCollection(List tenants) { TenantCollection tenantCollection = new TenantCollection(); tenantCollection.setTenants(tenants); @@ -201,12 +208,15 @@ public static PublicationRequest createPublicationRequestForSetting(SharingSetti PublicationRequest publicationRequest = new PublicationRequest(); publicationRequest.setUrl(sharingSetting.getUrl()); publicationRequest.setMethod(method); - final ObjectMapper mapper = new ObjectMapper(); - final ObjectNode root = mapper.createObjectNode(); - root.set("id", mapper.convertValue("1844767a-8367-4926-9999-514c35840399", JsonNode.class)); - root.set("name", mapper.convertValue("ORG-NAME", JsonNode.class)); - root.set("source", mapper.convertValue("consortium", JsonNode.class)); - publicationRequest.setPayload(root); + // we don't need payload for delete request + if (ObjectUtils.notEqual(method, HttpMethod.DELETE.toString())) { + final ObjectMapper mapper = new ObjectMapper(); + final ObjectNode root = mapper.createObjectNode(); + root.set("id", mapper.convertValue("1844767a-8367-4926-9999-514c35840399", JsonNode.class)); + root.set("name", mapper.convertValue("ORG-NAME", JsonNode.class)); + root.set("source", mapper.convertValue("consortium", JsonNode.class)); + publicationRequest.setPayload(root); + } return publicationRequest; } diff --git a/src/test/resources/mockdata/sharing_setting_request_without_payload.json b/src/test/resources/mockdata/sharing_setting_request_without_payload.json new file mode 100644 index 00000000..030d82cc --- /dev/null +++ b/src/test/resources/mockdata/sharing_setting_request_without_payload.json @@ -0,0 +1,4 @@ +{ + "settingId": "1844767a-8367-4926-9999-514c35840399", + "url": "/organizations-storage/organizations" +}