package de.ozgcloud.xta.client; import static de.ozgcloud.xta.client.XtaClientITCase.*; import static de.ozgcloud.xta.client.extension.XtaServerSetupExtensionTestUtil.*; import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import de.ozgcloud.xta.client.config.XtaClientConfig; import de.ozgcloud.xta.client.extension.StaticStringListAppender; import de.ozgcloud.xta.client.extension.XtaMessageExampleLoader; import de.ozgcloud.xta.client.extension.XtaRemoteServerSetupExtension; import de.ozgcloud.xta.client.model.XtaFile; import de.ozgcloud.xta.client.model.XtaIdentifier; import de.ozgcloud.xta.client.model.XtaMessage; import de.ozgcloud.xta.client.model.XtaMessageMetaData; import de.ozgcloud.xta.client.model.XtaMessageStatus; import de.ozgcloud.xta.client.model.XtaTransportReport; import de.ozgcloud.xta.client.xdomea.XdomeaXtaMessageCreator; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @Slf4j @EnabledIfEnvironmentVariable( named = "KOP_SH_KIEL_DEV_PATH", matches = ".+", disabledReason = "This test requires the path KOP_SH_KIEL_{DEV,TEST}_PATH and password KOP_SH_KIEL_{DEV,TEST}_PASSWORD of KOP_SH_KIEL_DEV.p12 and OZG-CLOUD_SH_KIEL_TEST.pfx. " + "Additionally, the endpoint of the DEV-xta-server at li33-0005.dp.dsecurecloud.de must be reachable." ) class XtaClientRemoteITCase { @RegisterExtension private static final XtaRemoteServerSetupExtension XTA_REMOTE_SERVER_SETUP_EXTENSION = new XtaRemoteServerSetupExtension(); private static final XdomeaXtaMessageCreator XDOMEA_XTA_MESSAGE_CREATOR = XdomeaXtaMessageCreator.createInstance(); private XtaClient testClient; private XtaClient silentTestClient; private XtaClient devClient; private XtaClient silentDevClient; private List<XtaMessageMetaData> supportCheckedMetadataItems; private List<XtaMessage> processedMessages; private Consumer<XtaMessage> processMessageDummy; private Predicate<XtaMessageMetaData> isSupportedDummy; private List<String> sendMessageIds; @BeforeEach @SneakyThrows void setup() { processMessageDummy = message -> { }; supportCheckedMetadataItems = new ArrayList<>(); isSupportedDummy = metaData -> true; processedMessages = new ArrayList<>(); testClient = XTA_REMOTE_SERVER_SETUP_EXTENSION.getTestClient(); silentTestClient = XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentTestClient(); devClient = XTA_REMOTE_SERVER_SETUP_EXTENSION.getDevClient(); silentDevClient = XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentDevClient(); if (Optional.ofNullable(System.getenv("CLEAR_ALL_MESSAGES")).map(d -> d.equals("yes")).orElse(false)) { closeAllMessages(XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentDevClientConfig(), DEV_READER_CLIENT_IDENTIFIER); closeAllMessages(XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentTestClientConfig(), TEST_READER_CLIENT_IDENTIFIER); } failIfAnyMessagePending(XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentDevClientConfig(), DEV_READER_CLIENT_IDENTIFIER); failIfAnyMessagePending(XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentTestClientConfig(), TEST_READER_CLIENT_IDENTIFIER); StaticStringListAppender.clearLogLines(); } @AfterEach void cleanup() { closeMessagesForAllReaders(); } private void closeMessagesForAllReaders() { closeMessagesById(XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentDevClientConfig(), DEV_READER_CLIENT_IDENTIFIER, sendMessageIds); closeMessagesById(XTA_REMOTE_SERVER_SETUP_EXTENSION.getSilentTestClientConfig(), TEST_READER_CLIENT_IDENTIFIER, sendMessageIds); } @DisplayName("fetch messages") @Nested class TestFetchMessages { private List<XtaMessage> sendMessages; @BeforeEach void setup() { sendMessages = List.of( createMessage("dfoerdermittel", DEV_READER_CLIENT_IDENTIFIER, DEV_READER_CLIENT_IDENTIFIER), createMessage("dfoerdermittel", DEV_READER_CLIENT_IDENTIFIER, TEST_READER_CLIENT_IDENTIFIER), createMessage("abgabe0401-kleiner-waffenschein", TEST_AUTHOR_CLIENT_IDENTIFIER, TEST_READER_CLIENT_IDENTIFIER), createMessage("dfoerdermittel", TEST_READER_CLIENT_IDENTIFIER, TEST_READER_CLIENT_IDENTIFIER) ); sendMessageIds = sendMessages.stream() .map(message -> sendTestMessage( message.metaData().authorIdentifier().equals(DEV_READER_CLIENT_IDENTIFIER) ? silentDevClient : silentTestClient, message)) .toList(); } @DisplayName("should fetch no messages if no client identifier is configured") @Test void shouldFetchNoMessagesIfNoClientIdentifierIsConfigured() { setupClientsWithIdentifiers(emptyList()); var messages = fetchMessages(); assertThat(supportCheckedMetadataItems).isEmpty(); assertThat(processedMessages).isEmpty(); assertThat(messages).isEmpty(); } @DisplayName("should fetch no messages if client identifier has no messages pending") @Test void shouldFetchNoMessagesIfClientIdentifierHasNoMessagesPending() { setupClientsWithIdentifiers(List.of(TEST_AUTHOR_CLIENT_IDENTIFIER)); var messages = fetchMessages(); assertThat(supportCheckedMetadataItems).isEmpty(); assertThat(processedMessages).isEmpty(); assertThat(messages).isEmpty(); } @DisplayName("should fetch messages from first reader") @Test @SneakyThrows void shouldFetchMessagesFromFirstReader() { setupClientsWithIdentifiers(List.of(DEV_READER_CLIENT_IDENTIFIER)); var transportReports = fetchMessages(); assertThat(supportCheckedMetadataItems).hasSize(1); assertThatMessages(processedMessages).containExactlyInAnyOrder(sendMessages.getFirst()); assertThatTransportReports(transportReports) .reportExactlyFor(processedMessages) .haveExactlyClosedStatusFor(messageIdBySendIndex(0)); } @DisplayName("should fetch messages from second reader") @Test void shouldFetchMessagesFromSecondReader() { setupClientsWithIdentifiers(List.of(TEST_READER_CLIENT_IDENTIFIER)); var transportReports = fetchMessages(); assertThat(supportCheckedMetadataItems).hasSize(3); assertThatMessages(processedMessages).containExactlyInAnyOrder(sendMessages.get(1), sendMessages.get(2), sendMessages.get(3)); assertThatTransportReports(transportReports) .reportExactlyFor(processedMessages) .haveExactlyClosedStatusFor(messageIdBySendIndex(1), messageIdBySendIndex(2), messageIdBySendIndex(3)); } @DisplayName("should fetch messages from first and second reader") @Test void shouldFetchMessagesFromFirstAndSecondReader() { setupClientsWithIdentifiers(List.of(DEV_READER_CLIENT_IDENTIFIER, TEST_READER_CLIENT_IDENTIFIER)); var transportReports = fetchMessages(); assertThat(supportCheckedMetadataItems).hasSize(1 + 3); assertThatMessages(processedMessages).containExactlyInAnyOrder( sendMessages.get(0), sendMessages.get(1), sendMessages.get(2), sendMessages.get(3) ); assertThatTransportReports(transportReports) .reportExactlyFor(processedMessages) .haveExactlyClosedStatusFor( messageIdBySendIndex(0), messageIdBySendIndex(1), messageIdBySendIndex(2), messageIdBySendIndex(3) ); } @SneakyThrows private void setupClientsWithIdentifiers(List<XtaIdentifier> identifiers) { devClient = createClientWithIdentifiersAndClientCert( identifiers, XTA_REMOTE_SERVER_SETUP_EXTENSION.getDevClientConfig().getClientCertKeystore() ); testClient = createClientWithIdentifiersAndClientCert( identifiers, XTA_REMOTE_SERVER_SETUP_EXTENSION.getTestClientConfig().getClientCertKeystore() ); } @SneakyThrows private XtaClient createClientWithIdentifiersAndClientCert(List<XtaIdentifier> identifiers, XtaClientConfig.KeyStore clientCertKeyStore) { return XtaClient.from( XTA_REMOTE_SERVER_SETUP_EXTENSION.createSpecificClientConfigBuilder() .clientCertKeystore(clientCertKeyStore) .clientIdentifiers(identifiers) .maxListItems(TWO_MAX_LIST_ITEMS) .isMessageSupported(this::isSupported) .build() ); } private boolean isSupported(XtaMessageMetaData metaData) { supportCheckedMetadataItems.add(metaData); return isSupportedDummy.test(metaData); } private String messageIdBySendIndex(int sendIndex) { return sendMessageIds.get(sendIndex); } private List<XtaTransportReport> fetchMessages() { return Stream.concat( fetchDevMessages().stream(), fetchTestMessages().stream() ).toList(); } @SneakyThrows private List<XtaTransportReport> fetchDevMessages() { return devClient.fetchMessages(this::processMessage); } @SneakyThrows private List<XtaTransportReport> fetchTestMessages() { return testClient.fetchMessages(this::processMessage); } private void processMessage(XtaMessage message) { processedMessages.add(message); processMessageDummy.accept(message); } } @DisplayName("send message") @Nested class TestSendMessage { @DisplayName("should return transport report with open status") @SneakyThrows @ParameterizedTest @ValueSource(strings = { "dfoerdermittel", "abgabe0401-kleiner-waffenschein" }) void shouldReturn(String messageLabel) { XtaMessage xtaMessage = createXdomeaMessage(loadMessage(messageLabel).messageFile()); var result = sendMessage(xtaMessage); assertThat(result.status()).isEqualTo(XtaMessageStatus.OPEN); } @SneakyThrows private XtaTransportReport sendMessage(XtaMessage xtaMessage) { var report = testClient.sendMessage(xtaMessage); recordMessageIdForCleanup(report); return report; } private void recordMessageIdForCleanup(XtaTransportReport report) { var messageId = report.metaData().messageId(); assertThat(messageId).isNotNull(); sendMessageIds = List.of(messageId); } } private XtaMessage createMessage(String messageLabel, XtaIdentifier author, XtaIdentifier reader) { return XtaMessageExampleLoader.load( XtaMessageExampleLoader.MessageExampleConfig.builder() .messageLabel(messageLabel) .reader(reader) .author(author) .build()); } @SneakyThrows private static XtaMessage createXdomeaMessage(XtaFile messageFile) { return XDOMEA_XTA_MESSAGE_CREATOR.createMessage(messageFile); } private static XtaMessage loadMessage(String messageLabel) { return XtaMessageExampleLoader.load(XtaMessageExampleLoader.MessageExampleConfig.builder() .messageLabel(messageLabel) .author(AUTHOR_CLIENT_IDENTIFIER) .reader(READER_CLIENT_IDENTIFIER1) .build()); } }