From f97ae44334790ec58096cd5bd5faaae1ab5b5d7f Mon Sep 17 00:00:00 2001 From: ds-lcapellino Date: Thu, 11 Jul 2024 16:05:42 +0200 Subject: [PATCH] feature: eclipse-tractusx/traceability-foss#1190 add getContractDefinition and deleteContractDefinition functionality --- CHANGELOG.md | 3 + .../edc/client/asset/model/EdcContext.java | 10 +++ ...equest.java => EdcContractDefinition.java} | 12 ++- .../model/EdcContractDefinitionCriteria.java | 6 ++ .../service/EdcContractDefinitionService.java | 38 ++++++--- .../EdcContractDefinitionServiceTest.java | 84 +++++++++++++++++-- 6 files changed, 133 insertions(+), 20 deletions(-) rename irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/{EdcCreateContractDefinitionRequest.java => EdcContractDefinition.java} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c60e6333..98db997589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ _**For better traceability add the corresponding GitHub issue number in each cha ### Added +- Added get and delete functionality for contract definitions eclipse-tractusx/traceability-foss#1190 + ### Fixed - Access and Usage Policy Validation flow correction. #757 @@ -19,6 +21,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha ### Changed - Replaced technical error message when trying to delete the configured default policy with a user-friendly message. +- Renamed EdcCreateContractDefinitionRequest to EdcContractDefinition because it's used for both get and post eclipse-tractusx/traceability-foss#1190 ## [5.2.0] - 2024-07-03 diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/asset/model/EdcContext.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/asset/model/EdcContext.java index 119678c256..b65e2c0d8d 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/asset/model/EdcContext.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/asset/model/EdcContext.java @@ -19,8 +19,13 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.edc.client.asset.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.ToString; import lombok.extern.jackson.Jacksonized; @@ -30,7 +35,12 @@ @ToString @Builder +@AllArgsConstructor @Jacksonized +@JsonIgnoreProperties(ignoreUnknown = true) +@NoArgsConstructor +@Getter +@Setter public class EdcContext { @JsonProperty("edc") private String edc; diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcCreateContractDefinitionRequest.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinition.java similarity index 85% rename from irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcCreateContractDefinitionRequest.java rename to irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinition.java index 646105cf56..5a33d51e79 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcCreateContractDefinitionRequest.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinition.java @@ -20,17 +20,25 @@ package org.eclipse.tractusx.irs.edc.client.contract.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.ToString; import org.eclipse.tractusx.irs.edc.client.asset.model.EdcContext; /** - * EdcCreateContractDefinitionRequest used for creation of contract + * EdcCreateContractDefinitionRequest used for creating and receiving contract definitions */ @ToString @Builder -public class EdcCreateContractDefinitionRequest { +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class EdcContractDefinition { @JsonProperty("@context") private EdcContext edcContext; diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinitionCriteria.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinitionCriteria.java index e8376de8ee..95f78d9dcd 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinitionCriteria.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/model/EdcContractDefinitionCriteria.java @@ -20,8 +20,11 @@ package org.eclipse.tractusx.irs.edc.client.contract.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.ToString; /** @@ -31,6 +34,9 @@ @ToString @Getter @Builder +@AllArgsConstructor +@NoArgsConstructor +@Setter public class EdcContractDefinitionCriteria { @JsonProperty("@type") diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionService.java index 646df1633a..693894f62d 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionService.java @@ -21,16 +21,21 @@ import static org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration.NAMESPACE_EDC; +import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.tractusx.irs.edc.client.EdcConfiguration; import org.eclipse.tractusx.irs.edc.client.asset.model.EdcContext; +import org.eclipse.tractusx.irs.edc.client.contract.model.EdcContractDefinition; import org.eclipse.tractusx.irs.edc.client.contract.model.EdcContractDefinitionCriteria; -import org.eclipse.tractusx.irs.edc.client.contract.model.EdcCreateContractDefinitionRequest; import org.eclipse.tractusx.irs.edc.client.contract.model.exception.CreateEdcContractDefinitionException; import org.eclipse.tractusx.irs.edc.client.contract.model.exception.EdcContractDefinitionAlreadyExists; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; @@ -56,7 +61,7 @@ public class EdcContractDefinitionService { public String createContractDefinition(final String assetId, final String policyId) throws CreateEdcContractDefinitionException { final String contractId = UUID.randomUUID().toString(); - final EdcCreateContractDefinitionRequest createContractDefinitionRequest = createContractDefinitionRequest( + final EdcContractDefinition createContractDefinitionRequest = createContractDefinitionRequest( assetId, policyId, contractId); final ResponseEntity createContractDefinitionResponse; try { @@ -85,7 +90,7 @@ public String createContractDefinition(final String assetId, final String policy } - public EdcCreateContractDefinitionRequest createContractDefinitionRequest(final String assetId, + public EdcContractDefinition createContractDefinitionRequest(final String assetId, final String accessPolicyId, final String contractId) { final EdcContractDefinitionCriteria edcContractDefinitionCriteria = EdcContractDefinitionCriteria.builder() .type(ASSET_SELECTOR_TYPE) @@ -98,13 +103,24 @@ public EdcCreateContractDefinitionRequest createContractDefinitionRequest(final .build(); final EdcContext edcContext = EdcContext.builder().edc(NAMESPACE_EDC).build(); - return EdcCreateContractDefinitionRequest.builder() - .contractPolicyId(accessPolicyId) - .edcContext(edcContext) - .type(CONTRACT_DEFINITION_TYPE) - .accessPolicyId(accessPolicyId) - .contractDefinitionId(contractId) - .assetsSelector(edcContractDefinitionCriteria) - .build(); + return EdcContractDefinition.builder() + .contractPolicyId(accessPolicyId) + .edcContext(edcContext) + .type(CONTRACT_DEFINITION_TYPE) + .accessPolicyId(accessPolicyId) + .contractDefinitionId(contractId) + .assetsSelector(edcContractDefinitionCriteria) + .build(); + } + + public ResponseEntity> getContractDefinitions(final QuerySpec querySpec) { + return restTemplate.exchange(config.getControlplane().getEndpoint().getContractDefinition() + "/request", + HttpMethod.POST, new HttpEntity<>(querySpec), new ParameterizedTypeReference<>() { + }); + } + + public void deleteContractDefinition(final String contractDefinitionId) { + restTemplate.delete(config.getControlplane().getEndpoint().getContractDefinition() + "/{contractDefinitionId}", + contractDefinitionId); } } diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionServiceTest.java index 7fc5545e76..d2d194c322 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/contract/service/EdcContractDefinitionServiceTest.java @@ -22,10 +22,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; +import java.io.IOException; +import java.util.List; +import java.util.Optional; + +import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.tractusx.irs.edc.client.EdcConfiguration; -import org.eclipse.tractusx.irs.edc.client.contract.model.EdcCreateContractDefinitionRequest; +import org.eclipse.tractusx.irs.edc.client.contract.model.EdcContractDefinition; import org.eclipse.tractusx.irs.edc.client.contract.model.exception.CreateEdcContractDefinitionException; import org.eclipse.tractusx.irs.edc.client.contract.model.exception.EdcContractDefinitionAlreadyExists; import org.json.JSONException; @@ -33,15 +39,18 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.testcontainers.shaded.com.fasterxml.jackson.core.JsonProcessingException; import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.type.TypeFactory; @ExtendWith(MockitoExtension.class) class EdcContractDefinitionServiceTest { @@ -71,7 +80,7 @@ void testCreateContractDefinition() throws JsonProcessingException, JSONExceptio String contractId = "ContractId1"; // when - EdcCreateContractDefinitionRequest request = service.createContractDefinitionRequest(assetId, policyId, + EdcContractDefinition request = service.createContractDefinitionRequest(assetId, policyId, contractId); // then @@ -102,7 +111,7 @@ void givenCreateContractDefinition_whenOK_thenReturnPolicyId() throws CreateEdcC when(endpointConfig.getContractDefinition()).thenReturn("/management/v2/contractdefinitions"); String assetId = "Asset1"; String policyId = "Policy1"; - when(restTemplate.postForEntity(any(String.class), any(EdcCreateContractDefinitionRequest.class), + when(restTemplate.postForEntity(any(String.class), any(EdcContractDefinition.class), any())).thenReturn(ResponseEntity.ok("test")); String result = service.createContractDefinition(assetId, policyId); @@ -118,7 +127,7 @@ void givenCreateContractDefinition_whenConflict_thenThrowException() throws Crea when(endpointConfig.getContractDefinition()).thenReturn("/management/v2/contractdefinitions"); final String assetId = "Asset1"; final String policyId = "Policy1"; - when(restTemplate.postForEntity(any(String.class), any(EdcCreateContractDefinitionRequest.class), + when(restTemplate.postForEntity(any(String.class), any(EdcContractDefinition.class), any())).thenThrow( HttpClientErrorException.create("Surprise", HttpStatus.CONFLICT, "", null, null, null)); @@ -134,7 +143,7 @@ void givenCreateContractDefinition_whenBadRequest_thenThrowException() { when(endpointConfig.getContractDefinition()).thenReturn("/management/v2/contractdefinitions"); String assetId = "Asset1"; String policyId = "Policy1"; - when(restTemplate.postForEntity(any(String.class), any(EdcCreateContractDefinitionRequest.class), + when(restTemplate.postForEntity(any(String.class), any(EdcContractDefinition.class), any())).thenReturn(ResponseEntity.status(HttpStatus.BAD_REQUEST.value()).build()); assertThrows(CreateEdcContractDefinitionException.class, @@ -149,11 +158,72 @@ void givenCreateContractDefinition_whenRestClientException_thenThrowException() when(endpointConfig.getContractDefinition()).thenReturn("/management/v2/contractdefinitions"); String assetId = "Asset1"; String policyId = "Policy1"; - when(restTemplate.postForEntity(any(String.class), any(EdcCreateContractDefinitionRequest.class), + when(restTemplate.postForEntity(any(String.class), any(EdcContractDefinition.class), any())).thenThrow( HttpClientErrorException.create("Surprise", HttpStatus.INTERNAL_SERVER_ERROR, "", null, null, null)); assertThrows(CreateEdcContractDefinitionException.class, () -> service.createContractDefinition(assetId, policyId)); } + @Test + void givenGetContractDefinitions_thenReturnContractDefinitions() { + // given + when(edcConfiguration.getControlplane()).thenReturn(controlplaneConfig); + when(controlplaneConfig.getEndpoint()).thenReturn(endpointConfig); + when(endpointConfig.getContractDefinition()).thenReturn("/management/v2/contractdefinitions"); + when(restTemplate.exchange(any(String.class), any(HttpMethod.class), + any(), any(ParameterizedTypeReference.class))).thenReturn(ResponseEntity.of( + Optional.of(List.of(EdcContractDefinition.builder().accessPolicyId("").contractPolicyId("").build())))); + + //when + final ResponseEntity> contractDefinitions = service.getContractDefinitions( + new QuerySpec()); + //then + assertThat(contractDefinitions.getBody()).isNotEmpty(); + + } + + @Test + void givenDeleteContractDefinition_thenCallDeletionEndpoint() { + // given + when(edcConfiguration.getControlplane()).thenReturn(controlplaneConfig); + when(controlplaneConfig.getEndpoint()).thenReturn(endpointConfig); + when(endpointConfig.getContractDefinition()).thenReturn("/management/v2/contractdefinitions"); + + //when + service.deleteContractDefinition(""); + + //then + Mockito.verify(restTemplate).delete(anyString(), anyString()); + + } + + @Test + void testCreateContractDefinitionResponse() throws IOException, JSONException { + //GIVEN + String jsonResponse = """ + [ + { + "@id": "d355a2d5-bb3c-4fb1-b7a5-efa94f48ce73", + "@type": "ContractDefinition", + "accessPolicyId": "default-policy", + "contractPolicyId": "default-policy", + "assetsSelector": { + "@type": "Criterion", + "operandLeft": "https://w3id.org/edc/v0.0.1/ns/id", + "operator": "=", + "operandRight": "02d6977e-b71c-4873-9294-a9a15e05abb7" + }, + "@context": { + "edc": "https://w3id.org/edc/v0.0.1/ns/" + } + } + ] + """; + //WHEN + List responseObj = objectMapper.readValue(jsonResponse, TypeFactory.defaultInstance().constructCollectionType(List.class, EdcContractDefinition.class)); + + //THEN + JSONAssert.assertEquals(jsonResponse, objectMapper.writeValueAsString(responseObj), false); + } }