diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController.java index 37c715a374..854404e541 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController.java @@ -36,6 +36,7 @@ import org.eclipse.edc.protocol.dsp.http.spi.message.DspRequestHandler; import org.eclipse.edc.protocol.dsp.http.spi.message.GetDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.PostDspRequest; +import org.eclipse.edc.protocol.dsp.spi.type.DspNamespace; import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; @@ -43,7 +44,8 @@ import static org.eclipse.edc.protocol.dsp.catalog.http.api.CatalogApiPaths.CATALOG_REQUEST; import static org.eclipse.edc.protocol.dsp.catalog.http.api.CatalogApiPaths.DATASET_REQUEST; import static org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP; -import static org.eclipse.edc.protocol.dsp.spi.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI; +import static org.eclipse.edc.protocol.dsp.spi.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_08; /** * Provides the HTTP endpoint for receiving catalog requests. @@ -57,16 +59,18 @@ public class DspCatalogApiController { private final DspRequestHandler dspRequestHandler; private final ContinuationTokenManager continuationTokenManager; private final String protocol; + private final DspNamespace namespace; public DspCatalogApiController(CatalogProtocolService service, DspRequestHandler dspRequestHandler, ContinuationTokenManager continuationTokenManager) { - this(service, dspRequestHandler, continuationTokenManager, DATASPACE_PROTOCOL_HTTP); + this(service, dspRequestHandler, continuationTokenManager, DATASPACE_PROTOCOL_HTTP, DSP_NAMESPACE_V_08); } - public DspCatalogApiController(CatalogProtocolService service, DspRequestHandler dspRequestHandler, ContinuationTokenManager continuationTokenManager, String protocol) { + public DspCatalogApiController(CatalogProtocolService service, DspRequestHandler dspRequestHandler, ContinuationTokenManager continuationTokenManager, String protocol, DspNamespace namespace) { this.service = service; this.dspRequestHandler = dspRequestHandler; this.continuationTokenManager = continuationTokenManager; this.protocol = protocol; + this.namespace = namespace; } @POST @@ -83,7 +87,7 @@ public Response requestCatalog(JsonObject jsonObject, @HeaderParam(AUTHORIZATION var request = PostDspRequest.Builder.newInstance(CatalogRequestMessage.class, Catalog.class, CatalogError.class) .token(token) - .expectedMessageType(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM)) .message(messageJson) .serviceCall(service::getCatalog) .errorProvider(CatalogError.Builder::newInstance) diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController20241.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController20241.java index 5d38042433..9544e08b9b 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController20241.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiController20241.java @@ -24,6 +24,7 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.edc.protocol.dsp.catalog.http.api.CatalogApiPaths.BASE_PATH; import static org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP_V_2024_1; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1; import static org.eclipse.edc.protocol.dsp.spi.version.DspVersions.V_2024_1_PATH; /** @@ -36,6 +37,6 @@ public class DspCatalogApiController20241 extends DspCatalogApiController { public DspCatalogApiController20241(CatalogProtocolService service, DspRequestHandler dspRequestHandler, ContinuationTokenManager responseDecorator) { - super(service, dspRequestHandler, responseDecorator, DATASPACE_PROTOCOL_HTTP_V_2024_1); + super(service, dspRequestHandler, responseDecorator, DATASPACE_PROTOCOL_HTTP_V_2024_1, DSP_NAMESPACE_V_2024_1); } } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiControllerTest.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiControllerTest.java index 47d2d8a532..554086b4f6 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiControllerTest.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-api/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/api/controller/DspCatalogApiControllerTest.java @@ -30,6 +30,7 @@ import org.eclipse.edc.protocol.dsp.http.spi.message.GetDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.PostDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.ResponseDecorator; +import org.eclipse.edc.protocol.dsp.spi.type.DspNamespace; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; @@ -47,7 +48,10 @@ import static org.eclipse.edc.protocol.dsp.catalog.http.api.CatalogApiPaths.BASE_PATH; import static org.eclipse.edc.protocol.dsp.catalog.http.api.CatalogApiPaths.CATALOG_REQUEST; import static org.eclipse.edc.protocol.dsp.catalog.http.api.CatalogApiPaths.DATASET_REQUEST; -import static org.eclipse.edc.protocol.dsp.spi.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI; +import static org.eclipse.edc.protocol.dsp.spi.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_08; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1; +import static org.eclipse.edc.protocol.dsp.spi.version.DspVersions.V_2024_1_PATH; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; @@ -56,115 +60,156 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -@ApiTest -class DspCatalogApiControllerTest extends RestControllerTestBase { - - private final TypeTransformerRegistry transformerRegistry = mock(); - private final CatalogProtocolService service = mock(); - private final DspRequestHandler dspRequestHandler = mock(); - private final ContinuationTokenManager continuationTokenManager = mock(); - - @Test - void getDataset_shouldGetResource() { - when(dspRequestHandler.getResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON).build()); - - baseRequest() - .get(DATASET_REQUEST + "/datasetId") - .then() - .statusCode(200) - .contentType(JSON); - - var captor = ArgumentCaptor.forClass(GetDspRequest.class); - verify(dspRequestHandler).getResource(captor.capture()); - var request = captor.getValue(); - assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getResultClass()).isEqualTo(Dataset.class); - assertThat(request.getId()).isEqualTo("datasetId"); - } - - @Override - protected Object controller() { - return new DspCatalogApiController(service, dspRequestHandler, continuationTokenManager); - } +class DspCatalogApiControllerTest { - private RequestSpecification baseRequest() { - return given() - .baseUri("http://localhost:" + port) - .basePath(BASE_PATH) - .header(HttpHeaders.AUTHORIZATION, "auth") - .when(); - } + abstract static class Tests extends RestControllerTestBase { - @Nested - class RequestCatalog { + protected final TypeTransformerRegistry transformerRegistry = mock(); + protected final CatalogProtocolService service = mock(); + protected final DspRequestHandler dspRequestHandler = mock(); + protected final ContinuationTokenManager continuationTokenManager = mock(); @Test - void shouldCreateResource() { - var requestBody = createObjectBuilder().add(TYPE, DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI).build(); - var catalog = createObjectBuilder().add(JsonLdKeywords.TYPE, "catalog").build(); - when(transformerRegistry.transform(any(Catalog.class), eq(JsonObject.class))).thenReturn(Result.success(catalog)); - when(dspRequestHandler.createResource(any(), any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - when(continuationTokenManager.createResponseDecorator(any())).thenReturn(mock()); + void getDataset_shouldGetResource() { + when(dspRequestHandler.getResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON).build()); baseRequest() - .contentType(JSON) - .body(requestBody) - .post(CATALOG_REQUEST) + .get(DATASET_REQUEST + "/datasetId") .then() .statusCode(200) .contentType(JSON); - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).createResource(captor.capture(), isA(ResponseDecorator.class)); + var captor = ArgumentCaptor.forClass(GetDspRequest.class); + verify(dspRequestHandler).getResource(captor.capture()); var request = captor.getValue(); - assertThat(request.getInputClass()).isEqualTo(CatalogRequestMessage.class); - assertThat(request.getResultClass()).isEqualTo(Catalog.class); - assertThat(request.getExpectedMessageType()).isEqualTo(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI); - assertThat(request.getProcessId()).isNull(); assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getMessage()).isEqualTo(requestBody); - verify(continuationTokenManager).createResponseDecorator("http://localhost:%d/catalog/request".formatted(port)); + assertThat(request.getResultClass()).isEqualTo(Dataset.class); + assertThat(request.getId()).isEqualTo("datasetId"); } - @Test - void shouldApplyContinuationToken_whenPassed() { - var requestBody = createObjectBuilder().add(TYPE, DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI).build(); - var catalog = createObjectBuilder().add(JsonLdKeywords.TYPE, "catalog").build(); - when(transformerRegistry.transform(any(Catalog.class), eq(JsonObject.class))).thenReturn(Result.success(catalog)); - when(dspRequestHandler.createResource(any(), any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - when(continuationTokenManager.createResponseDecorator(any())).thenReturn(mock()); - var enrichedRequestBody = createObjectBuilder(requestBody).add("query", Json.createObjectBuilder()).build(); - when(continuationTokenManager.applyQueryFromToken(any(), any())).thenReturn(Result.success(enrichedRequestBody)); - baseRequest() - .contentType(JSON) - .body(requestBody) - .post(CATALOG_REQUEST + "?continuationToken=pagination-token") - .then() - .statusCode(200) - .contentType(JSON); + protected abstract String basePath(); - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).createResource(captor.capture(), isA(ResponseDecorator.class)); - var request = captor.getValue(); - assertThat(request.getMessage()).isSameAs(enrichedRequestBody); - verify(continuationTokenManager).applyQueryFromToken(requestBody, "pagination-token"); + protected abstract DspNamespace namespace(); + + private RequestSpecification baseRequest() { + return given() + .baseUri("http://localhost:" + port) + .basePath(basePath()) + .header(HttpHeaders.AUTHORIZATION, "auth") + .when(); } - @Test - void shouldReturnBadRequest_whenContinuationTokenIsNotValid() { - var requestBody = createObjectBuilder().add(TYPE, DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_IRI).build(); - when(continuationTokenManager.applyQueryFromToken(any(), any())).thenReturn(Result.failure("error")); + @Nested + class RequestCatalog { + + @Test + void shouldCreateResource() { + var requestBody = createObjectBuilder().add(TYPE, namespace().toIri(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM)).build(); + var catalog = createObjectBuilder().add(JsonLdKeywords.TYPE, "catalog").build(); + when(transformerRegistry.transform(any(Catalog.class), eq(JsonObject.class))).thenReturn(Result.success(catalog)); + when(dspRequestHandler.createResource(any(), any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + when(continuationTokenManager.createResponseDecorator(any())).thenReturn(mock()); + + baseRequest() + .contentType(JSON) + .body(requestBody) + .post(CATALOG_REQUEST) + .then() + .statusCode(200) + .contentType(JSON); + + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).createResource(captor.capture(), isA(ResponseDecorator.class)); + var request = captor.getValue(); + assertThat(request.getInputClass()).isEqualTo(CatalogRequestMessage.class); + assertThat(request.getResultClass()).isEqualTo(Catalog.class); + assertThat(request.getExpectedMessageType()).isEqualTo(namespace().toIri(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM)); + assertThat(request.getProcessId()).isNull(); + assertThat(request.getToken()).isEqualTo("auth"); + assertThat(request.getMessage()).isEqualTo(requestBody); + verify(continuationTokenManager).createResponseDecorator("http://localhost:%d%s".formatted(port, basePath() + CATALOG_REQUEST)); + } + + @Test + void shouldApplyContinuationToken_whenPassed() { + var requestBody = createObjectBuilder().add(TYPE, namespace().toIri(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM)).build(); + var catalog = createObjectBuilder().add(JsonLdKeywords.TYPE, "catalog").build(); + when(transformerRegistry.transform(any(Catalog.class), eq(JsonObject.class))).thenReturn(Result.success(catalog)); + when(dspRequestHandler.createResource(any(), any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + when(continuationTokenManager.createResponseDecorator(any())).thenReturn(mock()); + var enrichedRequestBody = createObjectBuilder(requestBody).add("query", Json.createObjectBuilder()).build(); + when(continuationTokenManager.applyQueryFromToken(any(), any())).thenReturn(Result.success(enrichedRequestBody)); + + baseRequest() + .contentType(JSON) + .body(requestBody) + .post(CATALOG_REQUEST + "?continuationToken=pagination-token") + .then() + .statusCode(200) + .contentType(JSON); + + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).createResource(captor.capture(), isA(ResponseDecorator.class)); + var request = captor.getValue(); + assertThat(request.getMessage()).isSameAs(enrichedRequestBody); + verify(continuationTokenManager).applyQueryFromToken(requestBody, "pagination-token"); + } + + @Test + void shouldReturnBadRequest_whenContinuationTokenIsNotValid() { + var requestBody = createObjectBuilder().add(TYPE, namespace().toIri(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE_TERM)).build(); + when(continuationTokenManager.applyQueryFromToken(any(), any())).thenReturn(Result.failure("error")); + + baseRequest() + .contentType(JSON) + .body(requestBody) + .post(CATALOG_REQUEST + "?continuationToken=pagination-token") + .then() + .statusCode(400); + + verifyNoInteractions(dspRequestHandler, transformerRegistry); + } + } + } - baseRequest() - .contentType(JSON) - .body(requestBody) - .post(CATALOG_REQUEST + "?continuationToken=pagination-token") - .then() - .statusCode(400); + @ApiTest + @Nested + class DspCatalogApiControllerV08Test extends Tests { + + @Override + protected String basePath() { + return BASE_PATH; + } + + @Override + protected DspNamespace namespace() { + return DSP_NAMESPACE_V_08; + } - verifyNoInteractions(dspRequestHandler, transformerRegistry); + @Override + protected Object controller() { + return new DspCatalogApiController(service, dspRequestHandler, continuationTokenManager); } } + @ApiTest + @Nested + class DspCatalogApiControllerV20241Test extends Tests { + + @Override + protected String basePath() { + return V_2024_1_PATH + BASE_PATH; + } + + @Override + protected DspNamespace namespace() { + return DSP_NAMESPACE_V_2024_1; + } + + @Override + protected Object controller() { + return new DspCatalogApiController20241(service, dspRequestHandler, continuationTokenManager); + } + } } diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController.java index a4b9479224..57d0f47810 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController.java @@ -36,6 +36,7 @@ import org.eclipse.edc.protocol.dsp.http.spi.message.DspRequestHandler; import org.eclipse.edc.protocol.dsp.http.spi.message.GetDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.PostDspRequest; +import org.eclipse.edc.protocol.dsp.spi.type.DspNamespace; import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION; import static org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP; @@ -48,12 +49,13 @@ import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.INITIAL_CONTRACT_REQUEST; import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.TERMINATION; import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.VERIFICATION; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_08; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM; /** * Provides consumer and provider endpoints for the contract negotiation according to the http binding @@ -66,20 +68,23 @@ public class DspNegotiationApiController { private final DspRequestHandler dspRequestHandler; private final String protocol; + private final DspNamespace namespace; private final ContractNegotiationProtocolService protocolService; public DspNegotiationApiController(ContractNegotiationProtocolService protocolService, DspRequestHandler dspRequestHandler) { - this(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP); + this(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP, DSP_NAMESPACE_V_08); } public DspNegotiationApiController(ContractNegotiationProtocolService protocolService, DspRequestHandler dspRequestHandler, - String protocol) { + String protocol, + DspNamespace namespace) { this.protocolService = protocolService; this.dspRequestHandler = dspRequestHandler; this.protocol = protocol; + this.namespace = namespace; } /** @@ -112,7 +117,7 @@ public Response getNegotiation(@PathParam("id") String id, @HeaderParam(AUTHORIZ @Path(INITIAL_CONTRACT_REQUEST) public Response initialContractRequest(JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractRequestMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM)) .message(jsonObject) .token(token) .serviceCall(protocolService::notifyRequested) @@ -134,7 +139,7 @@ public Response initialContractRequest(JsonObject jsonObject, @HeaderParam(AUTHO @Path(INITIAL_CONTRACT_OFFER) public Response initialContractOffer(JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractOfferMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM)) .message(jsonObject) .token(token) .serviceCall(protocolService::notifyOffered) @@ -159,7 +164,7 @@ public Response contractRequest(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractRequestMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM)) .processId(id) .message(jsonObject) .token(token) @@ -185,7 +190,7 @@ public Response createEvent(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractNegotiationEventMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_TERM)) .processId(id) .message(jsonObject) .token(token) @@ -214,7 +219,7 @@ public Response verifyAgreement(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractAgreementVerificationMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_TERM)) .processId(id) .message(jsonObject) .token(token) @@ -240,7 +245,7 @@ public Response terminateNegotiation(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractNegotiationTerminationMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_TERM)) .processId(id) .message(jsonObject) .token(token) @@ -266,7 +271,7 @@ public Response providerOffer(@PathParam("id") String id, JsonObject body, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractOfferMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM)) .processId(id) .message(body) .token(token) @@ -292,7 +297,7 @@ public Response createAgreement(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(ContractAgreementMessage.class, ContractNegotiation.class, ContractNegotiationError.class) - .expectedMessageType(DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_TERM)) .processId(id) .message(jsonObject) .token(token) diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController20241.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController20241.java index 504dd95013..1e76520410 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController20241.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiController20241.java @@ -24,6 +24,7 @@ import static org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP_V_2024_1; import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.BASE_PATH; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1; /** * Versioned Negotiation endpoint, same as {@link DspNegotiationApiController} but exposed on the /2024/1 path @@ -34,6 +35,6 @@ public class DspNegotiationApiController20241 extends DspNegotiationApiController { public DspNegotiationApiController20241(ContractNegotiationProtocolService protocolService, DspRequestHandler dspRequestHandler) { - super(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP_V_2024_1); + super(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP_V_2024_1, DSP_NAMESPACE_V_2024_1); } } diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiControllerTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiControllerTest.java index 5d54785cd5..d405f400cd 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiControllerTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-api/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/http/api/controller/DspNegotiationApiControllerTest.java @@ -29,7 +29,9 @@ import org.eclipse.edc.protocol.dsp.http.spi.message.DspRequestHandler; import org.eclipse.edc.protocol.dsp.http.spi.message.GetDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.PostDspRequest; +import org.eclipse.edc.protocol.dsp.spi.type.DspNamespace; import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; @@ -54,167 +56,209 @@ import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.INITIAL_CONTRACT_REQUEST; import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.TERMINATION; import static org.eclipse.edc.protocol.dsp.negotiation.http.api.NegotiationApiPaths.VERIFICATION; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_08; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.version.DspVersions.V_2024_1_PATH; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -@ApiTest -class DspNegotiationApiControllerTest extends RestControllerTestBase { - - private final ContractNegotiationProtocolService protocolService = mock(); - private final DspRequestHandler dspRequestHandler = mock(); - - @Test - void getNegotiation_shouldGetResource() { - when(dspRequestHandler.getResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - - var result = baseRequest() - .get(BASE_PATH + "negotiationId") - .then() - .contentType(APPLICATION_JSON) - .statusCode(200); - - assertThat(result).isNotNull(); - var captor = ArgumentCaptor.forClass(GetDspRequest.class); - verify(dspRequestHandler).getResource(captor.capture()); - var dspMessage = captor.getValue(); - assertThat(dspMessage.getToken()).isEqualTo("auth"); - assertThat(dspMessage.getId()).isEqualTo("negotiationId"); - assertThat(dspMessage.getResultClass()).isEqualTo(ContractNegotiation.class); - } +class DspNegotiationApiControllerTest { - @Test - void initialContractRequest_shouldCreateResource() { - var requestBody = createObjectBuilder().add("@type", DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI).build(); - when(dspRequestHandler.createResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - - var result = baseRequest() - .contentType(APPLICATION_JSON) - .body(requestBody) - .post(BASE_PATH + INITIAL_CONTRACT_REQUEST) - .then() - .statusCode(200) - .contentType(APPLICATION_JSON); - - assertThat(result).isNotNull(); - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).createResource(captor.capture()); - var request = captor.getValue(); - assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getProcessId()).isEqualTo(null); - assertThat(request.getMessage()).isNotNull(); - assertThat(request.getInputClass()).isEqualTo(ContractRequestMessage.class); - assertThat(request.getResultClass()).isEqualTo(ContractNegotiation.class); - assertThat(request.getExpectedMessageType()).isEqualTo(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI); - } + abstract static class Tests extends RestControllerTestBase { - @Test - void initialContractOffer_shouldCreateResource() { - var requestBody = createObjectBuilder().add("@type", DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI).build(); - when(dspRequestHandler.createResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - - var result = baseRequest() - .contentType(APPLICATION_JSON) - .body(requestBody) - .post(BASE_PATH + INITIAL_CONTRACT_OFFER) - .then() - .statusCode(200) - .contentType(APPLICATION_JSON); - - assertThat(result).isNotNull(); - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).createResource(captor.capture()); - var request = captor.getValue(); - assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getProcessId()).isEqualTo(null); - assertThat(request.getMessage()).isNotNull(); - assertThat(request.getInputClass()).isEqualTo(ContractOfferMessage.class); - assertThat(request.getResultClass()).isEqualTo(ContractNegotiation.class); - assertThat(request.getExpectedMessageType()).isEqualTo(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI); - } + protected final ContractNegotiationProtocolService protocolService = mock(); + protected final DspRequestHandler dspRequestHandler = mock(); - /** - * Verifies that an endpoint returns 401 if the identity service cannot verify the identity token. - * - * @param path the request path to the endpoint - */ - @ParameterizedTest - @ArgumentsSource(ControllerMethodArguments.class) - void callEndpoint_shouldUpdateResource(String path, Class messageClass, String messageType) { - when(dspRequestHandler.updateResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - var requestBody = createObjectBuilder().add("http://schema/key", "value").build(); - - baseRequest() - .contentType(APPLICATION_JSON) - .body(requestBody) - .post(path) - .then() - .contentType(APPLICATION_JSON) - .statusCode(200); - - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).updateResource(captor.capture()); - var request = captor.getValue(); - assertThat(request.getExpectedMessageType()).isEqualTo(messageType); - assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getProcessId()).isEqualTo("testId"); - assertThat(request.getMessage()).isNotNull(); - assertThat(request.getInputClass()).isEqualTo(messageClass); - assertThat(request.getResultClass()).isEqualTo(ContractNegotiation.class); - assertThat(request.getExpectedMessageType()).isEqualTo(messageType); - } + @Test + void getNegotiation_shouldGetResource() { + when(dspRequestHandler.getResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - @Override - protected Object controller() { - return new DspNegotiationApiController(protocolService, dspRequestHandler); - } + var result = baseRequest() + .get(basePath() + "negotiationId") + .then() + .contentType(APPLICATION_JSON) + .statusCode(200); + + assertThat(result).isNotNull(); + var captor = ArgumentCaptor.forClass(GetDspRequest.class); + verify(dspRequestHandler).getResource(captor.capture()); + var dspMessage = captor.getValue(); + assertThat(dspMessage.getToken()).isEqualTo("auth"); + assertThat(dspMessage.getId()).isEqualTo("negotiationId"); + assertThat(dspMessage.getResultClass()).isEqualTo(ContractNegotiation.class); + } + + @Test + void initialContractRequest_shouldCreateResource() { + var requestBody = createObjectBuilder().add("@type", namespace().toIri(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM)).build(); + when(dspRequestHandler.createResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + + var result = baseRequest() + .contentType(APPLICATION_JSON) + .body(requestBody) + .post(basePath() + INITIAL_CONTRACT_REQUEST) + .then() + .statusCode(200) + .contentType(APPLICATION_JSON); + + assertThat(result).isNotNull(); + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).createResource(captor.capture()); + var request = captor.getValue(); + assertThat(request.getToken()).isEqualTo("auth"); + assertThat(request.getProcessId()).isEqualTo(null); + assertThat(request.getMessage()).isNotNull(); + assertThat(request.getInputClass()).isEqualTo(ContractRequestMessage.class); + assertThat(request.getResultClass()).isEqualTo(ContractNegotiation.class); + assertThat(request.getExpectedMessageType()).isEqualTo(namespace().toIri(DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM)); + } + + @Test + void initialContractOffer_shouldCreateResource() { + var requestBody = createObjectBuilder().add("@type", namespace().toIri(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM)).build(); + when(dspRequestHandler.createResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + + var result = baseRequest() + .contentType(APPLICATION_JSON) + .body(requestBody) + .post(basePath() + INITIAL_CONTRACT_OFFER) + .then() + .statusCode(200) + .contentType(APPLICATION_JSON); + + assertThat(result).isNotNull(); + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).createResource(captor.capture()); + var request = captor.getValue(); + assertThat(request.getToken()).isEqualTo("auth"); + assertThat(request.getProcessId()).isEqualTo(null); + assertThat(request.getMessage()).isNotNull(); + assertThat(request.getInputClass()).isEqualTo(ContractOfferMessage.class); + assertThat(request.getResultClass()).isEqualTo(ContractNegotiation.class); + assertThat(request.getExpectedMessageType()).isEqualTo(namespace().toIri(DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM)); + } + + /** + * Verifies that an endpoint returns 401 if the identity service cannot verify the identity token. + * + * @param path the request path to the endpoint + */ + @ParameterizedTest + @ArgumentsSource(ControllerMethodArguments.class) + void callEndpoint_shouldUpdateResource(String path, Class messageClass, String messageType) { + when(dspRequestHandler.updateResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + var requestBody = createObjectBuilder().add("http://schema/key", "value").build(); + + baseRequest() + .contentType(APPLICATION_JSON) + .body(requestBody) + .post(basePath() + path) + .then() + .contentType(APPLICATION_JSON) + .statusCode(200); + + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).updateResource(captor.capture()); + var request = captor.getValue(); + assertThat(request.getExpectedMessageType()).isEqualTo(namespace().toIri(messageType)); + assertThat(request.getToken()).isEqualTo("auth"); + assertThat(request.getProcessId()).isEqualTo("testId"); + assertThat(request.getMessage()).isNotNull(); + assertThat(request.getInputClass()).isEqualTo(messageClass); + assertThat(request.getResultClass()).isEqualTo(ContractNegotiation.class); + } + + protected abstract String basePath(); + + protected abstract DspNamespace namespace(); - private RequestSpecification baseRequest() { - var authHeader = "auth"; - return given() - .baseUri("http://localhost:" + port) - .basePath("/") - .header(HttpHeaders.AUTHORIZATION, authHeader) - .when(); + private RequestSpecification baseRequest() { + var authHeader = "auth"; + return given() + .baseUri("http://localhost:" + port) + .basePath("/") + .header(HttpHeaders.AUTHORIZATION, authHeader) + .when(); + } + + private static class ControllerMethodArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + Arguments.of( + "testId" + CONTRACT_REQUEST, + ContractRequestMessage.class, + DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_TERM), + Arguments.of( + "testId" + EVENT, + ContractNegotiationEventMessage.class, + DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_TERM), + Arguments.of( + "testId" + AGREEMENT + VERIFICATION, + ContractAgreementVerificationMessage.class, + DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_TERM), + Arguments.of( + "testId" + TERMINATION, + ContractNegotiationTerminationMessage.class, + DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_TERM), + Arguments.of( + "testId" + AGREEMENT, + ContractAgreementMessage.class, + DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_TERM), + Arguments.of( + "testId" + CONTRACT_OFFER, + ContractOfferMessage.class, + DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_TERM) + ); + } + } } - private static class ControllerMethodArguments implements ArgumentsProvider { + @ApiTest + @Nested + class DspNegotiationApiControllerV08Test extends Tests { + + @Override + protected String basePath() { + return BASE_PATH; + } + + @Override + protected DspNamespace namespace() { + return DSP_NAMESPACE_V_08; + } + @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of( - BASE_PATH + "testId" + CONTRACT_REQUEST, - ContractRequestMessage.class, - DSPACE_TYPE_CONTRACT_REQUEST_MESSAGE_IRI), - Arguments.of( - BASE_PATH + "testId" + EVENT, - ContractNegotiationEventMessage.class, - DSPACE_TYPE_CONTRACT_NEGOTIATION_EVENT_MESSAGE_IRI), - Arguments.of( - BASE_PATH + "testId" + AGREEMENT + VERIFICATION, - ContractAgreementVerificationMessage.class, - DSPACE_TYPE_CONTRACT_AGREEMENT_VERIFICATION_MESSAGE_IRI), - Arguments.of( - BASE_PATH + "testId" + TERMINATION, - ContractNegotiationTerminationMessage.class, - DSPACE_TYPE_CONTRACT_NEGOTIATION_TERMINATION_MESSAGE_IRI), - Arguments.of( - BASE_PATH + "testId" + AGREEMENT, - ContractAgreementMessage.class, - DSPACE_TYPE_CONTRACT_AGREEMENT_MESSAGE_IRI), - Arguments.of( - BASE_PATH + "testId" + CONTRACT_OFFER, - ContractOfferMessage.class, - DSPACE_TYPE_CONTRACT_OFFER_MESSAGE_IRI) - ); + protected Object controller() { + return new DspNegotiationApiController(protocolService, dspRequestHandler); } } + @ApiTest + @Nested + class DspNegotiationApiControllerV20241Test extends Tests { + + @Override + protected String basePath() { + return V_2024_1_PATH + BASE_PATH; + } + + @Override + protected DspNamespace namespace() { + return DSP_NAMESPACE_V_2024_1; + } + + @Override + protected Object controller() { + return new DspNegotiationApiController20241(protocolService, dspRequestHandler); + } + } } diff --git a/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspConstants.java b/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspConstants.java index 31f1e91f75..5211c4b532 100644 --- a/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspConstants.java +++ b/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspConstants.java @@ -14,6 +14,7 @@ package org.eclipse.edc.protocol.dsp.spi.type; +import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_SCHEMA; import static org.eclipse.edc.protocol.dsp.spi.version.DspVersions.V_08_VERSION; import static org.eclipse.edc.protocol.dsp.spi.version.DspVersions.V_2024_1_VERSION; @@ -27,4 +28,7 @@ public interface DspConstants { String DSP_TRANSFORMER_CONTEXT = "dsp-api"; String DSP_TRANSFORMER_CONTEXT_V_08 = DSP_TRANSFORMER_CONTEXT + DSP_CONTEXT_SEPARATOR + V_08_VERSION; String DSP_TRANSFORMER_CONTEXT_V_2024_1 = DSP_TRANSFORMER_CONTEXT + DSP_CONTEXT_SEPARATOR + V_2024_1_VERSION; + + DspNamespace DSP_NAMESPACE_V_08 = new DspNamespace(DSPACE_SCHEMA); + DspNamespace DSP_NAMESPACE_V_2024_1 = new DspNamespace(DSPACE_SCHEMA); } diff --git a/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspNamespace.java b/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspNamespace.java new file mode 100644 index 0000000000..398d46f368 --- /dev/null +++ b/data-protocols/dsp/dsp-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/type/DspNamespace.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.protocol.dsp.spi.type; + +/** + * Represents a namespace for DSP terms. + */ +public record DspNamespace(String namespace) { + + /** + * Converts a given term to its IRI (Internationalized Resource Identifier) by appending it to the namespace. + * + * @param term the term to be converted to an IRI. + * @return the IRI as a string. + */ + public String toIri(String term) { + return namespace + term; + } +} diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController.java index fc6c0b0e91..9aff46f898 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController.java @@ -35,14 +35,16 @@ import org.eclipse.edc.protocol.dsp.http.spi.message.DspRequestHandler; import org.eclipse.edc.protocol.dsp.http.spi.message.GetDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.PostDspRequest; +import org.eclipse.edc.protocol.dsp.spi.type.DspNamespace; import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION; import static org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_START_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_IRI; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_08; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_START_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_TERM; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.BASE_PATH; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.TRANSFER_COMPLETION; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.TRANSFER_INITIAL_REQUEST; @@ -62,15 +64,17 @@ public class DspTransferProcessApiController { private final TransferProcessProtocolService protocolService; private final DspRequestHandler dspRequestHandler; private final String protocol; + private final DspNamespace namespace; public DspTransferProcessApiController(TransferProcessProtocolService protocolService, DspRequestHandler dspRequestHandler) { - this(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP); + this(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP, DSP_NAMESPACE_V_08); } - public DspTransferProcessApiController(TransferProcessProtocolService protocolService, DspRequestHandler dspRequestHandler, String protocol) { + public DspTransferProcessApiController(TransferProcessProtocolService protocolService, DspRequestHandler dspRequestHandler, String protocol, DspNamespace namespace) { this.protocolService = protocolService; this.dspRequestHandler = dspRequestHandler; this.protocol = protocol; + this.namespace = namespace; } /** @@ -106,7 +110,7 @@ public Response initiateTransferProcess(JsonObject jsonObject, @HeaderParam(AUTH var request = PostDspRequest.Builder.newInstance(TransferRequestMessage.class, TransferProcess.class, TransferError.class) .message(jsonObject) .token(token) - .expectedMessageType(DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_TERM)) .serviceCall(protocolService::notifyRequested) .errorProvider(TransferError.Builder::newInstance) .protocol(protocol) @@ -128,7 +132,7 @@ public Response initiateTransferProcess(JsonObject jsonObject, @HeaderParam(AUTH public Response transferProcessStart(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(TransferStartMessage.class, TransferProcess.class, TransferError.class) .processId(id) - .expectedMessageType(DSPACE_TYPE_TRANSFER_START_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_TRANSFER_START_MESSAGE_TERM)) .message(jsonObject) .token(token) .serviceCall(protocolService::notifyStarted) @@ -152,7 +156,7 @@ public Response transferProcessStart(@PathParam("id") String id, JsonObject json public Response transferProcessCompletion(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(TransferCompletionMessage.class, TransferProcess.class, TransferError.class) .processId(id) - .expectedMessageType(DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_TERM)) .message(jsonObject) .token(token) .serviceCall(protocolService::notifyCompleted) @@ -176,7 +180,7 @@ public Response transferProcessCompletion(@PathParam("id") String id, JsonObject public Response transferProcessTermination(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(TransferTerminationMessage.class, TransferProcess.class, TransferError.class) .processId(id) - .expectedMessageType(DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_TERM)) .message(jsonObject) .token(token) .serviceCall(protocolService::notifyTerminated) @@ -200,7 +204,7 @@ public Response transferProcessTermination(@PathParam("id") String id, JsonObjec public Response transferProcessSuspension(@PathParam("id") String id, JsonObject jsonObject, @HeaderParam(AUTHORIZATION) String token) { var request = PostDspRequest.Builder.newInstance(TransferSuspensionMessage.class, TransferProcess.class, TransferError.class) .processId(id) - .expectedMessageType(DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_IRI) + .expectedMessageType(namespace.toIri(DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_TERM)) .message(jsonObject) .token(token) .serviceCall(protocolService::notifySuspended) diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController20241.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController20241.java index 49dd29dbd9..0f257c425a 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController20241.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiController20241.java @@ -23,6 +23,7 @@ import org.eclipse.edc.protocol.dsp.spi.version.DspVersions; import static org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP_V_2024_1; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.BASE_PATH; @@ -35,6 +36,6 @@ public class DspTransferProcessApiController20241 extends DspTransferProcessApiController { public DspTransferProcessApiController20241(TransferProcessProtocolService protocolService, DspRequestHandler dspRequestHandler) { - super(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP_V_2024_1); + super(protocolService, dspRequestHandler, DATASPACE_PROTOCOL_HTTP_V_2024_1, DSP_NAMESPACE_V_2024_1); } } diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiControllerTest.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiControllerTest.java index 5dd71432e3..ae08d03ce0 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiControllerTest.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-api/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/http/api/controller/DspTransferProcessApiControllerTest.java @@ -30,7 +30,9 @@ import org.eclipse.edc.protocol.dsp.http.spi.message.DspRequestHandler; import org.eclipse.edc.protocol.dsp.http.spi.message.GetDspRequest; import org.eclipse.edc.protocol.dsp.http.spi.message.PostDspRequest; +import org.eclipse.edc.protocol.dsp.spi.type.DspNamespace; import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; @@ -46,11 +48,14 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_START_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_IRI; -import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_IRI; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_08; +import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_START_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.type.DspTransferProcessPropertyAndTypeNames.DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_TERM; +import static org.eclipse.edc.protocol.dsp.spi.version.DspVersions.V_2024_1_PATH; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.BASE_PATH; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.TRANSFER_COMPLETION; import static org.eclipse.edc.protocol.dsp.transferprocess.http.api.TransferProcessApiPaths.TRANSFER_INITIAL_REQUEST; @@ -63,121 +68,163 @@ import static org.mockito.Mockito.when; @ApiTest -class DspTransferProcessApiControllerTest extends RestControllerTestBase { - - private static final String PROCESS_ID = "testId"; - private final TransferProcessProtocolService protocolService = mock(); - private final DspRequestHandler dspRequestHandler = mock(); - - @Test - void getTransferProcess_shouldGetResource() { - var id = "transferProcessId"; - - when(dspRequestHandler.getResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - - baseRequest() - .get(BASE_PATH + id) - .then() - .contentType(MediaType.APPLICATION_JSON) - .statusCode(200); - - var captor = ArgumentCaptor.forClass(GetDspRequest.class); - verify(dspRequestHandler).getResource(captor.capture()); - var dspRequest = captor.getValue(); - assertThat(dspRequest.getId()).isEqualTo("transferProcessId"); - assertThat(dspRequest.getResultClass()).isEqualTo(TransferProcess.class); - assertThat(dspRequest.getToken()).isEqualTo("auth"); - } +class DspTransferProcessApiControllerTest { - @Test - void initiateTransferProcess_shouldCreateResource() { - when(dspRequestHandler.createResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - - var result = baseRequest() - .contentType(MediaType.APPLICATION_JSON) - .body(Json.createObjectBuilder().add(TYPE, DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_IRI).build()) - .post(BASE_PATH + TRANSFER_INITIAL_REQUEST) - .then() - .statusCode(200) - .contentType(MediaType.APPLICATION_JSON); - - assertThat(result).isNotNull(); - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).createResource(captor.capture()); - var request = captor.getValue(); - assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getProcessId()).isEqualTo(null); - assertThat(request.getInputClass()).isEqualTo(TransferRequestMessage.class); - assertThat(request.getResultClass()).isEqualTo(TransferProcess.class); - assertThat(request.getMessage()).isNotNull(); - assertThat(request.getExpectedMessageType()).isEqualTo(DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_IRI); - } + abstract static class Tests extends RestControllerTestBase { - /** - * Verifies that an endpoint returns 401 if the identity service cannot verify the identity token. - * - * @param path the request path to the endpoint - */ - @ParameterizedTest - @ArgumentsSource(ControllerMethodArguments.class) - void callEndpoint_shouldUpdateResource(String path, Class messageClass, String messageType) { - when(dspRequestHandler.updateResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); - var requestBody = createObjectBuilder().add("http://schema/key", "value").build(); - - baseRequest() - .contentType(MediaType.APPLICATION_JSON) - .body(requestBody) - .post(path) - .then() - .contentType(MediaType.APPLICATION_JSON) - .statusCode(200); - - var captor = ArgumentCaptor.forClass(PostDspRequest.class); - verify(dspRequestHandler).updateResource(captor.capture()); - var request = captor.getValue(); - assertThat(request.getToken()).isEqualTo("auth"); - assertThat(request.getProcessId()).isEqualTo(PROCESS_ID); - assertThat(request.getMessage()).isNotNull(); - assertThat(request.getInputClass()).isEqualTo(messageClass); - assertThat(request.getResultClass()).isEqualTo(TransferProcess.class); - assertThat(request.getExpectedMessageType()).isEqualTo(messageType); - } + private static final String PROCESS_ID = "testId"; + protected final TransferProcessProtocolService protocolService = mock(); + protected final DspRequestHandler dspRequestHandler = mock(); - @Override - protected Object controller() { - return new DspTransferProcessApiController(protocolService, dspRequestHandler); - } + @Test + void getTransferProcess_shouldGetResource() { + var id = "transferProcessId"; + + when(dspRequestHandler.getResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + + baseRequest() + .get(basePath() + id) + .then() + .contentType(MediaType.APPLICATION_JSON) + .statusCode(200); + + var captor = ArgumentCaptor.forClass(GetDspRequest.class); + verify(dspRequestHandler).getResource(captor.capture()); + var dspRequest = captor.getValue(); + assertThat(dspRequest.getId()).isEqualTo("transferProcessId"); + assertThat(dspRequest.getResultClass()).isEqualTo(TransferProcess.class); + assertThat(dspRequest.getToken()).isEqualTo("auth"); + } + + @Test + void initiateTransferProcess_shouldCreateResource() { + when(dspRequestHandler.createResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + + var result = baseRequest() + .contentType(MediaType.APPLICATION_JSON) + .body(Json.createObjectBuilder().add(TYPE, namespace().toIri(DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_TERM)).build()) + .post(basePath() + TRANSFER_INITIAL_REQUEST) + .then() + .statusCode(200) + .contentType(MediaType.APPLICATION_JSON); + + assertThat(result).isNotNull(); + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).createResource(captor.capture()); + var request = captor.getValue(); + assertThat(request.getToken()).isEqualTo("auth"); + assertThat(request.getProcessId()).isEqualTo(null); + assertThat(request.getInputClass()).isEqualTo(TransferRequestMessage.class); + assertThat(request.getResultClass()).isEqualTo(TransferProcess.class); + assertThat(request.getMessage()).isNotNull(); + assertThat(request.getExpectedMessageType()).isEqualTo(namespace().toIri(DSPACE_TYPE_TRANSFER_REQUEST_MESSAGE_TERM)); + } + + /** + * Verifies that an endpoint returns 401 if the identity service cannot verify the identity token. + * + * @param path the request path to the endpoint + */ + @ParameterizedTest + @ArgumentsSource(ControllerMethodArguments.class) + void callEndpoint_shouldUpdateResource(String path, Class messageClass, String messageType) { + when(dspRequestHandler.updateResource(any())).thenReturn(Response.ok().type(APPLICATION_JSON_TYPE).build()); + var requestBody = createObjectBuilder().add("http://schema/key", "value").build(); + + baseRequest() + .contentType(MediaType.APPLICATION_JSON) + .body(requestBody) + .post(basePath() + path) + .then() + .contentType(MediaType.APPLICATION_JSON) + .statusCode(200); + + var captor = ArgumentCaptor.forClass(PostDspRequest.class); + verify(dspRequestHandler).updateResource(captor.capture()); + var request = captor.getValue(); + assertThat(request.getToken()).isEqualTo("auth"); + assertThat(request.getProcessId()).isEqualTo(PROCESS_ID); + assertThat(request.getMessage()).isNotNull(); + assertThat(request.getInputClass()).isEqualTo(messageClass); + assertThat(request.getResultClass()).isEqualTo(TransferProcess.class); + assertThat(request.getExpectedMessageType()).isEqualTo(namespace().toIri(messageType)); + } + + protected abstract String basePath(); + + protected abstract DspNamespace namespace(); + + private RequestSpecification baseRequest() { + return given() + .baseUri("http://localhost:" + port) + .basePath("/") + .header(HttpHeaders.AUTHORIZATION, "auth") + .when(); + } + + private static class ControllerMethodArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + Arguments.of( + PROCESS_ID + TRANSFER_START, + TransferStartMessage.class, + DSPACE_TYPE_TRANSFER_START_MESSAGE_TERM), + Arguments.of( + PROCESS_ID + TRANSFER_COMPLETION, + TransferCompletionMessage.class, + DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_TERM), + Arguments.of( + PROCESS_ID + TRANSFER_SUSPENSION, + TransferSuspensionMessage.class, + DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_TERM), + Arguments.of( + PROCESS_ID + TRANSFER_TERMINATION, + TransferTerminationMessage.class, + DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_TERM) + ); + } + } - private RequestSpecification baseRequest() { - return given() - .baseUri("http://localhost:" + port) - .basePath("/") - .header(HttpHeaders.AUTHORIZATION, "auth") - .when(); } - private static class ControllerMethodArguments implements ArgumentsProvider { + @ApiTest + @Nested + class DspTransferProcessApiControllerV08Test extends Tests { + @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of( - BASE_PATH + PROCESS_ID + TRANSFER_START, - TransferStartMessage.class, - DSPACE_TYPE_TRANSFER_START_MESSAGE_IRI), - Arguments.of( - BASE_PATH + PROCESS_ID + TRANSFER_COMPLETION, - TransferCompletionMessage.class, - DSPACE_TYPE_TRANSFER_COMPLETION_MESSAGE_IRI), - Arguments.of( - BASE_PATH + PROCESS_ID + TRANSFER_SUSPENSION, - TransferSuspensionMessage.class, - DSPACE_TYPE_TRANSFER_SUSPENSION_MESSAGE_IRI), - Arguments.of( - BASE_PATH + PROCESS_ID + TRANSFER_TERMINATION, - TransferTerminationMessage.class, - DSPACE_TYPE_TRANSFER_TERMINATION_MESSAGE_IRI) - ); + protected String basePath() { + return BASE_PATH; + } + + @Override + protected DspNamespace namespace() { + return DSP_NAMESPACE_V_08; + } + + @Override + protected Object controller() { + return new DspTransferProcessApiController(protocolService, dspRequestHandler); } } + @ApiTest + @Nested + class DspTransferProcessControllerV20241Test extends Tests { + + @Override + protected String basePath() { + return V_2024_1_PATH + BASE_PATH; + } + + @Override + protected DspNamespace namespace() { + return DSP_NAMESPACE_V_2024_1; + } + + @Override + protected Object controller() { + return new DspTransferProcessApiController20241(protocolService, dspRequestHandler); + } + } }