From 40deae0cab247b11e2abb775414b9630b9a6f290 Mon Sep 17 00:00:00 2001 From: Eric Klemm Date: Thu, 19 Dec 2024 16:49:11 +0100 Subject: [PATCH 1/2] prepare egvp rest client --- .../a2j/config/EgvpClientConfig.java | 24 ++++++++ .../service/egvp/DTO/GetVersionResponse.java | 3 + .../a2j/service/egvp/DTO/ResponseError.java | 3 + .../a2j/service/egvp/EgvpClient.java | 29 ++++++++++ .../a2j/service/egvp/EgvpClientException.java | 7 +++ .../resources/application-local.yaml.example | 3 + .../EgvpClientIntegrationTest.java | 56 +++++++++++++++++++ 7 files changed, 125 insertions(+) create mode 100644 src/main/java/de/bund/digitalservice/a2j/config/EgvpClientConfig.java create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/GetVersionResponse.java create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/ResponseError.java create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClientException.java create mode 100644 src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java diff --git a/src/main/java/de/bund/digitalservice/a2j/config/EgvpClientConfig.java b/src/main/java/de/bund/digitalservice/a2j/config/EgvpClientConfig.java new file mode 100644 index 0000000..8793a81 --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/config/EgvpClientConfig.java @@ -0,0 +1,24 @@ +package de.bund.digitalservice.a2j.config; + +import de.bund.digitalservice.a2j.service.egvp.EgvpClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class EgvpClientConfig { + + @Bean + public EgvpClient egvpClient(@Value("egvp.client.baseUri") String baseUri) { + RestTemplate restClient = + new RestTemplateBuilder() + .errorHandler(new DefaultResponseErrorHandler()) + .rootUri(baseUri) + .build(); + + return new EgvpClient(restClient); + } +} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/GetVersionResponse.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/GetVersionResponse.java new file mode 100644 index 0000000..518d013 --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/GetVersionResponse.java @@ -0,0 +1,3 @@ +package de.bund.digitalservice.a2j.service.egvp.DTO; + +public record GetVersionResponse(String version) {} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/ResponseError.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/ResponseError.java new file mode 100644 index 0000000..be77ded --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/ResponseError.java @@ -0,0 +1,3 @@ +package de.bund.digitalservice.a2j.service.egvp.DTO; + +public record ResponseError(String responseCode, String errorDetail, String errorDescription) {} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java new file mode 100644 index 0000000..bb3f95d --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java @@ -0,0 +1,29 @@ +package de.bund.digitalservice.a2j.service.egvp; + +import de.bund.digitalservice.a2j.service.egvp.DTO.GetVersionResponse; +import de.bund.digitalservice.a2j.service.egvp.DTO.ResponseError; +import java.util.Objects; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +public class EgvpClient { + private final RestTemplate client; + + public EgvpClient(RestTemplate client) { + this.client = client; + } + + public GetVersionResponse getVersion() throws EgvpClientException, HttpClientErrorException { + try { + return this.client.getForEntity("/getVersion", GetVersionResponse.class).getBody(); + } catch (HttpClientErrorException e) { + ResponseError error = e.getResponseBodyAs(ResponseError.class); + + if (Objects.isNull(error)) { + throw e; + } else { + throw new EgvpClientException(error.responseCode()); + } + } + } +} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClientException.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClientException.java new file mode 100644 index 0000000..46668f6 --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClientException.java @@ -0,0 +1,7 @@ +package de.bund.digitalservice.a2j.service.egvp; + +public class EgvpClientException extends RuntimeException { + public EgvpClientException(String message) { + super(message); + } +} diff --git a/src/main/resources/application-local.yaml.example b/src/main/resources/application-local.yaml.example index c001896..27485d6 100644 --- a/src/main/resources/application-local.yaml.example +++ b/src/main/resources/application-local.yaml.example @@ -15,3 +15,6 @@ fitConnect: name: Simple Dummy Service jsonUri: https://schema.fitko.de/fim/s17000717_1.0.schema.json callbackSecret: s3cr3t +egvp: + client: + baseUri: "localhost:8088" diff --git a/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java b/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java new file mode 100644 index 0000000..c6e9e53 --- /dev/null +++ b/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java @@ -0,0 +1,56 @@ +package de.bund.digitalservice.a2j.integration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import de.bund.digitalservice.a2j.service.egvp.DTO.GetVersionResponse; +import de.bund.digitalservice.a2j.service.egvp.EgvpClient; +import de.bund.digitalservice.a2j.service.egvp.EgvpClientException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Tag("integration") +public class EgvpClientIntegrationTest { + + private EgvpClient client; + + private MockRestServiceServer mockServer; + + @BeforeEach + void setup() { + RestTemplate restTemplate = new RestTemplateBuilder().rootUri("http://localhost:8088").build(); + this.client = new EgvpClient(restTemplate); + this.mockServer = MockRestServiceServer.createServer(restTemplate); + } + + @Test + void getVersion() { + mockServer + .expect(requestTo("http://localhost:8088/getVersion")) + .andRespond( + withSuccess( + """ + { + "version":"6.0.1" + } + """, + MediaType.APPLICATION_JSON)); + GetVersionResponse res = null; + + try { + res = client.getVersion(); + } catch (EgvpClientException e) { + throw new RuntimeException(e); + } + + assertEquals(new GetVersionResponse("6.0.1"), res); + } +} From 96a763d32727ae8642d99cabd3ea3b8bbd0e8179 Mon Sep 17 00:00:00 2001 From: Eric Klemm Date: Fri, 3 Jan 2025 14:27:49 +0100 Subject: [PATCH 2/2] test error parsing test checking status of message in transit --- .../DTO/MessageDeliveryStatusResponse.java | 4 ++ .../service/egvp/DTO/SendMessageRequest.java | 8 +++ .../service/egvp/DTO/SendMessageResponse.java | 3 + .../a2j/service/egvp/EgvpClient.java | 46 +++++++++--- .../EgvpClientIntegrationTest.java | 71 +++++++++++++++---- 5 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/MessageDeliveryStatusResponse.java create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageRequest.java create mode 100644 src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageResponse.java diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/MessageDeliveryStatusResponse.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/MessageDeliveryStatusResponse.java new file mode 100644 index 0000000..1b31341 --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/MessageDeliveryStatusResponse.java @@ -0,0 +1,4 @@ +package de.bund.digitalservice.a2j.service.egvp.DTO; + +public record MessageDeliveryStatusResponse( + String messageId, Boolean delivered, String pendingReason, String path) {} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageRequest.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageRequest.java new file mode 100644 index 0000000..3af18f3 --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageRequest.java @@ -0,0 +1,8 @@ +package de.bund.digitalservice.a2j.service.egvp.DTO; + +public record SendMessageRequest( + String receiverId, + String bundIdMailbox, + String subject, + String attachmentFile, + String xJustizFile) {} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageResponse.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageResponse.java new file mode 100644 index 0000000..f9397c0 --- /dev/null +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/DTO/SendMessageResponse.java @@ -0,0 +1,3 @@ +package de.bund.digitalservice.a2j.service.egvp.DTO; + +public record SendMessageResponse(String customId) {} diff --git a/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java b/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java index bb3f95d..daf206b 100644 --- a/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java +++ b/src/main/java/de/bund/digitalservice/a2j/service/egvp/EgvpClient.java @@ -1,9 +1,9 @@ package de.bund.digitalservice.a2j.service.egvp; -import de.bund.digitalservice.a2j.service.egvp.DTO.GetVersionResponse; -import de.bund.digitalservice.a2j.service.egvp.DTO.ResponseError; +import de.bund.digitalservice.a2j.service.egvp.DTO.*; import java.util.Objects; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; public class EgvpClient { @@ -13,17 +13,45 @@ public EgvpClient(RestTemplate client) { this.client = client; } - public GetVersionResponse getVersion() throws EgvpClientException, HttpClientErrorException { + public GetVersionResponse getVersion() throws EgvpClientException { try { return this.client.getForEntity("/getVersion", GetVersionResponse.class).getBody(); } catch (HttpClientErrorException e) { - ResponseError error = e.getResponseBodyAs(ResponseError.class); + throw parseException(e); + } catch (RestClientException e) { + throw new EgvpClientException(e.getMessage()); + } + } + + public SendMessageResponse sendMessage(SendMessageRequest request) throws EgvpClientException { + try { + return this.client + .postForEntity("/sendMessage", request, SendMessageResponse.class) + .getBody(); + } catch (HttpClientErrorException e) { + throw parseException(e); + } catch (RestClientException e) { + throw new EgvpClientException(e.getMessage()); + } + } + + public MessageDeliveryStatusResponse checkMessageStatus(String customId) { + + try { + return this.client.getForObject( + "/getMessageDeliveryStatus/{customId}", MessageDeliveryStatusResponse.class, customId); + } catch (HttpClientErrorException e) { + throw parseException(e); + } catch (RestClientException e) { + throw new EgvpClientException(e.getMessage()); + } + } - if (Objects.isNull(error)) { - throw e; - } else { - throw new EgvpClientException(error.responseCode()); - } + private EgvpClientException parseException(HttpClientErrorException e) { + ResponseError re = e.getResponseBodyAs(ResponseError.class); + if (Objects.isNull(re)) { + return new EgvpClientException(e.getMessage()); } + return new EgvpClientException(re.responseCode()); } } diff --git a/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java b/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java index c6e9e53..822545c 100644 --- a/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java +++ b/src/test/java/de/bund/digitalservice/a2j/integration/EgvpClientIntegrationTest.java @@ -1,22 +1,30 @@ package de.bund.digitalservice.a2j.integration; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; -import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; +import static org.springframework.test.web.client.response.MockRestResponseCreators.*; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import de.bund.digitalservice.a2j.service.egvp.DTO.GetVersionResponse; +import de.bund.digitalservice.a2j.service.egvp.DTO.MessageDeliveryStatusResponse; +import de.bund.digitalservice.a2j.service.egvp.DTO.SendMessageRequest; import de.bund.digitalservice.a2j.service.egvp.EgvpClient; import de.bund.digitalservice.a2j.service.egvp.EgvpClientException; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +// only extend with SpringExtension to avoid loading the whole Application context +@ExtendWith(SpringExtension.class) @Tag("integration") public class EgvpClientIntegrationTest { @@ -32,7 +40,7 @@ void setup() { } @Test - void getVersion() { + void getVersionsuccess() { mockServer .expect(requestTo("http://localhost:8088/getVersion")) .andRespond( @@ -43,14 +51,53 @@ void getVersion() { } """, MediaType.APPLICATION_JSON)); - GetVersionResponse res = null; - try { - res = client.getVersion(); - } catch (EgvpClientException e) { - throw new RuntimeException(e); - } + assertEquals(new GetVersionResponse("6.0.1"), client.getVersion()); + } + + @Test + void checkMessageStatus() { + mockServer + .expect(requestTo("http://localhost:8088/getMessageDeliveryStatus/12345")) + .andRespond( + withSuccess( + """ + { + "messageId":"MSG_ID_123", + "delivered":true, + "pendingReason":"", + "path": "path_to_file.pdf" + } + """, + MediaType.APPLICATION_JSON)); + MessageDeliveryStatusResponse expectedResponse = + new MessageDeliveryStatusResponse("MSG_ID_123", true, "", "path_to_file.pdf"); + + assertEquals(expectedResponse, client.checkMessageStatus("12345")); + } + + @Test + void sendMessageFailure() throws JsonProcessingException { + SendMessageRequest request = + new SendMessageRequest( + "receiverId", "mailbox", "subject", "attachmentFilepath", "xjustizFilepath"); + + mockServer + .expect(requestTo("http://localhost:8088/sendMessage")) + .andExpect(method(HttpMethod.POST)) + .andExpect(content().json(new ObjectMapper().writeValueAsString(request))) + .andRespond( + withBadRequest() + .body( + """ + { + "responseCode":"ZERO_SIZE_ATTACHMENT" + } + """) + .contentType(MediaType.APPLICATION_JSON)); + EgvpClientException ex = + Assertions.assertThrows(EgvpClientException.class, () -> client.sendMessage(request)); - assertEquals(new GetVersionResponse("6.0.1"), res); + assertEquals("ZERO_SIZE_ATTACHMENT", ex.getMessage()); } }