diff --git a/extensions/data-plane/data-plane-public-api-v2/src/main/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2Controller.java b/extensions/data-plane/data-plane-public-api-v2/src/main/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2Controller.java index 5a3e47b6abc..c54e8b54e09 100644 --- a/extensions/data-plane/data-plane-public-api-v2/src/main/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2Controller.java +++ b/extensions/data-plane/data-plane-public-api-v2/src/main/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2Controller.java @@ -66,8 +66,8 @@ public DataPlanePublicApiV2Controller(PipelineService pipelineService, this.executorService = executorService; } - private static Response error(Response.Status status, String error) { - return status(status).type(APPLICATION_JSON).entity(new TransferErrorResponse(List.of(error))).build(); + private static Response error(Response.Status status, List errors) { + return status(status).type(APPLICATION_JSON).entity(new TransferErrorResponse(errors)).build(); } @GET @@ -135,13 +135,13 @@ private void handle(ContainerRequestContext requestContext, AsyncResponse respon var token = contextApi.headers().get(HttpHeaders.AUTHORIZATION); if (token == null) { - response.resume(error(UNAUTHORIZED, "Missing Authorization Header")); + response.resume(error(UNAUTHORIZED, List.of("Missing Authorization Header"))); return; } var sourceDataAddress = authorizationService.authorize(token, buildRequestData(requestContext)); if (sourceDataAddress.failed()) { - response.resume(error(FORBIDDEN, sourceDataAddress.getFailureDetail())); + response.resume(error(FORBIDDEN, sourceDataAddress.getFailureMessages())); return; } @@ -173,11 +173,11 @@ private void processRequest(DataFlowStartMessage dataFlowStartMessage, AsyncResp .whenComplete((result, throwable) -> { if (throwable == null) { if (result.failed()) { - response.resume(error(INTERNAL_SERVER_ERROR, result.getFailureDetail())); + response.resume(error(INTERNAL_SERVER_ERROR, result.getFailureMessages())); } } else { var error = "Unhandled exception occurred during data transfer: " + throwable.getMessage(); - response.resume(error(INTERNAL_SERVER_ERROR, error)); + response.resume(error(INTERNAL_SERVER_ERROR, List.of(error))); } }); } diff --git a/extensions/data-plane/data-plane-public-api-v2/src/test/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2ControllerTest.java b/extensions/data-plane/data-plane-public-api-v2/src/test/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2ControllerTest.java index 32b4cdb6f4b..0e40d353ce7 100644 --- a/extensions/data-plane/data-plane-public-api-v2/src/test/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2ControllerTest.java +++ b/extensions/data-plane/data-plane-public-api-v2/src/test/java/org/eclipse/edc/connector/dataplane/api/controller/DataPlanePublicApiV2ControllerTest.java @@ -20,6 +20,7 @@ import org.eclipse.edc.connector.dataplane.spi.iam.DataPlaneAuthorizationService; import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSource; import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; +import org.eclipse.edc.connector.dataplane.spi.pipeline.StreamFailure; import org.eclipse.edc.connector.dataplane.spi.pipeline.StreamResult; import org.eclipse.edc.connector.dataplane.spi.resolver.DataAddressResolver; import org.eclipse.edc.connector.dataplane.util.sink.AsyncStreamingDataSink; @@ -34,6 +35,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -45,9 +47,10 @@ import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.failedFuture; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.connector.dataplane.spi.pipeline.StreamFailure.Reason.GENERAL_ERROR; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.isA; import static org.hamcrest.CoreMatchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; @@ -117,7 +120,33 @@ void should_returnInternalServerError_if_transferFails() { .then() .statusCode(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) .contentType(JSON) - .body("errors[0]", is(GENERAL_ERROR + ": " + errorMsg)); + .body("errors[0]", is(errorMsg)); + } + + @Test + void should_returnListOfErrorsAsResponse_if_anythingFails() { + var token = UUID.randomUUID().toString(); + var firstErrorMsg = UUID.randomUUID().toString(); + var secondErrorMsg = UUID.randomUUID().toString(); + + when(dataAddressResolver.resolve(any())).thenReturn(Result.success(testDestAddress())); + when(pipelineService.transfer(any(), any())) + .thenReturn(completedFuture(StreamResult.failure(new StreamFailure(List.of(firstErrorMsg, secondErrorMsg), StreamFailure.Reason.GENERAL_ERROR)))); + + var response = baseRequest() + .header(AUTHORIZATION, token) + .when() + .post("/any") + .then() + .statusCode(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) + .contentType(JSON) + .body("errors", isA(List.class)) + .extract() + .jsonPath(); + + var errors = response.getList("errors", String.class); + assertEquals(firstErrorMsg, errors.get(0)); + assertEquals(secondErrorMsg, errors.get(1)); } @Test