From e0ff858d410817f8ef05d8659934b89b6248696d Mon Sep 17 00:00:00 2001
From: Jan Zickermann <jan.zickermann@dataport.de>
Date: Fri, 18 Oct 2024 15:33:17 +0200
Subject: [PATCH] OZG-6891 KOP-2733 Test fetchMessages in XtaClientRemoteITCase

---
 .../xdomea/XdomeaXtaMessageCreator.java       |   4 +
 .../xta/client/XtaClientRemoteITCase.java     | 252 +++++++++++++++---
 .../XtaRemoteServerSetupExtension.java        |  67 +++--
 .../XtaServerSetupExtensionTestUtil.java      |  56 +++-
 .../xta-message.yaml                          |   2 +-
 5 files changed, 300 insertions(+), 81 deletions(-)

diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java b/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java
index 2bd66d7..68ad3d9 100644
--- a/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java
+++ b/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java
@@ -32,6 +32,10 @@ public class XdomeaXtaMessageCreator {
 	private final ZipFileEntryReader zipFileEntryReader;
 	private final XdomeaMetaDataValidator metaDataValidator;
 
+	public static XdomeaXtaMessageCreator createInstance() {
+		return XdomeaXtaMessageCreatorFactory.createInstance().create();
+	}
+
 	public XtaMessage createMessage(XtaFile xdomeaZipFile) throws ClientException {
 		return XtaMessage.builder()
 				.metaData(deriveValidMetaData(xdomeaZipFile))
diff --git a/src/test/java/de/ozgcloud/xta/client/XtaClientRemoteITCase.java b/src/test/java/de/ozgcloud/xta/client/XtaClientRemoteITCase.java
index 5aa5fc7..6f0d11b 100644
--- a/src/test/java/de/ozgcloud/xta/client/XtaClientRemoteITCase.java
+++ b/src/test/java/de/ozgcloud/xta/client/XtaClientRemoteITCase.java
@@ -1,24 +1,39 @@
 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.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
 import org.junit.Ignore;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
 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.xdomea.XdomeaXtaMessageCreatorFactory;
+import de.ozgcloud.xta.client.model.XtaTransportReport;
+import de.ozgcloud.xta.client.xdomea.XdomeaXtaMessageCreator;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 
@@ -36,62 +51,239 @@ class XtaClientRemoteITCase {
 	@RegisterExtension
 	static final XtaRemoteServerSetupExtension XTA_REMOTE_SERVER_SETUP_EXTENSION = new XtaRemoteServerSetupExtension();
 
-	private XtaClient authorClient;
-	private XtaClient readerClient;
+	private static final XdomeaXtaMessageCreator XDOMEA_XTA_MESSAGE_CREATOR = XdomeaXtaMessageCreator.createInstance();
+
+	private static XtaClient testClient;
+	private static XtaClient silentTestClient;
+	private static XtaClient devClient;
+	private static XtaClient silentDevClient;
+
+	private List<XtaMessageMetaData> supportCheckedMetadataItems;
+	private List<XtaMessage> processedMessages;
+	private Consumer<XtaMessage> processMessageDummy;
+	private Predicate<XtaMessageMetaData> isSupportedDummy;
+
+	@BeforeAll
+	static void checkNoMessagePending() {
+		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();
+
+		throwIfAnyMessagePending(silentDevClient, DEV_READER_CLIENT_IDENTIFIER);
+		throwIfAnyMessagePending(silentTestClient, TEST_READER_CLIENT_IDENTIFIER);
+	}
 
 	@BeforeEach
 	@SneakyThrows
 	void setup() {
-		authorClient = XTA_REMOTE_SERVER_SETUP_EXTENSION.getAuthorClient();
-		readerClient = XTA_REMOTE_SERVER_SETUP_EXTENSION.getReaderClient();
+		processMessageDummy = (message) -> {
+		};
+		supportCheckedMetadataItems = new ArrayList<>();
+		isSupportedDummy = (metaData) -> true;
+		processedMessages = new ArrayList<>();
+		StaticStringListAppender.clearLogLines();
+	}
+
+	@AfterEach
+	void cleanup() {
+		closeMessagesForAllReaders();
+	}
+
+	private void closeMessagesForAllReaders() {
+		closeAllMessages(silentDevClient, DEV_READER_CLIENT_IDENTIFIER);
+		closeAllMessages(silentTestClient, TEST_READER_CLIENT_IDENTIFIER);
 	}
 
 	@DisplayName("fetch messages")
 	@Nested
 	class TestFetchMessages {
-		// TODO KOP-2733
+
+		private List<XtaMessage> sendMessages;
+		private List<String> sendMessageIds;
+
+		@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)
+					.haveExactlyGreenStatusFor(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)
+					.haveExactlyGreenStatusFor(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)
+					.haveExactlyGreenStatusFor(
+							messageIdBySendIndex(0),
+							messageIdBySendIndex(1), messageIdBySendIndex(2), messageIdBySendIndex(3)
+					);
+		}
+
+		@SneakyThrows
+		private void setupClientsWithIdentifiers(List<XtaIdentifier> identifiers) {
+			devClient = createClientWithIdentifiersAndClientCert(
+					identifiers,
+					XTA_REMOTE_SERVER_SETUP_EXTENSION.getDevClientCertKeyStore()
+			);
+			testClient = createClientWithIdentifiersAndClientCert(
+					identifiers,
+					XTA_REMOTE_SERVER_SETUP_EXTENSION.getTestClientCertKeyStore()
+			);
+		}
+
+		@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();
+		}
+
+		private List<XtaTransportReport> fetchDevMessages() {
+			return devClient.fetchMessages(this::processMessage);
+		}
+
+		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 {
 
-		@AfterEach
-		@SneakyThrows
-		void afterEach() {
-			closeAllMessages(readerClient, READER_CLIENT_IDENTIFIER1);
-		}
-
 		@DisplayName("should return transport report with open status")
 		@SneakyThrows
 		@ParameterizedTest
 		@ValueSource(strings = { "dfoerdermittel", "abgabe0401-kleiner-waffenschein" })
 		void shouldReturn(String messageLabel) {
-			XtaMessage xtaMessage = createXdomeaMessage(messageLabel);
+			XtaMessage xtaMessage = createXdomeaMessage(loadMessage(messageLabel).messageFile());
 
-			var result = authorClient.sendMessage(xtaMessage);
+			var result = testClient.sendMessage(xtaMessage);
 
 			assertThat(result.status()).isEqualTo(XtaMessageStatus.OPEN);
 		}
+	}
 
-		@SneakyThrows
-		private static XtaMessage createXdomeaMessage(
-				String messageLabel) {
-			var creator = XdomeaXtaMessageCreatorFactory
-					.createInstance()
-					.create();
+	private XtaMessage createMessage(String messageLabel, XtaIdentifier author, XtaIdentifier reader) {
+		return XtaMessageExampleLoader.load(
+				XtaMessageExampleLoader.MessageExampleConfig.builder()
+						.messageLabel(messageLabel)
+						.reader(reader)
+						.author(author)
+						.build());
+	}
 
-			return creator.createMessage(loadMessageFile(messageLabel));
-		}
+	@SneakyThrows
+	private static XtaMessage createXdomeaMessage(XtaFile messageFile) {
+		return XDOMEA_XTA_MESSAGE_CREATOR.createMessage(messageFile);
+	}
 
-		private static XtaFile loadMessageFile(String messageLabel) {
-			var message = XtaMessageExampleLoader.load(XtaMessageExampleLoader.MessageExampleConfig.builder()
-					.messageLabel(messageLabel)
-					.author(AUTHOR_CLIENT_IDENTIFIER)
-					.reader(READER_CLIENT_IDENTIFIER1)
-					.build());
-			return message.messageFile();
-		}
+	private static XtaMessage loadMessage(String messageLabel) {
+		return XtaMessageExampleLoader.load(XtaMessageExampleLoader.MessageExampleConfig.builder()
+				.messageLabel(messageLabel)
+				.author(AUTHOR_CLIENT_IDENTIFIER)
+				.reader(READER_CLIENT_IDENTIFIER1)
+				.build());
 	}
 
 }
