From 7a7d58a8e4893ab21d458f6f785820e0f4ed8c8a Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Wed, 15 Jan 2025 14:42:22 +0100 Subject: [PATCH 01/22] OZG-4094 beans: Condition on enabled=true --- .../postfach/osiv2/OsiPostfachRemoteService.java | 3 ++- .../postfach/osiv2/config/ApiClientConfiguration.java | 6 +++--- ...achProperties.java => Osi2PostfachProperties.java} | 11 ++++++----- .../osiv2/transfer/PostfachApiFacadeService.java | 11 ++++++++--- 4 files changed, 19 insertions(+), 12 deletions(-) rename src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/{OsiPostfachProperties.java => Osi2PostfachProperties.java} (73%) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java index 6559227..8664f52 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java @@ -7,11 +7,12 @@ import org.springframework.stereotype.Service; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachRemoteService; +import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; import de.ozgcloud.nachrichten.postfach.osiv2.transfer.PostfachApiFacadeService; import lombok.extern.log4j.Log4j2; @Service -@ConditionalOnProperty("ozgcloud.osiv2-postfach.enabled") +@ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") @Log4j2 public record OsiPostfachRemoteService( PostfachApiFacadeService postfachApiFacadeService diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index 16d7d79..4584e52 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -23,11 +23,11 @@ import reactor.netty.transport.ProxyProvider; @Configuration @RequiredArgsConstructor -@ConditionalOnProperty("ozgcloud.osiv2-postfach.enabled") +@ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") public class ApiClientConfiguration { - private final OsiPostfachProperties.ApiConfiguration apiConfiguration; - private final OsiPostfachProperties.ProxyConfiguration proxyConfiguration; + private final Osi2PostfachProperties.ApiConfiguration apiConfiguration; + private final Osi2PostfachProperties.ProxyConfiguration proxyConfiguration; @Bean MessageExchangeApi messageExchangeApi(ApiClient apiClient) { diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/OsiPostfachProperties.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java similarity index 73% rename from src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/OsiPostfachProperties.java rename to src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java index 44fd8ef..2cf55ad 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/OsiPostfachProperties.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java @@ -2,6 +2,7 @@ package de.ozgcloud.nachrichten.postfach.osiv2.config; import jakarta.annotation.Nullable; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -11,10 +12,10 @@ import lombok.Setter; @Getter @Setter @Configuration -@ConfigurationProperties(prefix = OsiPostfachProperties.PREFIX) -public class OsiPostfachProperties { +@ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") +public class Osi2PostfachProperties { - static final String PREFIX = "ozgcloud.osiv2-postfach"; + public static final String PREFIX = "ozgcloud.osiv2-postfach"; private boolean enabled; @@ -23,7 +24,7 @@ public class OsiPostfachProperties { @Configuration @ConfigurationProperties(prefix = ApiConfiguration.PREFIX) static class ApiConfiguration { - static final String PREFIX = OsiPostfachProperties.PREFIX + ".api"; + static final String PREFIX = Osi2PostfachProperties.PREFIX + ".api"; private String resource; private String url; @@ -40,7 +41,7 @@ public class OsiPostfachProperties { @Configuration @ConfigurationProperties(prefix = ProxyConfiguration.PREFIX) static class ProxyConfiguration { - static final String PREFIX = OsiPostfachProperties.PREFIX + ".http-proxy"; + static final String PREFIX = Osi2PostfachProperties.PREFIX + ".http-proxy"; private boolean enabled; diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index 246a121..4405c98 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -7,16 +7,21 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; import lombok.extern.log4j.Log4j2; @Log4j2 @Service -@ConditionalOnProperty("ozgcloud.osiv2-postfach.enabled") -public record PostfachApiFacadeService(MessageExchangeApi messageExchangeApi, RequestMapper requestMapper, ResponseMapper responseMapper) { - +@ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") +public record PostfachApiFacadeService( + MessageExchangeApi messageExchangeApi, + RequestMapper requestMapper, + ResponseMapper responseMapper +) { private static int MAX_NUMBER_RECEIVED_MESSAGES = 100; + public void sendMessage(PostfachNachricht nachricht) { messageExchangeApi.sendMessage( requestMapper.mapMailboxId(nachricht), -- GitLab From 47f503cc56c3cd73c038273b3a98e4ec0d80b002 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 17 Jan 2025 08:57:48 +0100 Subject: [PATCH 02/22] OZG-4094 send: Use OSI Postfach-type --- .../nachrichten/postfach/osiv2/OsiPostfachRemoteService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java index 8664f52..0d94013 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java @@ -17,7 +17,7 @@ import lombok.extern.log4j.Log4j2; public record OsiPostfachRemoteService( PostfachApiFacadeService postfachApiFacadeService ) implements PostfachRemoteService { - public static final String POSTFACH_TYPE_OSI = "OSIV2"; + public static final String POSTFACH_TYPE_OSI = "OSI"; @Override public void sendMessage(PostfachNachricht nachricht) { -- GitLab From 4089276d22902a310c0d0131f732d396b61e2718 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 17 Jan 2025 09:11:04 +0100 Subject: [PATCH 03/22] OZG-4094 config: Disable osiv2 by default --- src/main/resources/application.yml | 4 +--- src/test/resources/application-itcase.yml | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 172d0ad..1d1f1bf 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,4 @@ spring: - main: - web-application-type: reactive jackson: default-property-inclusion: NON_NULL security: @@ -18,7 +16,7 @@ spring: token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' ozgcloud: osiv2-postfach: - enabled: true + enabled: false api: resource: 'urn:dataport:osi:postfach:rz2:stage:sh' url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0' diff --git a/src/test/resources/application-itcase.yml b/src/test/resources/application-itcase.yml index dcbea65..d8cacf7 100644 --- a/src/test/resources/application-itcase.yml +++ b/src/test/resources/application-itcase.yml @@ -1,3 +1,6 @@ +ozgcloud: + osiv2-postfach: + enabled: true logging: level: de.ozgcloud.nachrichten.postfach.osiv2: DEBUG -- GitLab From c51bd8472202ba44afc1c0cd47fef73d613f52ca Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 20 Jan 2025 09:49:14 +0100 Subject: [PATCH 04/22] OZG-4094 beans: Turn records to classes --- .../postfach/osiv2/OsiPostfachRemoteService.java | 8 +++++--- .../osiv2/transfer/PostfachApiFacadeService.java | 13 ++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java index 0d94013..a3d3ccd 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java @@ -9,14 +9,16 @@ import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachRemoteService; import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; import de.ozgcloud.nachrichten.postfach.osiv2.transfer.PostfachApiFacadeService; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Service @ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") @Log4j2 -public record OsiPostfachRemoteService( - PostfachApiFacadeService postfachApiFacadeService -) implements PostfachRemoteService { +@RequiredArgsConstructor +public class OsiPostfachRemoteService implements PostfachRemoteService { + private final PostfachApiFacadeService postfachApiFacadeService; + public static final String POSTFACH_TYPE_OSI = "OSI"; @Override diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index 4405c98..d3aaa13 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -10,16 +10,19 @@ import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 @Service @ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") -public record PostfachApiFacadeService( - MessageExchangeApi messageExchangeApi, - RequestMapper requestMapper, - ResponseMapper responseMapper -) { +@RequiredArgsConstructor +public class PostfachApiFacadeService { + + private final MessageExchangeApi messageExchangeApi; + private final RequestMapper requestMapper; + private final ResponseMapper responseMapper; + private static int MAX_NUMBER_RECEIVED_MESSAGES = 100; public void sendMessage(PostfachNachricht nachricht) { -- GitLab From 1c915ef750e2ab0859ff69025d495c42e2297534 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 24 Jan 2025 09:48:36 +0100 Subject: [PATCH 05/22] OZG-4095 refactor: Cleanup ITCase --- .../osiv2/OsiPostfachRemoteServiceITCase.java | 126 ++++++++---------- .../postfach/osiv2/factory/JsonUtil.java | 4 +- 2 files changed, 56 insertions(+), 74 deletions(-) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index eaf8f54..2771bbd 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -7,17 +7,14 @@ import static org.mockserver.mock.OpenAPIExpectation.*; import static org.mockserver.model.HttpRequest.*; import static org.mockserver.model.HttpResponse.*; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.OffsetDateTime; import java.util.Arrays; import java.util.Map; -import java.util.Objects; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -30,18 +27,14 @@ import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.TestPropertySource; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.extension.Jwt; import de.ozgcloud.nachrichten.postfach.osiv2.extension.OsiMockServerExtension; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.JsonUtil; import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; -import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; -import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; import lombok.SneakyThrows; @SpringBootTest(classes = TestApplication.class) @@ -49,11 +42,16 @@ import lombok.SneakyThrows; @TestPropertySource(properties = { "ozgcloud.osiv2-postfach.http-proxy.enabled=false", }) -public class OsiPostfachRemoteServiceITCase { +class OsiPostfachRemoteServiceITCase { @RegisterExtension static final OsiMockServerExtension OSI_MOCK_SERVER_EXTENSION = new OsiMockServerExtension(); + @SneakyThrows + private static String getPostfachApiSpec() { + return Files.readString(Path.of("spec", "postfach-api-facade.yaml")); + } + private final PostfachNachricht postfachNachricht = PostfachNachrichtTestFactory.create(); @Autowired @@ -76,19 +74,13 @@ public class OsiPostfachRemoteServiceITCase { postfachFacadeMockClient = OSI_MOCK_SERVER_EXTENSION.getPostfachFacadeMockClient(); } -// @Disabled - @DisplayName("should send dummy request with jwt") + @DisplayName("should send request with jwt") @Test @SneakyThrows - void shouldSendDummyRequestWithJwt() { - postfachFacadeMockClient.upsert( - openAPIExpectation() - .withSpecUrlOrPayload(Files.readString(Path.of("spec", "postfach-api-facade.yaml"))) - .withOperationsAndResponses(Map.of( - "SendMessage", "200" - )) - ); - + void shouldSendRequestWithJwt() { + mockOperationsAndResponses(Map.of( + "SendMessage", "200" + )); osiPostfachRemoteService.sendMessage(postfachNachricht); @@ -101,89 +93,77 @@ public class OsiPostfachRemoteServiceITCase { assertThat(jwt.body().read("$.aud", String.class)).isEqualTo(RESOURCE_URN); } - ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); - - @Disabled @DisplayName("should receive one messages") @Test @SneakyThrows void shouldReceiveMessages() { - var uuid = UUID.fromString("00000000-0000-0000-0000-000000000000"); - - createMessagesJson(uuid, null); - - createOneReplyMessageJson(uuid); + mockPostfachMessageAndResponse("00000000-0000-0000-0000-000000000000"); - var messageStream = osiPostfachRemoteService.getAllMessages(); + var messageList = osiPostfachRemoteService.getAllMessages().toList(); - var messageList = messageStream.toList(); - assertThat(messageList).size().isEqualTo(1); + assertThat(messageList).hasSize(1); } - @Disabled @DisplayName("should receive two messages") @Test @SneakyThrows void shouldReceiveTwoMessages() { - var uuid1 = UUID.fromString("00000000-0000-0000-0000-000000000000"); - var uuid2 = UUID.fromString("00000000-0000-0000-0000-000000000001"); + mockPostfachMessageAndResponse("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000001"); - createMessagesJson(uuid1, uuid2); + var messageList = osiPostfachRemoteService.getAllMessages().toList(); - createOneReplyMessageJson(uuid1); - createOneReplyMessageJson(uuid2); - - var messageStream = osiPostfachRemoteService.getAllMessages(); - - var messageList = messageStream.toList(); - assertThat(messageList).size().isEqualTo(2); + assertThat(messageList).hasSize(2); } - private void createMessagesJson(final UUID... uuids) throws IOException { - var messagesList = Arrays.stream(uuids).filter(Objects::nonNull).map(uuid -> new MessageExchangeReceiveMessage().guid(uuid)).toList(); - - var messages = new MessageExchangeReceiveMessagesResponse().messages(messagesList); - - ObjectWriter ow = objectMapper.writer().withDefaultPrettyPrinter(); - String messagesJson = ow.writeValueAsString(messages); - - createMessagesCall("receiveMessages", messagesJson); + private void mockPostfachMessageAndResponse(final String... uuids) { + // Stub message listing response + mockJsonOperation("receiveMessages", new MessageExchangeReceiveMessagesResponse() + .messages(Arrays.stream(uuids) + .map(uuid -> new MessageExchangeReceiveMessage() + .guid(UUID.fromString(uuid))) + .toList())); + for (String uuid : uuids) { + // Stub individual response for message + mockJsonOperation("getMessage", V1ReplyMessageFactory.create() + .messageBox(UUID.fromString(uuid)) + .responseTime(OffsetDateTime.now())); + } } - private void createMessagesCall(final String receiveMessages, final String messagesJson) throws IOException { + private void mockJsonOperation(final String operationId, final Object body) { postfachFacadeMockClient .when( new OpenAPIDefinition() - .withSpecUrlOrPayload(Files.readString(Path.of("spec", "postfach-api-facade.yaml"))) - .withOperationId(receiveMessages) + .withSpecUrlOrPayload(getPostfachApiSpec()) + .withOperationId(operationId) ) - .respond(response().withHeader("Content-type", "application/json").withBody(messagesJson)); + .respond( + response() + .withHeader("Content-type", "application/json") + .withBody(JsonUtil.toJson(body)) + ); } - private void createOneReplyMessageJson(final UUID uuid) throws IOException { - ObjectWriter ow = objectMapper.writer().withDefaultPrettyPrinter(); - - var replyMessage = new V1ReplyMessage() - .body("das ist ein toller Body").replyAction(V1ReplyBehavior.REPLYPOSSIBLE).messageBox(uuid).responseTime(OffsetDateTime.now()); - String messageJson = ow.writeValueAsString(replyMessage); - - createMessagesCall("getMessage", messageJson); - } - - @Disabled @DisplayName("should delete message") @Test @SneakyThrows void shouldDeleteMessage() { + mockOperationsAndResponses(Map.of( + "deleteMessage", "200" + )); + + assertDoesNotThrow(() -> osiPostfachRemoteService.deleteMessage("00000000-0000-0000-0000-000000000000")); + + // TODO verify delete message called + // var requests = postfachFacadeMockClient.retrieveRecordedRequests(request()); + } + + private void mockOperationsAndResponses(Map<String, String> operationsAndResponses) { postfachFacadeMockClient.upsert( openAPIExpectation() - .withSpecUrlOrPayload(Files.readString(Path.of("spec", "postfach-api-facade.yaml"))) - .withOperationsAndResponses(Map.of( - "deleteMessage", "200" - )) + .withSpecUrlOrPayload(getPostfachApiSpec()) + .withOperationsAndResponses(operationsAndResponses) ); - - assertDoesNotThrow(() -> osiPostfachRemoteService.deleteMessage("00000000-0000-0000-0000-000000000000")); } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/JsonUtil.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/JsonUtil.java index 5353606..ac01337 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/JsonUtil.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/JsonUtil.java @@ -1,11 +1,13 @@ package de.ozgcloud.nachrichten.postfach.osiv2.factory; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.SneakyThrows; public class JsonUtil { - private static final ObjectMapper jsonMapper = new ObjectMapper(); + private static final ObjectMapper jsonMapper = new ObjectMapper() + .registerModule(new JavaTimeModule()); @SneakyThrows public static String toJson(Object object) { -- GitLab From 69cb6a73c6357a562fb1031b26bd3f5d3d84fe07 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 24 Jan 2025 12:08:32 +0100 Subject: [PATCH 06/22] OZG-4095 config: Configure oauth2 manager --- .../osiv2/config/ApiClientConfiguration.java | 168 +++++------------- .../extension/OsiMockServerExtension.java | 2 +- 2 files changed, 49 insertions(+), 121 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index 650960e..d8671c1 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -1,6 +1,5 @@ package de.ozgcloud.nachrichten.postfach.osiv2.config; -import jakarta.annotation.PostConstruct; import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; @@ -10,21 +9,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.converter.FormHttpMessageConverter; -import org.springframework.http.converter.json.JsonbHttpMessageConverter; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.oauth2.client.*; -import org.springframework.security.oauth2.client.endpoint.*; -import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; +import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; +import org.springframework.security.oauth2.client.endpoint.RestClientClientCredentialsTokenResponseClient; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ClientRegistrations; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor; -import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; @@ -41,7 +34,6 @@ public class ApiClientConfiguration { private final OsiPostfachProperties.ApiConfiguration apiConfiguration; private final OsiPostfachProperties.ProxyConfiguration proxyConfiguration; - private static final String RESOURCE_HEADER = "resource"; @Bean MessageExchangeApi messageExchangeApi(ApiClient apiClient) { @@ -49,126 +41,31 @@ public class ApiClientConfiguration { } @Bean - ApiClient apiClient(OAuth2AuthorizedClientManager authorizedClientManager){ - var apiClient = new ApiClient(restClient(authorizedClientManager)); + ApiClient apiClient(RestClient restClient) { + var apiClient = new ApiClient(restClient); apiClient.setBasePath(apiConfiguration.getUrl()); return apiClient; } - @Bean - public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) { + public RestClient restClient(ClientRegistrationRepository clientRegistrations) { OAuth2ClientHttpRequestInterceptor requestInterceptor = - new OAuth2ClientHttpRequestInterceptor(authorizedClientManager); + new OAuth2ClientHttpRequestInterceptor(authorizedClientManager(clientRegistrations)); + requestInterceptor.setClientRegistrationIdResolver(request -> "osi2"); return RestClient.builder() .requestInterceptor(requestInterceptor) - . - .build(); } - - - private RestClient restClient; - - @PostConstruct - void initialize() { - - this.restClient = RestClient.builder() - .messageConverters((messageConverters) -> { - messageConverters.clear(); - messageConverters.add(new FormHttpMessageConverter()); -// messageConverters.add(new JsonbHttpMessageConverter()); - messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter()); - }) - .defaultStatusHandler(new OAuth2ErrorResponseErrorHandler()) - // TODO: Customize the instance of RestClient as needed... - .build(); - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() { - RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient = - new RestClientAuthorizationCodeTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() { - RestClientRefreshTokenTokenResponseClient accessTokenResponseClient = - new RestClientRefreshTokenTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() { - RestClientClientCredentialsTokenResponseClient accessTokenResponseClient = - new RestClientClientCredentialsTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() { - return (grantRequest) -> { - throw new UnsupportedOperationException("The `password` grant type is not supported."); - }; - } - - @Bean - public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() { - RestClientJwtBearerTokenResponseClient accessTokenResponseClient = - new RestClientJwtBearerTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - - @Bean - public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() { - RestClientTokenExchangeTokenResponseClient accessTokenResponseClient = - new RestClientTokenExchangeTokenResponseClient(); - accessTokenResponseClient.setRestClient(this.restClient); - - return accessTokenResponseClient; - } - -// @Bean -// RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) { -// -// RestClient restClient = RestClient.builder() -// .requestFactory(createProxyRequestFactory()) -// .requestInterceptor(createOAuth2Interceptor(authorizedClientManager)) -// .baseUrl(apiConfiguration.getUrl()) -//// .defaultHeader(RESOURCE_HEADER, apiConfiguration.getResource()) -// .build(); -// return restClient; -// } - -// @Bean -// public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient(RestClient restClient) { -// RestClientClientCredentialsTokenResponseClient accessTokenResponseClient = -// new RestClientClientCredentialsTokenResponseClient(); -// accessTokenResponseClient.setRestClient(restClient); -// -// return accessTokenResponseClient; -// } - - - private ClientHttpRequestFactory createProxyRequestFactory(){ + private ClientHttpRequestFactory createProxyRequestFactory() { var requestFactory = new HttpComponentsClientHttpRequestFactory(); - if(proxyConfiguration.isEnabled()){ + if (proxyConfiguration.isEnabled()) { var credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope(proxyConfiguration.getHost(), proxyConfiguration.getPort()), -//TODO: hier brauchen wir noch eine Ordentliche Lösung -// new UsernamePasswordCredentials(proxyConfiguration.getUsername(), proxyConfiguration.getPassword().toCharArray()) + //TODO: hier brauchen wir noch eine Ordentliche Lösung + // new UsernamePasswordCredentials(proxyConfiguration.getUsername(), proxyConfiguration.getPassword().toCharArray()) new UsernamePasswordCredentials("", "".toCharArray()) ); var httpClient = HttpClientBuilder.create() @@ -180,8 +77,39 @@ public class ApiClientConfiguration { return requestFactory; } - private ClientHttpRequestInterceptor createOAuth2Interceptor(OAuth2AuthorizedClientManager authorizedClientManager) { - var interceptor = new OAuth2ClientHttpRequestInterceptor(authorizedClientManager); - return interceptor; + private AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager( + ClientRegistrationRepository clientRegistrations) { + var clientService = new InMemoryOAuth2AuthorizedClientService( + clientRegistrations); + var authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager( + clientRegistrations, clientService); + + authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider()); + + return authorizedClientManager; + } + + private OAuth2AuthorizedClientProvider authorizedClientProvider() { + return OAuth2AuthorizedClientProviderBuilder.builder() + .clientCredentials(builder -> + builder.accessTokenResponseClient(clientCredentialsTokenResponseClient()) + ) + .build(); } + + private RestClientClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient() { + var client = new RestClientClientCredentialsTokenResponseClient(); + configureParametersForTokenRequests(client); + return client; + } + + private void configureParametersForTokenRequests(RestClientClientCredentialsTokenResponseClient client) { + client.addParametersConverter(source -> { + MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(); + // Pass a resource indicator parameter https://datatracker.ietf.org/doc/html/rfc8707 + parameters.add("resource", apiConfiguration.getResource()); + return parameters; + }); + } + } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java index 5ce2169..9d59d95 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java @@ -105,7 +105,7 @@ public class OsiMockServerExtension implements BeforeAllCallback, AfterAllCallba .withMethod("POST") .withPath("/access-token") .withHeaders( - header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") + header("Content-Type", "application/x-www-form-urlencoded") ) .withBody( params( -- GitLab From b174e3f17761c9cecd616598114118b437e916b8 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 24 Jan 2025 12:50:14 +0100 Subject: [PATCH 07/22] OZG-4095 config: Configure proxy --- .../osiv2/config/ApiClientConfiguration.java | 49 ++++++++++++++----- .../OsiPostfachRemoteServiceRemoteITCase.java | 4 +- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index d8671c1..2cb4f19 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -10,14 +10,17 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; import org.springframework.security.oauth2.client.endpoint.RestClientClientCredentialsTokenResponseClient; +import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor; +import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; @@ -53,30 +56,40 @@ public class ApiClientConfiguration { new OAuth2ClientHttpRequestInterceptor(authorizedClientManager(clientRegistrations)); requestInterceptor.setClientRegistrationIdResolver(request -> "osi2"); - return RestClient.builder() + return defaultRestClientBuilder() .requestInterceptor(requestInterceptor) .build(); } + private RestClient.Builder defaultRestClientBuilder() { + return RestClient.builder() + .requestFactory(createProxyRequestFactory()); + } + private ClientHttpRequestFactory createProxyRequestFactory() { var requestFactory = new HttpComponentsClientHttpRequestFactory(); if (proxyConfiguration.isEnabled()) { - var credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials( - new AuthScope(proxyConfiguration.getHost(), proxyConfiguration.getPort()), - //TODO: hier brauchen wir noch eine Ordentliche Lösung - // new UsernamePasswordCredentials(proxyConfiguration.getUsername(), proxyConfiguration.getPassword().toCharArray()) - new UsernamePasswordCredentials("", "".toCharArray()) + requestFactory.setHttpClient( + HttpClientBuilder.create() + .setProxy(new HttpHost(proxyConfiguration.getHost(), proxyConfiguration.getPort())) + .setDefaultCredentialsProvider(basicCredentialsProviderForProxy()) + .build() ); - var httpClient = HttpClientBuilder.create() - .setProxy(new HttpHost(proxyConfiguration.getHost(), proxyConfiguration.getPort())) - .setDefaultCredentialsProvider(credsProvider) - .build(); - requestFactory.setHttpClient(httpClient); } return requestFactory; } + private BasicCredentialsProvider basicCredentialsProviderForProxy() { + var credentialsProvider = new BasicCredentialsProvider(); + var username = proxyConfiguration.getUsername(); + var password = proxyConfiguration.getPassword(); + if (username != null && password != null) { + credentialsProvider.setCredentials(new AuthScope(proxyConfiguration.getHost(), proxyConfiguration.getPort()), + new UsernamePasswordCredentials(username, password.toCharArray())); + } + return credentialsProvider; + } + private AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager( ClientRegistrationRepository clientRegistrations) { var clientService = new InMemoryOAuth2AuthorizedClientService( @@ -99,10 +112,22 @@ public class ApiClientConfiguration { private RestClientClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient() { var client = new RestClientClientCredentialsTokenResponseClient(); + configureClientCredentialsRestClient(client); configureParametersForTokenRequests(client); return client; } + private void configureClientCredentialsRestClient(RestClientClientCredentialsTokenResponseClient client) { + client.setRestClient(defaultRestClientBuilder() + .messageConverters(messageConverters -> { + messageConverters.clear(); + messageConverters.add(new FormHttpMessageConverter()); + messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter()); + }) + .defaultStatusHandler(new OAuth2ErrorResponseErrorHandler()) + .build()); + } + private void configureParametersForTokenRequests(RestClientClientCredentialsTokenResponseClient client) { client.addParametersConverter(source -> { MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(); diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java index 6012b3c..9978f98 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java @@ -83,8 +83,10 @@ public class OsiPostfachRemoteServiceRemoteITCase { @Test void shouldReceiveAllMessage(){ Stream<PostfachNachricht> allMessages = osiPostfachRemoteService.getAllMessages(); + var messages = allMessages.toList(); - assertThat(messages.size() > 0); + + assertThat(messages).isNotEmpty(); } } -- GitLab From d21d5fbeb2edaacd511d05f965753053730994ab Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 24 Jan 2025 13:32:41 +0100 Subject: [PATCH 08/22] OZG-4095 Avoid restClient bean --- .../postfach/osiv2/config/ApiClientConfiguration.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index 2cb4f19..729d574 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -44,14 +44,13 @@ public class ApiClientConfiguration { } @Bean - ApiClient apiClient(RestClient restClient) { - var apiClient = new ApiClient(restClient); + ApiClient apiClient(ClientRegistrationRepository clientRegistrations) { + var apiClient = new ApiClient(restClient(clientRegistrations)); apiClient.setBasePath(apiConfiguration.getUrl()); return apiClient; } - @Bean - public RestClient restClient(ClientRegistrationRepository clientRegistrations) { + private RestClient restClient(ClientRegistrationRepository clientRegistrations) { OAuth2ClientHttpRequestInterceptor requestInterceptor = new OAuth2ClientHttpRequestInterceptor(authorizedClientManager(clientRegistrations)); requestInterceptor.setClientRegistrationIdResolver(request -> "osi2"); -- GitLab From f16bf35e6ea81e42baf9083f639a16ca32c46543 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Fri, 24 Jan 2025 15:34:24 +0100 Subject: [PATCH 09/22] OZG-4095 pom: Cleanup dependencies --- pom.xml | 26 +++---------------- .../factory/PostfachAddressTestFactory.java | 2 ++ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index ab38b51..8991d23 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.9.0-SNAPSHOT</version> + <version>4.9.0</version> </parent> <groupId>de.ozgcloud.osiv2</groupId> @@ -17,19 +17,14 @@ <description>OSIv2-Postfach-Anbindung für OZG-Cloud-Nachrichten</description> <properties> - <api-lib.version>0.14.0</api-lib.version> - <nachrichten-manager.version>2.14.0</nachrichten-manager.version> + <api-lib.version>0.16.0</api-lib.version> + <nachrichten-manager.version>2.17.0-SNAPSHOT</nachrichten-manager.version> <mockserver-client.version>5.15.0</mockserver-client.version> <openapi-generator.version>7.10.0</openapi-generator.version> <swagger-parser.version>2.1.23</swagger-parser.version> </properties> <dependencies> <!-- OZG-Cloud --> - <dependency> - <groupId>de.ozgcloud.api-lib</groupId> - <artifactId>ozg-cloud-spring-boot-starter</artifactId> - <version>${api-lib.version}</version> - </dependency> <dependency> <groupId>de.ozgcloud.nachrichten</groupId> <artifactId>nachrichten-manager-postfach-interface</artifactId> @@ -48,21 +43,6 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - </dependency> - <dependency> - <groupId>jakarta.json.bind</groupId> - <artifactId>jakarta.json.bind-api</artifactId> - <version>3.0.1</version> - </dependency> - <dependency> - <groupId>org.eclipse</groupId> - <artifactId>yasson</artifactId> - <version>3.0.4</version> - <scope>test</scope> - </dependency> <dependency> <groupId>org.mapstruct</groupId> diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java index a871295..046f298 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/PostfachAddressTestFactory.java @@ -5,6 +5,7 @@ import de.ozgcloud.nachrichten.postfach.PostfachAddress; public class PostfachAddressTestFactory { public static final String MAILBOX_ID = "testMailboxId"; + public static final String SERVICE_KONTO_TYPE = "TYPE1"; public static PostfachAddress create() { return createBuilder().build(); @@ -13,6 +14,7 @@ public class PostfachAddressTestFactory { public static PostfachAddress.PostfachAddressBuilder createBuilder() { return PostfachAddress.builder() .type(1) + .serviceKontoType("TYPE1") .identifier(DummyStringBasedIdentifier.builder() .mailboxId(MAILBOX_ID) .build()); -- GitLab From 27562f2ddd691cf386640155426c8d13f6c5feb7 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 27 Jan 2025 13:34:53 +0100 Subject: [PATCH 10/22] OZG-4095 config: Make nested classes public --- .../postfach/osiv2/config/Osi2PostfachProperties.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java index 2cf55ad..f5a3d44 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java @@ -7,23 +7,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; @Getter @Setter @Configuration @ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") +@RequiredArgsConstructor public class Osi2PostfachProperties { public static final String PREFIX = "ozgcloud.osiv2-postfach"; private boolean enabled; + private final ApiConfiguration api; + + private final ProxyConfiguration httpProxy; + @Getter @Setter @Configuration @ConfigurationProperties(prefix = ApiConfiguration.PREFIX) - static class ApiConfiguration { + public static class ApiConfiguration { static final String PREFIX = Osi2PostfachProperties.PREFIX + ".api"; private String resource; @@ -40,7 +46,7 @@ public class Osi2PostfachProperties { @Setter @Configuration @ConfigurationProperties(prefix = ProxyConfiguration.PREFIX) - static class ProxyConfiguration { + public static class ProxyConfiguration { static final String PREFIX = Osi2PostfachProperties.PREFIX + ".http-proxy"; private boolean enabled; -- GitLab From 70414f67cc1ebc9a39fc38730ca4886bbc04a952 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 27 Jan 2025 14:17:46 +0100 Subject: [PATCH 11/22] OZG-4095 config: Use `stage` profile --- pom.xml | 7 ++++- src/main/resources/application-stage.yml | 26 ++++++++++++++++++ src/main/resources/application.yml | 27 +------------------ .../osiv2/OsiPostfachRemoteServiceITCase.java | 2 +- .../OsiPostfachRemoteServiceRemoteITCase.java | 10 +++---- src/test/resources/application-itcase.yml | 3 --- 6 files changed, 39 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/application-stage.yml diff --git a/pom.xml b/pom.xml index 8991d23..86abf55 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ <groupId>de.ozgcloud.osiv2</groupId> <artifactId>osiv2-postfach</artifactId> - <version>0.1.1-SNAPSHOT</version> + <version>0.1.0-SNAPSHOT</version> <name>OZG-Cloud-OSIv2-Postfach</name> <description>OSIv2-Postfach-Anbindung für OZG-Cloud-Nachrichten</description> @@ -25,6 +25,11 @@ </properties> <dependencies> <!-- OZG-Cloud --> + <dependency> + <groupId>de.ozgcloud.api-lib</groupId> + <artifactId>ozg-cloud-spring-boot-starter</artifactId> + <version>${api-lib.version}</version> + </dependency> <dependency> <groupId>de.ozgcloud.nachrichten</groupId> <artifactId>nachrichten-manager-postfach-interface</artifactId> diff --git a/src/main/resources/application-stage.yml b/src/main/resources/application-stage.yml new file mode 100644 index 0000000..f7c2e25 --- /dev/null +++ b/src/main/resources/application-stage.yml @@ -0,0 +1,26 @@ +spring: + security: + oauth2: + client: + registration: + osi2: + client-id: 'OZG-Kopfstelle' + client-secret: 'changeme' + scope: default, access_urn:dataport:osi:sh:stage:ozgkopfstelle + authorization-grant-type: 'client_credentials' + client-authentication-method: client_secret_post + provider: + osi2: + token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' +ozgcloud: + osiv2-postfach: + enabled: true + api: + resource: 'urn:dataport:osi:postfach:rz2:stage:sh' + url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0' + tenant: 'SH' + name-identifier: 'ozgkopfstelle' + http-proxy: + enabled: true + host: 127.0.0.1 + port: 3128 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1d1f1bf..065fffe 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,28 +1,3 @@ spring: jackson: - default-property-inclusion: NON_NULL - security: - oauth2: - client: - registration: - osi2: - client-id: 'OZG-Kopfstelle' - client-secret: 'changeme' - scope: default, access_urn:dataport:osi:sh:stage:ozgkopfstelle - authorization-grant-type: 'client_credentials' - client-authentication-method: client_secret_post - provider: - osi2: - token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' -ozgcloud: - osiv2-postfach: - enabled: false - api: - resource: 'urn:dataport:osi:postfach:rz2:stage:sh' - url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0' - tenant: 'SH' - name-identifier: 'ozgkopfstelle' - http-proxy: - enabled: true - host: 127.0.0.1 - port: 3128 + default-property-inclusion: NON_NULL \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index 2771bbd..dcfa4c5 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -38,7 +38,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMe import lombok.SneakyThrows; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles("itcase") +@ActiveProfiles({"itcase", "stage"}) @TestPropertySource(properties = { "ozgcloud.osiv2-postfach.http-proxy.enabled=false", }) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java index 9978f98..9301a37 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java @@ -23,7 +23,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles("local") +@ActiveProfiles({ "local", "stage" }) @EnabledIfEnvironmentVariable(named = "SH_STAGE_CLIENT_SECRET", matches = ".+") public class OsiPostfachRemoteServiceRemoteITCase { @@ -78,10 +78,10 @@ public class OsiPostfachRemoteServiceRemoteITCase { @DisplayName("receive all messages") @Nested - class TestReceiveAllMessages{ + class TestReceiveAllMessages { @Test - void shouldReceiveAllMessage(){ + void shouldReceiveAllMessage() { Stream<PostfachNachricht> allMessages = osiPostfachRemoteService.getAllMessages(); var messages = allMessages.toList(); @@ -93,10 +93,10 @@ public class OsiPostfachRemoteServiceRemoteITCase { @Disabled @DisplayName("delete message") @Nested - class TestDeleteMessageById{ + class TestDeleteMessageById { @Test - void shouldDeleteMessage(){ + void shouldDeleteMessage() { assertThatCode(() -> osiPostfachRemoteService.deleteMessage("5dd65c1e-bd41-4c3d-bf98-be769ca341dc")) .doesNotThrowAnyException(); } diff --git a/src/test/resources/application-itcase.yml b/src/test/resources/application-itcase.yml index d8cacf7..dcbea65 100644 --- a/src/test/resources/application-itcase.yml +++ b/src/test/resources/application-itcase.yml @@ -1,6 +1,3 @@ -ozgcloud: - osiv2-postfach: - enabled: true logging: level: de.ozgcloud.nachrichten.postfach.osiv2: DEBUG -- GitLab From 05642db428f2cf77890be0742070f6b6f5defcfc Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 27 Jan 2025 14:22:40 +0100 Subject: [PATCH 12/22] OZG-4095 config: Disable osi2.enable by default for `stage` --- src/main/resources/application-stage.yml | 2 +- src/test/resources/application-itcase.yml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application-stage.yml b/src/main/resources/application-stage.yml index f7c2e25..6892480 100644 --- a/src/main/resources/application-stage.yml +++ b/src/main/resources/application-stage.yml @@ -14,7 +14,7 @@ spring: token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' ozgcloud: osiv2-postfach: - enabled: true + enabled: false api: resource: 'urn:dataport:osi:postfach:rz2:stage:sh' url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0' diff --git a/src/test/resources/application-itcase.yml b/src/test/resources/application-itcase.yml index dcbea65..d8cacf7 100644 --- a/src/test/resources/application-itcase.yml +++ b/src/test/resources/application-itcase.yml @@ -1,3 +1,6 @@ +ozgcloud: + osiv2-postfach: + enabled: true logging: level: de.ozgcloud.nachrichten.postfach.osiv2: DEBUG -- GitLab From 1315be523c106fac6c13e719cbbc23bea74e9397 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 27 Jan 2025 14:27:10 +0100 Subject: [PATCH 13/22] OZG-4095 config: Disable osi2.enable by default for `stage` --- .../postfach/osiv2/OsiPostfachRemoteServiceITCase.java | 2 +- .../postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index dcfa4c5..f75663d 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -38,7 +38,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMe import lombok.SneakyThrows; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles({"itcase", "stage"}) +@ActiveProfiles({"stage", "itcase"}) @TestPropertySource(properties = { "ozgcloud.osiv2-postfach.http-proxy.enabled=false", }) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java index 9301a37..27c5c05 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java @@ -23,7 +23,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles({ "local", "stage" }) +@ActiveProfiles({ "stage", "local" }) @EnabledIfEnvironmentVariable(named = "SH_STAGE_CLIENT_SECRET", matches = ".+") public class OsiPostfachRemoteServiceRemoteITCase { -- GitLab From a9101e0f7668f7ced265d6a314aaa681acde2b78 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 27 Jan 2025 17:07:18 +0100 Subject: [PATCH 14/22] OZG-4095 wiremock: Replace mockserver with wiremock --- pom.xml | 8 ++ .../osiv2/OsiPostfachRemoteServiceITCase.java | 112 ++++++++++-------- .../extension/OsiMockServerExtension.java | 101 +++------------- 3 files changed, 88 insertions(+), 133 deletions(-) diff --git a/pom.xml b/pom.xml index 86abf55..1e8f3fd 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ <mockserver-client.version>5.15.0</mockserver-client.version> <openapi-generator.version>7.10.0</openapi-generator.version> <swagger-parser.version>2.1.23</swagger-parser.version> + <wiremock-spring-boot.version>3.6.0</wiremock-spring-boot.version> </properties> <dependencies> <!-- OZG-Cloud --> @@ -86,6 +87,13 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>org.wiremock.integrations</groupId> + <artifactId>wiremock-spring-boot</artifactId> + <version>${wiremock-spring-boot.version}</version> + </dependency> + + <!-- commons --> <dependency> <groupId>org.apache.commons</groupId> diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index f75663d..d20919e 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -1,25 +1,19 @@ package de.ozgcloud.nachrichten.postfach.osiv2; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.JwtFactory.*; import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockserver.mock.OpenAPIExpectation.*; -import static org.mockserver.model.HttpRequest.*; -import static org.mockserver.model.HttpResponse.*; import java.nio.file.Files; import java.nio.file.Path; import java.time.OffsetDateTime; import java.util.Arrays; -import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.mockserver.client.MockServerClient; -import org.mockserver.model.OpenAPIDefinition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; @@ -27,6 +21,9 @@ import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.TestPropertySource; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; + import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.extension.Jwt; import de.ozgcloud.nachrichten.postfach.osiv2.extension.OsiMockServerExtension; @@ -35,10 +32,11 @@ import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFacto import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeSendMessageResponse; import lombok.SneakyThrows; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles({"stage", "itcase"}) +@ActiveProfiles({ "stage", "itcase" }) @TestPropertySource(properties = { "ozgcloud.osiv2-postfach.http-proxy.enabled=false", }) @@ -66,29 +64,40 @@ class OsiPostfachRemoteServiceITCase { registry.add("ozgcloud.osiv2-postfach.api.resource", () -> RESOURCE_URN); } - private MockServerClient postfachFacadeMockClient; + private WireMockServer postfachFacadeMockServer; + private WireMockServer serviceKontoMockServer; @BeforeEach @SneakyThrows public void setup() { - postfachFacadeMockClient = OSI_MOCK_SERVER_EXTENSION.getPostfachFacadeMockClient(); + postfachFacadeMockServer = OSI_MOCK_SERVER_EXTENSION.getPostfachFacadeMockServer(); + serviceKontoMockServer = OSI_MOCK_SERVER_EXTENSION.getServiceKontoMockServer(); } @DisplayName("should send request with jwt") @Test @SneakyThrows void shouldSendRequestWithJwt() { - mockOperationsAndResponses(Map.of( - "SendMessage", "200" - )); + // Stub message send response (MessageExchangeApi::sendMessage) + postfachFacadeMockServer.stubFor(post("/MessageExchange/v1/Send/{mailboxId}") + .willReturn(okJsonObj(new MessageExchangeSendMessageResponse().messageId(UUID.randomUUID()))) + ); osiPostfachRemoteService.sendMessage(postfachNachricht); - var requests = postfachFacadeMockClient.retrieveRecordedRequests(request()); - assertThat(requests).hasSize(1); - var jwt = Jwt.parseAuthHeaderValue( - requests[0].getHeader("Authorization").getFirst() + serviceKontoMockServer.verify( + exactly(1), + postRequestedFor(urlEqualTo(OSI_MOCK_SERVER_EXTENSION.getAccessTokenUrl())) + .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded")) + .withQueryParam("grant_type", equalTo("client_credentials")) + .withQueryParam("client_id", equalTo(CLIENT_ID)) + .withQueryParam("scope", equalTo(String.join(" ", CLIENT_SCOPES))) + .withQueryParam("resource", equalTo(RESOURCE_URN)) ); + var requests = postfachFacadeMockServer.findAll( + postRequestedFor(urlPathEqualTo("/MessageExchange/v1/Send"))); + assertThat(requests).hasSize(1); + var jwt = Jwt.parseAuthHeaderValue(requests.getFirst().getHeader("Authorization")); assertThat(jwt.body().read("$.client_id", String.class)).isEqualTo(CLIENT_ID); assertThat(jwt.body().read("$.aud", String.class)).isEqualTo(RESOURCE_URN); } @@ -116,53 +125,54 @@ class OsiPostfachRemoteServiceITCase { } private void mockPostfachMessageAndResponse(final String... uuids) { - // Stub message listing response - mockJsonOperation("receiveMessages", new MessageExchangeReceiveMessagesResponse() - .messages(Arrays.stream(uuids) - .map(uuid -> new MessageExchangeReceiveMessage() - .guid(UUID.fromString(uuid))) - .toList())); + // Stub message listing response (MessageExchangeApi::receiveMessages) + postfachFacadeMockServer.stubFor(get("/MessageExchange/v1/Receive") + .willReturn( + okJsonObj( + new MessageExchangeReceiveMessagesResponse() + .messages(Arrays.stream(uuids) + .map(uuid -> new MessageExchangeReceiveMessage() + .guid(UUID.fromString(uuid))) + .toList()) + ) + ) + ); for (String uuid : uuids) { - // Stub individual response for message - mockJsonOperation("getMessage", V1ReplyMessageFactory.create() - .messageBox(UUID.fromString(uuid)) - .responseTime(OffsetDateTime.now())); + // Stub individual response for message (MessageExchangeApi::getMessage) + postfachFacadeMockServer.stubFor(get("/MessageExchange/v1/Receive/{messageId}") + .withPathParam("messageId", equalTo(uuid)) + .willReturn( + okJsonObj( + V1ReplyMessageFactory.create() + .messageBox(UUID.fromString(uuid)) + .responseTime(OffsetDateTime.now()) + ) + ) + ); } } - private void mockJsonOperation(final String operationId, final Object body) { - postfachFacadeMockClient - .when( - new OpenAPIDefinition() - .withSpecUrlOrPayload(getPostfachApiSpec()) - .withOperationId(operationId) - ) - .respond( - response() - .withHeader("Content-type", "application/json") - .withBody(JsonUtil.toJson(body)) - ); + private ResponseDefinitionBuilder okJsonObj(final Object body) { + return okJson(JsonUtil.toJson(body)); } @DisplayName("should delete message") @Test @SneakyThrows void shouldDeleteMessage() { - mockOperationsAndResponses(Map.of( - "deleteMessage", "200" - )); + var messageId = "00000000-0000-0000-0000-000000000000"; + // Stub delete message response (MessageExchangeApi::deleteMessage) + postfachFacadeMockServer.stubFor(delete("/MessageExchange/v1/Delete/{messageId}") + .willReturn(ok()) + ); - assertDoesNotThrow(() -> osiPostfachRemoteService.deleteMessage("00000000-0000-0000-0000-000000000000")); + osiPostfachRemoteService.deleteMessage(messageId); - // TODO verify delete message called - // var requests = postfachFacadeMockClient.retrieveRecordedRequests(request()); - } - private void mockOperationsAndResponses(Map<String, String> operationsAndResponses) { - postfachFacadeMockClient.upsert( - openAPIExpectation() - .withSpecUrlOrPayload(getPostfachApiSpec()) - .withOperationsAndResponses(operationsAndResponses) + postfachFacadeMockServer.verify( + exactly(1), + deleteRequestedFor(urlPathEqualTo("/MessageExchange/v1/Delete/{messageId}")) + .withPathParam("messageId", equalTo(messageId)) ); } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java index 9d59d95..adf3e29 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java @@ -1,22 +1,14 @@ package de.ozgcloud.nachrichten.postfach.osiv2.extension; -import static de.ozgcloud.nachrichten.postfach.osiv2.factory.JwtFactory.*; -import static org.mockserver.matchers.Times.*; -import static org.mockserver.model.Header.*; -import static org.mockserver.model.HttpRequest.*; -import static org.mockserver.model.HttpResponse.*; -import static org.mockserver.model.Parameter.*; -import static org.mockserver.model.ParameterBody.*; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; -import org.mockserver.client.MockServerClient; -import org.testcontainers.containers.MockServerContainer; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.utility.DockerImageName; + +import com.github.tomakehurst.wiremock.WireMockServer; import de.ozgcloud.nachrichten.postfach.osiv2.factory.JwtFactory; import lombok.Getter; @@ -28,25 +20,8 @@ import lombok.extern.log4j.Log4j2; @RequiredArgsConstructor public class OsiMockServerExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback { - private MockServerClient serviceKontoMockClient; - private MockServerClient postfachFacadeMockClient; - - private static final DockerImageName MOCK_SERVER_IMAGE = DockerImageName.parse("mockserver/mockserver") - .withTag("mockserver-5.15.0"); - - private final MockServerContainer serviceKontoMockContainer = new MockServerContainer(MOCK_SERVER_IMAGE) - .withLogConsumer(this::logContainerOutput); - private final MockServerContainer postfachFacadeMockContainer = new MockServerContainer(MOCK_SERVER_IMAGE) - .withLogConsumer(this::logContainerOutput); - - private void logContainerOutput(OutputFrame outputFrame) { - var line = outputFrame.getUtf8String().stripTrailing(); - if (outputFrame.getType() == OutputFrame.OutputType.STDERR) { - System.err.println(line); - } else { - System.out.println(line); - } - } + private WireMockServer serviceKontoMockServer; + private WireMockServer postfachFacadeMockServer; @Override public void beforeAll(ExtensionContext context) { @@ -56,77 +31,39 @@ public class OsiMockServerExtension implements BeforeAllCallback, AfterAllCallba @Override public void afterEach(ExtensionContext context) { - postfachFacadeMockClient.reset(); - serviceKontoMockClient.reset(); + postfachFacadeMockServer.resetAll(); + serviceKontoMockServer.resetAll(); } @Override public void afterAll(ExtensionContext context) { - serviceKontoMockClient.stop(); - serviceKontoMockContainer.stop(); - - postfachFacadeMockClient.stop(); - postfachFacadeMockContainer.stop(); + serviceKontoMockServer.shutdown(); + postfachFacadeMockServer.shutdown(); } private void setupPostfachFacadeMock() { - postfachFacadeMockContainer.start(); - postfachFacadeMockClient = new MockServerClient( - postfachFacadeMockContainer.getHost(), - postfachFacadeMockContainer.getServerPort() - ); + postfachFacadeMockServer = new WireMockServer(0); + postfachFacadeMockServer.start(); } private void setupServiceKontoMock() { - serviceKontoMockContainer.start(); - serviceKontoMockClient = new MockServerClient( - serviceKontoMockContainer.getHost(), - serviceKontoMockContainer.getServerPort() - ); + serviceKontoMockServer = new WireMockServer(0); + serviceKontoMockServer.start(); } public String getAccessTokenUrl() { - return getMockServerUrl(serviceKontoMockClient) + "/access-token"; + return serviceKontoMockServer.baseUrl() + "/access-token"; } public String getPostfachFacadeUrl() { - return getMockServerUrl(postfachFacadeMockClient); - } - - private String getMockServerUrl(MockServerClient mockClient) { - return "http://" + mockClient.remoteAddress().getHostName() + ":" + mockClient.remoteAddress().getPort(); + return postfachFacadeMockServer.baseUrl(); } @Override public void beforeEach(ExtensionContext context) { - serviceKontoMockClient - .when( - request() - .withMethod("POST") - .withPath("/access-token") - .withHeaders( - header("Content-Type", "application/x-www-form-urlencoded") - ) - .withBody( - params( - param("grant_type", "client_credentials"), - param("client_id", CLIENT_ID), - param("client_secret", "changeme"), - param("scope", String.join(" ", CLIENT_SCOPES)), - param("resource", RESOURCE_URN) - ) - ), - exactly(1) - ) - .respond( - response() - .withStatusCode(200) - .withHeader("Content-Type", "application/json") - .withBody( - JwtFactory.createTokenResponse( - JwtFactory.createAccessTokenExampleWithExpireIn(900) - ) - ) - ); + serviceKontoMockServer.stubFor(post("/access-token") + .willReturn(okJson(JwtFactory.createTokenResponse( + JwtFactory.createAccessTokenExampleWithExpireIn(900) + )))); } } -- GitLab From 88f2c78163f0f13a0a0afd29d7ca1155b25f0f35 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Mon, 27 Jan 2025 17:10:14 +0100 Subject: [PATCH 15/22] OZG-4095 todo: Add nullable reminder --- .../postfach/osiv2/transfer/PostfachApiFacadeService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index 7f62892..ed46e27 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -23,7 +23,7 @@ public class PostfachApiFacadeService { private final RequestMapper requestMapper; private final ResponseMapper responseMapper; - private static int MAX_NUMBER_RECEIVED_MESSAGES = 100; + private static final int MAX_NUMBER_RECEIVED_MESSAGES = 100; public void sendMessage(PostfachNachricht nachricht) { messageExchangeApi.sendMessage( @@ -34,6 +34,7 @@ public class PostfachApiFacadeService { public Stream<PostfachNachricht> receiveMessages() { var response = messageExchangeApi.receiveMessages(MAX_NUMBER_RECEIVED_MESSAGES, 0); + // TODO response.getMessages() is Nullable return response.getMessages().stream().map(this::fetchMessageByGuid); } -- GitLab From 4387d35529add50fb62479262998461d192157d4 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Tue, 28 Jan 2025 12:12:45 +0100 Subject: [PATCH 16/22] OZG-4095 wiremock: Adjust factories and matching --- .../osiv2/OsiPostfachRemoteServiceITCase.java | 54 ++++++++----------- .../extension/OsiMockServerExtension.java | 6 +++ ...sageExchangeReceiveMessageTestFactory.java | 15 ++++++ ...ngeReceiveMessagesResponseTestFactory.java | 13 +++++ ...xchangeSendMessageResponseTestFactory.java | 13 +++++ ...ry.java => V1ReplyMessageTestFactory.java} | 28 +++++----- .../osiv2/transfer/ResponseMapperTest.java | 4 +- 7 files changed, 84 insertions(+), 49 deletions(-) create mode 100644 src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessageTestFactory.java create mode 100644 src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java create mode 100644 src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeSendMessageResponseTestFactory.java rename src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/{V1ReplyMessageFactory.java => V1ReplyMessageTestFactory.java} (51%) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index d20919e..1de65de 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -4,8 +4,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.*; import static de.ozgcloud.nachrichten.postfach.osiv2.factory.JwtFactory.*; import static org.assertj.core.api.Assertions.*; -import java.nio.file.Files; -import java.nio.file.Path; import java.time.OffsetDateTime; import java.util.Arrays; import java.util.UUID; @@ -28,11 +26,11 @@ import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.extension.Jwt; import de.ozgcloud.nachrichten.postfach.osiv2.extension.OsiMockServerExtension; import de.ozgcloud.nachrichten.postfach.osiv2.factory.JsonUtil; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessageTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeSendMessageResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; -import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; -import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeSendMessageResponse; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory; import lombok.SneakyThrows; @SpringBootTest(classes = TestApplication.class) @@ -45,11 +43,6 @@ class OsiPostfachRemoteServiceITCase { @RegisterExtension static final OsiMockServerExtension OSI_MOCK_SERVER_EXTENSION = new OsiMockServerExtension(); - @SneakyThrows - private static String getPostfachApiSpec() { - return Files.readString(Path.of("spec", "postfach-api-facade.yaml")); - } - private final PostfachNachricht postfachNachricht = PostfachNachrichtTestFactory.create(); @Autowired @@ -65,13 +58,11 @@ class OsiPostfachRemoteServiceITCase { } private WireMockServer postfachFacadeMockServer; - private WireMockServer serviceKontoMockServer; @BeforeEach @SneakyThrows public void setup() { postfachFacadeMockServer = OSI_MOCK_SERVER_EXTENSION.getPostfachFacadeMockServer(); - serviceKontoMockServer = OSI_MOCK_SERVER_EXTENSION.getServiceKontoMockServer(); } @DisplayName("should send request with jwt") @@ -79,23 +70,19 @@ class OsiPostfachRemoteServiceITCase { @SneakyThrows void shouldSendRequestWithJwt() { // Stub message send response (MessageExchangeApi::sendMessage) - postfachFacadeMockServer.stubFor(post("/MessageExchange/v1/Send/{mailboxId}") - .willReturn(okJsonObj(new MessageExchangeSendMessageResponse().messageId(UUID.randomUUID()))) + postfachFacadeMockServer.stubFor(post(urlPathTemplate("/MessageExchange/v1/Send/{mailboxId}")) + .willReturn( + okJsonObj( + MessageExchangeSendMessageResponseTestFactory.create() + .messageId(UUID.randomUUID()) + ) + ) ); osiPostfachRemoteService.sendMessage(postfachNachricht); - serviceKontoMockServer.verify( - exactly(1), - postRequestedFor(urlEqualTo(OSI_MOCK_SERVER_EXTENSION.getAccessTokenUrl())) - .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded")) - .withQueryParam("grant_type", equalTo("client_credentials")) - .withQueryParam("client_id", equalTo(CLIENT_ID)) - .withQueryParam("scope", equalTo(String.join(" ", CLIENT_SCOPES))) - .withQueryParam("resource", equalTo(RESOURCE_URN)) - ); var requests = postfachFacadeMockServer.findAll( - postRequestedFor(urlPathEqualTo("/MessageExchange/v1/Send"))); + postRequestedFor(urlPathTemplate("/MessageExchange/v1/Send/{mailboxId}"))); assertThat(requests).hasSize(1); var jwt = Jwt.parseAuthHeaderValue(requests.getFirst().getHeader("Authorization")); assertThat(jwt.body().read("$.client_id", String.class)).isEqualTo(CLIENT_ID); @@ -126,12 +113,14 @@ class OsiPostfachRemoteServiceITCase { private void mockPostfachMessageAndResponse(final String... uuids) { // Stub message listing response (MessageExchangeApi::receiveMessages) - postfachFacadeMockServer.stubFor(get("/MessageExchange/v1/Receive") + postfachFacadeMockServer.stubFor(get(urlPathEqualTo("/MessageExchange/v1/Receive")) + .withQueryParam("take", equalTo("100")) + .withQueryParam("skip", equalTo("0")) .willReturn( okJsonObj( - new MessageExchangeReceiveMessagesResponse() + MessageExchangeReceiveMessagesResponseTestFactory.create() .messages(Arrays.stream(uuids) - .map(uuid -> new MessageExchangeReceiveMessage() + .map(uuid -> MessageExchangeReceiveMessageTestFactory.create() .guid(UUID.fromString(uuid))) .toList()) ) @@ -139,11 +128,11 @@ class OsiPostfachRemoteServiceITCase { ); for (String uuid : uuids) { // Stub individual response for message (MessageExchangeApi::getMessage) - postfachFacadeMockServer.stubFor(get("/MessageExchange/v1/Receive/{messageId}") + postfachFacadeMockServer.stubFor(get(urlPathTemplate("/MessageExchange/v1/Receive/{messageId}")) .withPathParam("messageId", equalTo(uuid)) .willReturn( okJsonObj( - V1ReplyMessageFactory.create() + V1ReplyMessageTestFactory.create() .messageBox(UUID.fromString(uuid)) .responseTime(OffsetDateTime.now()) ) @@ -162,16 +151,15 @@ class OsiPostfachRemoteServiceITCase { void shouldDeleteMessage() { var messageId = "00000000-0000-0000-0000-000000000000"; // Stub delete message response (MessageExchangeApi::deleteMessage) - postfachFacadeMockServer.stubFor(delete("/MessageExchange/v1/Delete/{messageId}") + postfachFacadeMockServer.stubFor(delete(urlPathTemplate("/MessageExchange/v1/Delete/{messageId}")) .willReturn(ok()) ); osiPostfachRemoteService.deleteMessage(messageId); - postfachFacadeMockServer.verify( exactly(1), - deleteRequestedFor(urlPathEqualTo("/MessageExchange/v1/Delete/{messageId}")) + deleteRequestedFor(urlPathTemplate("/MessageExchange/v1/Delete/{messageId}")) .withPathParam("messageId", equalTo(messageId)) ); } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java index adf3e29..71cd29c 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/OsiMockServerExtension.java @@ -1,6 +1,7 @@ package de.ozgcloud.nachrichten.postfach.osiv2.extension; import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.JwtFactory.*; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.AfterEachCallback; @@ -62,6 +63,11 @@ public class OsiMockServerExtension implements BeforeAllCallback, AfterAllCallba @Override public void beforeEach(ExtensionContext context) { serviceKontoMockServer.stubFor(post("/access-token") + .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded")) + .withFormParam("grant_type", equalTo("client_credentials")) + .withFormParam("client_id", equalTo(CLIENT_ID)) + .withFormParam("scope", equalTo(String.join(" ", CLIENT_SCOPES))) + .withFormParam("resource", equalTo(RESOURCE_URN)) .willReturn(okJson(JwtFactory.createTokenResponse( JwtFactory.createAccessTokenExampleWithExpireIn(900) )))); diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessageTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessageTestFactory.java new file mode 100644 index 0000000..75a60a2 --- /dev/null +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessageTestFactory.java @@ -0,0 +1,15 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.factory; + +import java.util.UUID; + +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; + +public class MessageExchangeReceiveMessageTestFactory { + + public static final UUID MESSAGE_ID = UUID.randomUUID(); + + public static MessageExchangeReceiveMessage create() { + return new MessageExchangeReceiveMessage() + .guid(MESSAGE_ID); + } +} diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java new file mode 100644 index 0000000..8721bbb --- /dev/null +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java @@ -0,0 +1,13 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.factory; + +import java.util.List; + +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; + +public class MessageExchangeReceiveMessagesResponseTestFactory { + + public static MessageExchangeReceiveMessagesResponse create() { + return new MessageExchangeReceiveMessagesResponse() + .messages(List.of()); + } +} diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeSendMessageResponseTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeSendMessageResponseTestFactory.java new file mode 100644 index 0000000..0c296a6 --- /dev/null +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeSendMessageResponseTestFactory.java @@ -0,0 +1,13 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.factory; + +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessageTestFactory.*; + +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeSendMessageResponse; + +public class MessageExchangeSendMessageResponseTestFactory { + + public static MessageExchangeSendMessageResponse create() { + return new MessageExchangeSendMessageResponse() + .messageId(MESSAGE_ID); + } +} diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/V1ReplyMessageFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/V1ReplyMessageTestFactory.java similarity index 51% rename from src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/V1ReplyMessageFactory.java rename to src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/V1ReplyMessageTestFactory.java index 61a52ac..244a643 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/V1ReplyMessageFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/V1ReplyMessageTestFactory.java @@ -7,22 +7,22 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1EidasLevel; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; -public class V1ReplyMessageFactory { +public class V1ReplyMessageTestFactory { - private static String SEQUENCE_NUMMER = "OZG-Cloud-VorgangId"; - private static String SUBJECT = "Das ist das Subject"; - private static String BODY = """ + private static final String SEQUENCE_NUMMER = "OZG-Cloud-VorgangId"; + private static final String SUBJECT = "Das ist das Subject"; + private static final String BODY = """ Das ist das Multiline Body"""; - private static String DISPLAY_NAME = "Das ist der Absender"; - private static String ORIGIN_SENDER = "das ist der original Sender"; - private static String REPLAY_ACTION = "Replypossible"; - private static String EIDAS_LEVEL = "Low"; - private static Boolean IS_OLIGATORY = Boolean.FALSE; - private static Boolean IS_HTML = Boolean.FALSE; - private static String GUID = "123-guid-456"; - private static String MESSAGE_BOX = "Mailbox-Id-Antwortender"; - private static OffsetDateTime RESPONSE_TIME = OffsetDateTime.now(); + private static final String DISPLAY_NAME = "Das ist der Absender"; + private static final String ORIGIN_SENDER = "das ist der original Sender"; + private static final String REPLAY_ACTION = "Replypossible"; + private static final String EIDAS_LEVEL = "Low"; + private static final Boolean IS_OBLIGATORY = Boolean.FALSE; + private static final Boolean IS_HTML = Boolean.FALSE; + private static final String GUID = "123-guid-456"; + private static final String MESSAGE_BOX = "Mailbox-Id-Antwortender"; + private static final OffsetDateTime RESPONSE_TIME = OffsetDateTime.now(); public static V1ReplyMessage create() { return new V1ReplyMessage() @@ -33,7 +33,7 @@ public class V1ReplyMessageFactory { .originSender(ORIGIN_SENDER) .replyAction(V1ReplyBehavior.fromValue(REPLAY_ACTION)) .eidasLevel(V1EidasLevel.fromValue(EIDAS_LEVEL)) - .isObligatory(IS_OLIGATORY) + .isObligatory(IS_OBLIGATORY) .isHtml(IS_HTML) .guid(UUID.nameUUIDFromBytes(GUID.getBytes())) .messageBox(UUID.nameUUIDFromBytes(MESSAGE_BOX.getBytes())) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java index d4c8706..c45f08e 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java @@ -13,14 +13,14 @@ import org.mapstruct.factory.Mappers; import org.mockito.InjectMocks; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; -import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; class ResponseMapperTest { @InjectMocks private ResponseMapper mapper = Mappers.getMapper(ResponseMapper.class); - private V1ReplyMessage message = V1ReplyMessageFactory.create(); + private V1ReplyMessage message = V1ReplyMessageTestFactory.create(); @DisplayName("map V1ReplyMessage to PostfachNachricht") @Nested -- GitLab From 6ad4b450683a4a582d42709a9ac00a56e6f127a3 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Tue, 28 Jan 2025 12:16:56 +0100 Subject: [PATCH 17/22] OZG-4095 wiremock: Remove mockserver dependency --- pom.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pom.xml b/pom.xml index 1e8f3fd..0ad4730 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,6 @@ <properties> <api-lib.version>0.16.0</api-lib.version> <nachrichten-manager.version>2.17.0-SNAPSHOT</nachrichten-manager.version> - <mockserver-client.version>5.15.0</mockserver-client.version> <openapi-generator.version>7.10.0</openapi-generator.version> <swagger-parser.version>2.1.23</swagger-parser.version> <wiremock-spring-boot.version>3.6.0</wiremock-spring-boot.version> @@ -75,17 +74,6 @@ <version>${testcontainers.version}</version> <scope>test</scope> </dependency> - <dependency> - <groupId>org.mock-server</groupId> - <artifactId>mockserver-client-java</artifactId> - <version>${mockserver-client.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.testcontainers</groupId> - <artifactId>mockserver</artifactId> - <scope>test</scope> - </dependency> <dependency> <groupId>org.wiremock.integrations</groupId> -- GitLab From 6f498a945feb0085f6f394d744edecc7965dfed8 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Tue, 28 Jan 2025 13:07:53 +0100 Subject: [PATCH 18/22] OZG-4095 base64: Use from testcontainer dependency --- .../de/ozgcloud/nachrichten/postfach/osiv2/extension/Jwt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/Jwt.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/Jwt.java index 327c91e..b8e053c 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/Jwt.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/extension/Jwt.java @@ -5,7 +5,7 @@ import static de.ozgcloud.nachrichten.postfach.osiv2.factory.JsonUtil.*; import java.io.Serializable; import java.util.Map; -import org.bouncycastle.util.encoders.Base64; +import org.testcontainers.shaded.org.bouncycastle.util.encoders.Base64; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.ReadContext; -- GitLab From f6351d9bd1b50bf4e305188dd23189040ad0059b Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Tue, 28 Jan 2025 13:11:41 +0100 Subject: [PATCH 19/22] OZG-4095 stage-test: Use itcase profile --- .../postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java index 27c5c05..29f64ec 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java @@ -23,7 +23,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachAddressTestFactory import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles({ "stage", "local" }) +@ActiveProfiles({ "stage", "itcase" }) @EnabledIfEnvironmentVariable(named = "SH_STAGE_CLIENT_SECRET", matches = ".+") public class OsiPostfachRemoteServiceRemoteITCase { -- GitLab From ad21ba794148ba1e2aa537b5fb24965f89d47dd9 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Tue, 28 Jan 2025 15:34:11 +0100 Subject: [PATCH 20/22] OZG-4095 bean: Avoid name conflict of requestMapperImpl --- .../{RequestMapper.java => Osi2RequestMapper.java} | 2 +- ...ResponseMapper.java => Osi2ResponseMapper.java} | 3 +-- .../osiv2/transfer/PostfachApiFacadeService.java | 10 +++++----- ...tMapperTest.java => Osi2RequestMapperTest.java} | 4 ++-- ...MapperTest.java => Osi2ResponseMapperTest.java} | 4 ++-- .../transfer/PostfachApiFacadeServiceTest.java | 14 +++++++------- 6 files changed, 18 insertions(+), 19 deletions(-) rename src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/{RequestMapper.java => Osi2RequestMapper.java} (98%) rename src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/{ResponseMapper.java => Osi2ResponseMapper.java} (97%) rename src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/{RequestMapperTest.java => Osi2RequestMapperTest.java} (97%) rename src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/{ResponseMapperTest.java => Osi2ResponseMapperTest.java} (96%) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/RequestMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java similarity index 98% rename from src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/RequestMapper.java rename to src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java index c9a42ae..4b1482c 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/RequestMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapper.java @@ -17,7 +17,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1References; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; @Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR) -public interface RequestMapper { +public interface Osi2RequestMapper { @Mapping(target = "sequencenumber", source = "vorgangId") @Mapping(target = "body", source = "mailBody") diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java similarity index 97% rename from src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapper.java rename to src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java index 84a1b80..f5acb80 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java @@ -1,7 +1,6 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -17,7 +16,7 @@ import lombok.Builder; import lombok.Getter; @Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR, imports = ZoneOffset.class) -public interface ResponseMapper { +public interface Osi2ResponseMapper { String POSTFACH_ADDRESS_VERSION = "2.0"; int POSTFACH_ADDRESS_TYPE = 2; diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index 7f62892..7d3651a 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -20,15 +20,15 @@ import lombok.extern.log4j.Log4j2; public class PostfachApiFacadeService { private final MessageExchangeApi messageExchangeApi; - private final RequestMapper requestMapper; - private final ResponseMapper responseMapper; + private final Osi2RequestMapper osi2RequestMapper; + private final Osi2ResponseMapper osi2ResponseMapper; private static int MAX_NUMBER_RECEIVED_MESSAGES = 100; public void sendMessage(PostfachNachricht nachricht) { messageExchangeApi.sendMessage( - requestMapper.mapMailboxId(nachricht), - requestMapper.mapOutSendMessageRequestV2(nachricht) + osi2RequestMapper.mapMailboxId(nachricht), + osi2RequestMapper.mapOutSendMessageRequestV2(nachricht) ); } @@ -39,7 +39,7 @@ public class PostfachApiFacadeService { PostfachNachricht fetchMessageByGuid(final MessageExchangeReceiveMessage message) { var messageReply = messageExchangeApi.getMessage(message.getGuid()); - return responseMapper.toPostfachNachricht(messageReply); + return osi2ResponseMapper.toPostfachNachricht(messageReply); } public void deleteMessage(final String messageId) { diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/RequestMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java similarity index 97% rename from src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/RequestMapperTest.java rename to src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java index 0e67c3c..3abec1a 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/RequestMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2RequestMapperTest.java @@ -23,9 +23,9 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.OutSendMessageRequestV2; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1EidasLevel; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; -class RequestMapperTest { +class Osi2RequestMapperTest { - private final RequestMapper mapper = Mappers.getMapper(RequestMapper.class); + private final Osi2RequestMapper mapper = Mappers.getMapper(Osi2RequestMapper.class); @DisplayName("map mailbox id") @Nested diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java similarity index 96% rename from src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java rename to src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java index d4c8706..3ec9b50 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/ResponseMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java @@ -16,10 +16,10 @@ import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageFactory; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; -class ResponseMapperTest { +class Osi2ResponseMapperTest { @InjectMocks - private ResponseMapper mapper = Mappers.getMapper(ResponseMapper.class); + private Osi2ResponseMapper mapper = Mappers.getMapper(Osi2ResponseMapper.class); private V1ReplyMessage message = V1ReplyMessageFactory.create(); @DisplayName("map V1ReplyMessage to PostfachNachricht") diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java index 139ba19..c1abebb 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java @@ -32,10 +32,10 @@ class PostfachApiFacadeServiceTest { MessageExchangeApi messageExchangeApi; @Mock - RequestMapper requestMapper; + Osi2RequestMapper osi2RequestMapper; @Mock - ResponseMapper responseMapper; + Osi2ResponseMapper osi2ResponseMapper; @DisplayName("send message") @Nested @@ -51,8 +51,8 @@ class PostfachApiFacadeServiceTest { @BeforeEach void mock() { - when(requestMapper.mapMailboxId(nachricht)).thenReturn(MAILBOX_ID); - when(requestMapper.mapOutSendMessageRequestV2(nachricht)).thenReturn(outSendMessageRequestV2); + when(osi2RequestMapper.mapMailboxId(nachricht)).thenReturn(MAILBOX_ID); + when(osi2RequestMapper.mapOutSendMessageRequestV2(nachricht)).thenReturn(outSendMessageRequestV2); when(messageExchangeApi.sendMessage(any(), any())).thenReturn(messageExchangeSendMessageResponse); } @@ -107,17 +107,17 @@ class PostfachApiFacadeServiceTest { @Test void shouldCallResponseMapper(){ when(messageExchangeApi.getMessage(any())).thenReturn(replyMessage); - when(responseMapper.toPostfachNachricht(any())).thenReturn(PostfachNachrichtTestFactory.create()); + when(osi2ResponseMapper.toPostfachNachricht(any())).thenReturn(PostfachNachrichtTestFactory.create()); postfachApiFacadeService.fetchMessageByGuid(receiveMessage); - verify(responseMapper).toPostfachNachricht(any()); + verify(osi2ResponseMapper).toPostfachNachricht(any()); } @Test void shouldReturnPostfachNachricht(){ when(messageExchangeApi.getMessage(any())).thenReturn(replyMessage); - when(responseMapper.toPostfachNachricht(any())).thenReturn(PostfachNachrichtTestFactory.create()); + when(osi2ResponseMapper.toPostfachNachricht(any())).thenReturn(PostfachNachrichtTestFactory.create()); var postfachNachricht = postfachApiFacadeService.fetchMessageByGuid(receiveMessage); -- GitLab From 4316a99baabb7f49cc0a84ba07448dd98a046208 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Wed, 29 Jan 2025 16:51:56 +0100 Subject: [PATCH 21/22] OZG-4094 Fix NPE for empty messages --- .../postfach/osiv2/transfer/PostfachApiFacadeService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index 7d3651a..b2b1499 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -1,5 +1,7 @@ package de.ozgcloud.nachrichten.postfach.osiv2.transfer; +import java.util.Collection; +import java.util.Optional; import java.util.UUID; import java.util.stream.Stream; @@ -34,7 +36,10 @@ public class PostfachApiFacadeService { public Stream<PostfachNachricht> receiveMessages() { var response = messageExchangeApi.receiveMessages(MAX_NUMBER_RECEIVED_MESSAGES, 0); - return response.getMessages().stream().map(this::fetchMessageByGuid); + return Optional.ofNullable(response.getMessages()) + .stream() + .flatMap(Collection::stream) + .map(this::fetchMessageByGuid); } PostfachNachricht fetchMessageByGuid(final MessageExchangeReceiveMessage message) { -- GitLab From d8fbdaf38868d95719f869d474f343721c508211 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Thu, 30 Jan 2025 16:47:53 +0100 Subject: [PATCH 22/22] OZG-4094 merge: Adjust config values --- .../postfach/osiv2/config/Osi2PostfachProperties.java | 6 +++--- src/main/resources/application-stage.yml | 4 ++-- .../postfach/osiv2/OsiPostfachRemoteServiceITCase.java | 2 +- .../osiv2/OsiPostfachRemoteServiceRemoteITCase.java | 1 - .../postfach/osiv2/OsiPostfachRemoteServiceTest.java | 1 + src/test/resources/application-itcase.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java index 6d4bb53..81ef462 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java @@ -17,7 +17,7 @@ import lombok.Setter; @RequiredArgsConstructor public class Osi2PostfachProperties { - static final String PREFIX = "ozgcloud.osiv2"; + public static final String PREFIX = "ozgcloud.osiv2"; private boolean enabled; @@ -30,7 +30,7 @@ public class Osi2PostfachProperties { @Configuration @ConfigurationProperties(prefix = ApiConfiguration.PREFIX) public static class ApiConfiguration { - static final String PREFIX = Osi2PostfachProperties.PREFIX + ".api"; + public static final String PREFIX = Osi2PostfachProperties.PREFIX + ".api"; private String resource; private String url; @@ -47,7 +47,7 @@ public class Osi2PostfachProperties { @Configuration @ConfigurationProperties(prefix = ProxyConfiguration.PREFIX) public static class ProxyConfiguration { - static final String PREFIX = Osi2PostfachProperties.PREFIX + ".proxy"; + public static final String PREFIX = Osi2PostfachProperties.PREFIX + ".proxy"; private boolean enabled; diff --git a/src/main/resources/application-stage.yml b/src/main/resources/application-stage.yml index 6892480..c2804ac 100644 --- a/src/main/resources/application-stage.yml +++ b/src/main/resources/application-stage.yml @@ -13,14 +13,14 @@ spring: osi2: token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token' ozgcloud: - osiv2-postfach: + osiv2: enabled: false api: resource: 'urn:dataport:osi:postfach:rz2:stage:sh' url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0' tenant: 'SH' name-identifier: 'ozgkopfstelle' - http-proxy: + proxy: enabled: true host: 127.0.0.1 port: 3128 diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java index d521985..53c668b 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceITCase.java @@ -38,7 +38,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMe import lombok.SneakyThrows; @SpringBootTest(classes = TestApplication.class) -@ActiveProfiles({"stage", "itcase"}) +@ActiveProfiles({ "stage", "itcase" }) @TestPropertySource(properties = { "ozgcloud.osiv2.proxy.enabled=false", }) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java index 482ed08..bfe893d 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceRemoteITCase.java @@ -6,7 +6,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java index a00ab88..685c36f 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java @@ -81,6 +81,7 @@ class OsiPostfachRemoteServiceTest { verify(postfachApiFacadeService).deleteMessage(any()); } + @DisplayName("should throw osi postfach exception on runtime exception") @Test void shouldThrowOsiPostfachExceptionOnRuntimeException() { diff --git a/src/test/resources/application-itcase.yml b/src/test/resources/application-itcase.yml index d8cacf7..41e8478 100644 --- a/src/test/resources/application-itcase.yml +++ b/src/test/resources/application-itcase.yml @@ -1,5 +1,5 @@ ozgcloud: - osiv2-postfach: + osiv2: enabled: true logging: level: -- GitLab