diff --git a/src/test/java/de/ozgcloud/xta/client/extension/XtaRemoteServerSetupExtension.java b/src/test/java/de/ozgcloud/xta/client/extension/XtaRemoteServerSetupExtension.java
index d59023b..34d8b06 100644
--- a/src/test/java/de/ozgcloud/xta/client/extension/XtaRemoteServerSetupExtension.java
+++ b/src/test/java/de/ozgcloud/xta/client/extension/XtaRemoteServerSetupExtension.java
@@ -6,7 +6,6 @@ import java.io.File;
 import java.util.Objects;
 
 import org.junit.jupiter.api.extension.BeforeAllCallback;
-import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
 import com.google.common.io.Files;
@@ -15,7 +14,6 @@ import de.ozgcloud.xta.client.XtaClient;
 import de.ozgcloud.xta.client.XtaClientFactory;
 import de.ozgcloud.xta.client.config.XtaClientConfig;
 import de.ozgcloud.xta.client.core.WrappedXtaService;
-import de.ozgcloud.xta.client.model.XtaMessage;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -25,12 +23,16 @@ import lombok.extern.slf4j.Slf4j;
 @Getter
 @Setter
 @Slf4j
-public class XtaRemoteServerSetupExtension implements BeforeAllCallback, BeforeEachCallback {
+public class XtaRemoteServerSetupExtension implements BeforeAllCallback {
+
+	private XtaClient testClient;
+	private XtaClient silentTestClient;
+	private XtaClientConfig.KeyStore testClientCertKeyStore;
+	private XtaClient devClient;
+	private XtaClient silentDevClient;
+	private XtaClientConfig.KeyStore devClientCertKeyStore;
 
-	private XtaClient authorClient;
-	private XtaClient readerClient;
 	private WrappedXtaService service;
-	private XtaClientConfig config;
 	private XtaClientFactory clientFactory;
 
 	static final String BASE_URL = "https://li33-0005.dp.dsecurecloud.de/MB_XTA-WS/XTA210";
@@ -38,54 +40,47 @@ public class XtaRemoteServerSetupExtension implements BeforeAllCallback, BeforeE
 	@Override
 	@SneakyThrows
 	public void beforeAll(ExtensionContext context) {
-		authorClient = setupClient(getEnvVar("KOP_SH_KIEL_TEST_PATH"), getEnvVar("KOP_SH_KIEL_TEST_PASSWORD"));
-		readerClient = setupClient(getEnvVar("KOP_SH_KIEL_DEV_PATH"), getEnvVar("KOP_SH_KIEL_DEV_PASSWORD"));
+		testClientCertKeyStore = createClientCertKeyStore(getEnvVar("KOP_SH_KIEL_TEST_PATH"), getEnvVar("KOP_SH_KIEL_TEST_PASSWORD"));
+		testClient = setupClient(testClientCertKeyStore, true);
+		silentTestClient = setupClient(testClientCertKeyStore, false);
+		devClientCertKeyStore = createClientCertKeyStore(getEnvVar("KOP_SH_KIEL_DEV_PATH"), getEnvVar("KOP_SH_KIEL_DEV_PASSWORD"));
+		devClient = setupClient(devClientCertKeyStore, true);
+		silentDevClient = setupClient(devClientCertKeyStore, false);
 	}
 
-	@SneakyThrows
-	XtaClient setupClient(String clientCertKeystorePath, String clientCertKeystorePassword) {
-		var clientCertKeyStore = XtaClientConfig.KeyStore.builder()
+	private XtaClientConfig.KeyStore createClientCertKeyStore(String clientCertKeystorePath, String clientCertKeystorePassword) {
+		return XtaClientConfig.KeyStore.builder()
 				.content(readBytesFromFile(clientCertKeystorePath))
 				.type("PKCS12")
 				.password(clientCertKeystorePassword.toCharArray())
 				.build();
-		config = createClientConfigBuilder()
-				.managementServiceUrl(BASE_URL + "managementPort.svc")
-				.sendServiceUrl(BASE_URL + "sendPort.svc")
-				.msgBoxServiceUrl(BASE_URL + "msgBoxPort.svc")
+	}
+
+	@SneakyThrows
+	XtaClient setupClient(XtaClientConfig.KeyStore clientCertKeyStore, boolean verbose) {
+		return XtaClient.from(createSpecificClientConfigBuilder()
+				.logSoapRequests(verbose)
+				.logSoapResponses(verbose)
 				.clientCertKeystore(clientCertKeyStore)
-				.build();
-		clientFactory = XtaClientFactory.from(config);
-		return clientFactory.create();
+				.build());
 	}
 
 	private String getEnvVar(String name) {
 		return Objects.requireNonNull(System.getenv(name), "Environment variable " + name + " is required!");
 	}
 
-	@Override
-	@SneakyThrows
-	public void beforeEach(ExtensionContext context) {
-		XtaServerSetupExtensionTestUtil.closeAllMessages(readerClient, READER_CLIENT_IDENTIFIER1);
-	}
-
-	@SneakyThrows
-	public String sendTestMessage() {
-		return XtaServerSetupExtensionTestUtil.sendTestMessage(authorClient, XtaMessageExampleLoader.MessageExampleConfig.builder()
-				.messageLabel("dfoerdermittel")
-				.reader(READER_CLIENT_IDENTIFIER1)
-				.author(AUTHOR_CLIENT_IDENTIFIER)
-				.build());
-	}
 
 	@SneakyThrows
-	public String sendTestMessage(XtaMessage message) {
-		return XtaServerSetupExtensionTestUtil.sendTestMessage(authorClient, message);
+	private static byte[] readBytesFromFile(String path) {
+		return Files.toByteArray(new File(path));
 	}
 
 	@SneakyThrows
-	private static byte[] readBytesFromFile(String path) {
-		return Files.toByteArray(new File(path));
+	public XtaClientConfig.XtaClientConfigBuilder createSpecificClientConfigBuilder() {
+		return createClientConfigBuilder()
+				.managementServiceUrl(BASE_URL + "managementPort.svc")
+				.sendServiceUrl(BASE_URL + "sendPort.svc")
+				.msgBoxServiceUrl(BASE_URL + "msgBoxPort.svc");
 	}
 
 }
diff --git a/src/test/java/de/ozgcloud/xta/client/extension/XtaServerSetupExtensionTestUtil.java b/src/test/java/de/ozgcloud/xta/client/extension/XtaServerSetupExtensionTestUtil.java
index 2c445b8..7582333 100644
--- a/src/test/java/de/ozgcloud/xta/client/extension/XtaServerSetupExtensionTestUtil.java
+++ b/src/test/java/de/ozgcloud/xta/client/extension/XtaServerSetupExtensionTestUtil.java
@@ -32,11 +32,24 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class XtaServerSetupExtensionTestUtil {
 
-	public static final XtaIdentifier AUTHOR_CLIENT_IDENTIFIER = XtaIdentifier.builder()
+	public static final XtaIdentifier DEV_READER_CLIENT_IDENTIFIER = XtaIdentifier.builder()
+			.value("gae:dev-environment@ozg-cloud.de")
+			.category("Generischer Antragsempfänger")
+			.name("OZG-Cloud Leser Dev")
+			.build();
+	public static final XtaIdentifier TEST_READER_CLIENT_IDENTIFIER = XtaIdentifier.builder()
+			.value("gae:test-environment@ozg-cloud.de")
+			.category("Generischer Antragsempfänger")
+			.name("OZG-Cloud Leser Test")
+			.build();
+
+	public static final XtaIdentifier TEST_AUTHOR_CLIENT_IDENTIFIER = XtaIdentifier.builder()
 			.value("gad:010103000000")
 			.category("DMS Schleswig-Holstein")
 			.name("Generischer Antragsdienst")
 			.build();
+
+	public static final XtaIdentifier AUTHOR_CLIENT_IDENTIFIER = TEST_AUTHOR_CLIENT_IDENTIFIER;
 	public static final XtaIdentifier AUTHOR_CLIENT_IDENTIFIER2 = XtaIdentifier.builder()
 			.value("ehp:010100100000")
 			.category("Engagement- und Hobbyportal (FIM Sender)")
@@ -48,22 +61,16 @@ public class XtaServerSetupExtensionTestUtil {
 			.name("OSI-Onlinedienst Hamburg Versammlungsanzeige Test")
 			.build();
 
-	public static final XtaIdentifier READER_CLIENT_IDENTIFIER2 = XtaIdentifier.builder()
-			.value("gae:test-environment@ozg-cloud.de")
-			.category("Generischer Antragsempfänger")
-			.name("OZG-Cloud Test")
-			.build();
-	public static final XtaIdentifier READER_CLIENT_IDENTIFIER1 = XtaIdentifier.builder()
-			.value("gae:dev-environment@ozg-cloud.de")
-			.category("Generischer Antragsempfänger")
-			.name("OZG-Cloud Dev")
-			.build();
+	public static final XtaIdentifier READER_CLIENT_IDENTIFIER1 = DEV_READER_CLIENT_IDENTIFIER;
+	public static final XtaIdentifier READER_CLIENT_IDENTIFIER2 = TEST_READER_CLIENT_IDENTIFIER;
 	public static final XtaIdentifier READER_CLIENT_IDENTIFIER3 = XtaIdentifier.builder()
 			.value("vbe:010510440100")
 			.category("Versammlungsbehörde (FIM Empfänger)")
 			.name("Kreisordnungsbehörde Dithmarschen")
 			.build();
 
+
+
 	public static XtaClientConfig.XtaClientConfigBuilder createClientConfigBuilder() {
 		return XtaClientConfig.builder()
 				.clientIdentifiers(emptyList())
@@ -102,10 +109,18 @@ public class XtaServerSetupExtensionTestUtil {
 		log.error("[{}] {}", fehlernummer.getCode(), fehlernummer.getName());
 	}
 
+	@SneakyThrows
+	public static void throwIfAnyMessagePending(XtaClient client, XtaIdentifier clientId) {
+		var wrappedService = getWrappedService(client);
+		var result = wrappedService.getStatusList(clientId, 1);
+		if (!result.messages().isEmpty()) {
+			fail("Expect no pending xta-messages for reader %s!".formatted(clientId.value()));
+		}
+	}
+
 	@SneakyThrows
 	public static void closeAllMessages(XtaClient client, XtaIdentifier clientId) {
-		XtaClientService clientService = getPrivateFieldValue(client, "service");
-		WrappedXtaService wrappedService = getPrivateFieldValue(clientService, "service");
+		var wrappedService = getWrappedService(client);
 
 		var result = wrappedService.getStatusList(clientId, 100);
 		var messageIds = result.messages().stream()
@@ -116,6 +131,11 @@ public class XtaServerSetupExtensionTestUtil {
 		}
 	}
 
+	private static WrappedXtaService getWrappedService(XtaClient client) {
+		XtaClientService clientService = getPrivateFieldValue(client, "service");
+		return getPrivateFieldValue(clientService, "service");
+	}
+
 	@SuppressWarnings("unchecked")
 	@SneakyThrows
 	private static <T> T getPrivateFieldValue(Object object, String fieldName) {
@@ -131,6 +151,12 @@ public class XtaServerSetupExtensionTestUtil {
 				.build();
 	}
 
+	public static XtaMessageMetaData withoutMessageSize(XtaMessageMetaData metaData) {
+		return metaData.toBuilder()
+				.messageSize(null)
+				.build();
+	}
+
 	public record MessagesAssert(List<XtaMessage> processedMessages) {
 		public MessagesAssert containExactlyInAnyOrder(XtaMessage... messages) {
 			try {
@@ -244,11 +270,13 @@ public class XtaServerSetupExtensionTestUtil {
 								.map(XtaMessage::metaData)
 								.map(XtaMessageMetaData::messageId)
 								.toList());
-				// Compare message metadata
+				// Compare message metadata (ignoring size since it may be null for transport report (due to message closed?))
 				assertThat(transportReports)
 						.extracting(XtaTransportReport::metaData)
+						.extracting(XtaServerSetupExtensionTestUtil::withoutMessageSize)
 						.containsExactlyElementsOf(processedMessages.stream()
 								.map(XtaMessage::metaData)
+								.map(XtaServerSetupExtensionTestUtil::withoutMessageSize)
 								.toList());
 			} catch (AssertionError | RuntimeException e) {
 				log.error("TransportReports do not exactly match messages metadata!");
diff --git a/src/test/resources/messages/abgabe0401-kleiner-waffenschein/xta-message.yaml b/src/test/resources/messages/abgabe0401-kleiner-waffenschein/xta-message.yaml
index 1b1adb5..4be291a 100644
--- a/src/test/resources/messages/abgabe0401-kleiner-waffenschein/xta-message.yaml
+++ b/src/test/resources/messages/abgabe0401-kleiner-waffenschein/xta-message.yaml
@@ -1,5 +1,5 @@
 metaData:
-  service: urn:xoev-de:xdomea:schema:3.0.0/xdomea300Antrag.wsdl
+  service: urn:xoev-de:xdomea:schema:3.0.0/xdomea300Abgabe.wsdl
   businessScenarioCode: XDOMEAGAD_DATA
   businessScenarioListUri: urn:de:dataport:codeliste:business.scenario
   businessScenarioListVersionId: 1.0
-- 
GitLab