From c2c170f3433e2cdadfa75ce685c92d37ff1bcb7c Mon Sep 17 00:00:00 2001
From: Jan Zickermann <jan.zickermann@dataport.de>
Date: Thu, 26 Sep 2024 16:17:14 +0200
Subject: [PATCH] OZG-6754 KOP-2703 Validate zip file name

---
 .../xdomea/XdomeaXtaMessageCreator.java       | 17 ++++-
 .../xdomea/reader/XdomeaValueReader.java      |  2 +
 .../reader/XdomeaValueReaderFactory.java      |  1 +
 .../client/xdomea/reader/XdomeaXmlValues.java |  1 +
 .../factory/XdomeaXmlValuesTestFactory.java   |  3 +-
 .../xdomea/XdomeaXtaMessageCreatorTest.java   | 71 +++++++++++++++++--
 .../reader/XdomeaValueReaderFactoryTest.java  |  5 ++
 .../xdomea/reader/XdomeaValueReaderTest.java  | 10 +++
 8 files changed, 103 insertions(+), 7 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 3bacbe6..cfbade2 100644
--- a/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java
+++ b/src/main/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreator.java
@@ -42,12 +42,27 @@ public class XdomeaXtaMessageCreator {
 	XtaMessageMetaData deriveMetaData(XtaFile xdomeaZipFile) throws ClientException {
 		try {
 			var xdomeaXmlValues = readXdomeaXmlValues(xdomeaZipFile);
-			return metadataMapper.mapXtaMessageMetadata(xdomeaXmlValues);
+			var messageMetadataData = metadataMapper.mapXtaMessageMetadata(xdomeaXmlValues);
+			validateZipFileName(
+					xdomeaZipFile.name(),
+					xdomeaXmlValues.processId(),
+					messageMetadataData.messageTypeCode()
+			);
+			return messageMetadataData;
 		} catch (TechnicalException e) {
 			throw new ClientException("Failed to derive message metadata from xdomea document!", e);
 		}
 	}
 
+	void validateZipFileName(String xdomeaZipFileName, String processId, String messageTypeCode) throws ClientException {
+		var expectedXdomeaZipFileName = "%s_%s.zip".formatted(processId, messageTypeCode);
+		if (!expectedXdomeaZipFileName.equals(xdomeaZipFileName)) {
+			throw new ClientException(
+					"Expect xdomea zip file name to equal '%s'! (actual: '%s')".formatted(expectedXdomeaZipFileName, xdomeaZipFileName)
+			);
+		}
+	}
+
 	XdomeaXmlValues readXdomeaXmlValues(XtaFile xdomeaZipFile) throws ClientException {
 		var document = readXdomeaXmlDocument(xdomeaZipFile);
 		return xdomeaValueReader.readValues(document);
diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java
index 9df91a3..df4cff9 100644
--- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java
+++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReader.java
@@ -14,6 +14,7 @@ import lombok.RequiredArgsConstructor;
 @RequiredArgsConstructor
 public class XdomeaValueReader {
 
+	static final String PROCESS_ID_XPATH = getTextXpath("Kopf", "ProzessID");
 	static final String AUTHOR_ID_SUFFIX_XPATH = getTextXpath("Kopf", "Absender", "code");
 	static final String READER_ID_SUFFIX_XPATH = getTextXpath("Kopf", "Empfaenger", "code");
 	static final String MESSAGE_TYPE_ID_SUFFIX_XPATH = getTextXpath("Kopf", "Nachrichtentyp", "code");
@@ -29,6 +30,7 @@ public class XdomeaValueReader {
 
 	public XdomeaXmlValues readValues(Document xdomeaXmlDocument) throws ClientException {
 		return XdomeaXmlValues.builder()
+				.processId(readRequiredValue(xdomeaXmlDocument, PROCESS_ID_XPATH))
 				.messageTypeCode(readRequiredValue(xdomeaXmlDocument, MESSAGE_TYPE_ID_SUFFIX_XPATH))
 				.authorIdSuffix(readRequiredValue(xdomeaXmlDocument, AUTHOR_ID_SUFFIX_XPATH))
 				.readerIdSuffix(readRequiredValue(xdomeaXmlDocument, READER_ID_SUFFIX_XPATH))
diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java
index 1e9b6e0..569488d 100644
--- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java
+++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactory.java
@@ -30,6 +30,7 @@ public class XdomeaValueReaderFactory {
 	public XdomeaValueReader create() {
 		return XdomeaValueReader.builder()
 				.xmlValueReaders(Stream.of(
+						PROCESS_ID_XPATH,
 						MESSAGE_TYPE_ID_SUFFIX_XPATH,
 						AUTHOR_ID_SUFFIX_XPATH,
 						READER_ID_SUFFIX_XPATH
diff --git a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java
index e5820e9..8f7ce94 100644
--- a/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java
+++ b/src/main/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaXmlValues.java
@@ -6,6 +6,7 @@ import lombok.Builder;
 
 @Builder
 public record XdomeaXmlValues(
+		@NotBlank String processId,
 		@NotBlank String messageTypeCode,
 		@NotBlank String authorIdSuffix,
 		@NotBlank String readerIdSuffix
diff --git a/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java b/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java
index 8e72d58..2c62293 100644
--- a/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java
+++ b/src/test/java/de/ozgcloud/xta/client/factory/XdomeaXmlValuesTestFactory.java
@@ -4,7 +4,7 @@ import de.ozgcloud.xta.client.xdomea.reader.XdomeaXmlValues;
 
 public class XdomeaXmlValuesTestFactory {
 
-
+	public static final String PROCESS_ID = "000ProcessId-111";
 	public static final String SHORT_MESSAGE_TYPE_CODE = "messageTypeCode";
 	public static final String AUTHOR_ID_SUFFIX = "authorIdSuffix";
 	public static final String READER_ID_SUFFIX = "readerIdSuffix";
@@ -15,6 +15,7 @@ public class XdomeaXmlValuesTestFactory {
 
 	public static XdomeaXmlValues.XdomeaXmlValuesBuilder createBuilder() {
 		return XdomeaXmlValues.builder()
+				.processId(PROCESS_ID)
 				.messageTypeCode(SHORT_MESSAGE_TYPE_CODE)
 				.authorIdSuffix(AUTHOR_ID_SUFFIX)
 				.readerIdSuffix(READER_ID_SUFFIX);
diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java
index e896b3b..969bbd6 100644
--- a/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java
+++ b/src/test/java/de/ozgcloud/xta/client/xdomea/XdomeaXtaMessageCreatorTest.java
@@ -1,5 +1,8 @@
 package de.ozgcloud.xta.client.xdomea;
 
+import static de.ozgcloud.xta.client.factory.MessageMetaDataTestFactory.*;
+import static de.ozgcloud.xta.client.factory.XdomeaXmlValuesTestFactory.*;
+import static de.ozgcloud.xta.client.factory.XtaFileTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -14,6 +17,8 @@ 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.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
@@ -21,6 +26,9 @@ import org.w3c.dom.Document;
 
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.xta.client.exception.ClientException;
+import de.ozgcloud.xta.client.factory.XdomeaXmlValuesTestFactory;
+import de.ozgcloud.xta.client.factory.XtaFileTestFactory;
+import de.ozgcloud.xta.client.factory.XtaMessageMetaDataTestFactory;
 import de.ozgcloud.xta.client.model.XtaFile;
 import de.ozgcloud.xta.client.model.XtaMessage;
 import de.ozgcloud.xta.client.model.XtaMessageMetaData;
@@ -98,13 +106,10 @@ class XdomeaXtaMessageCreatorTest {
 	@Nested
 	class TestDeriveMetaData {
 
-		@Mock
 		private XtaFile xdomeaZipFile;
 
-		@Mock
 		private XdomeaXmlValues xdomeaXmlValues;
 
-		@Mock
 		private XtaMessageMetaData metaData;
 
 		@Mock
@@ -113,6 +118,9 @@ class XdomeaXtaMessageCreatorTest {
 		@BeforeEach
 		@SneakyThrows
 		void mock() {
+			xdomeaZipFile = XtaFileTestFactory.create();
+			xdomeaXmlValues = XdomeaXmlValuesTestFactory.create();
+			metaData = XtaMessageMetaDataTestFactory.create();
 			doReturn(xdomeaXmlValues).when(creator).readXdomeaXmlValues(xdomeaZipFile);
 		}
 
@@ -120,13 +128,38 @@ class XdomeaXtaMessageCreatorTest {
 		@Test
 		@SneakyThrows
 		void shouldReturn() {
-			doReturn(metaData).when(metadataMapper).mapXtaMessageMetadata(xdomeaXmlValues);
+			mockValidMetadata();
 
 			var result = creator.deriveMetaData(xdomeaZipFile);
 
 			assertThat(result).isEqualTo(metaData);
 		}
 
+		@DisplayName("should verify zip file name")
+		@Test
+		@SneakyThrows
+		void shouldVerifyZipFileName() {
+			mockValidMetadata();
+
+			creator.deriveMetaData(xdomeaZipFile);
+
+			verify(creator).validateZipFileName(
+					XTA_FILE_NAME,
+					PROCESS_ID,
+					MESSAGE_TYPE_CODE
+			);
+		}
+
+		@SneakyThrows
+		private void mockValidMetadata() {
+			doReturn(metaData).when(metadataMapper).mapXtaMessageMetadata(xdomeaXmlValues);
+			doNothing().when(creator).validateZipFileName(
+					any(),
+					any(),
+					any()
+			);
+		}
+
 		@DisplayName("should throw client exception")
 		@Test
 		void shouldThrowClientException() {
@@ -163,7 +196,6 @@ class XdomeaXtaMessageCreatorTest {
 			assertThat(result).isEqualTo(xdomeaXmlValues);
 		}
 
-
 	}
 
 	@DisplayName("replace filename extension with xml")
@@ -220,4 +252,33 @@ class XdomeaXtaMessageCreatorTest {
 		}
 	}
 
+	@DisplayName("validate zip file name")
+	@Nested
+	class TestValidateZipFileName {
+
+		private static final String PROCESS_ID = "processId";
+		private static final String MESSAGE_TYPE_CODE = "messageTypeCode";
+		private static final String VALID_ZIP_FILE_NAME = "processId_messageTypeCode.zip";
+
+		@DisplayName("should not throw exception")
+		@Test
+		void shouldNotThrowException() {
+			assertThatCode(() -> creator.validateZipFileName(VALID_ZIP_FILE_NAME, PROCESS_ID, MESSAGE_TYPE_CODE))
+					.doesNotThrowAnyException();
+		}
+
+		@DisplayName("should throw client exception")
+		@ParameterizedTest
+		@ValueSource(strings = {
+				"$processId_messageTypeCode.zip",
+				"processId_me$ssageTypeCode.zip",
+				"processId_messageTypeCode.zip$",
+		})
+		void shouldThrowClientException() {
+			assertThatThrownBy(() -> creator.validateZipFileName("processId_messageTypeCode.zip", PROCESS_ID, "wrongMessageTypeCode"))
+					.isInstanceOf(ClientException.class);
+		}
+
+	}
+
 }
\ No newline at end of file
diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java
index b9ffaac..630e4bc 100644
--- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java
+++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderFactoryTest.java
@@ -32,6 +32,9 @@ class XdomeaValueReaderFactoryTest {
 	@Nested
 	class TestCreate {
 
+		@Mock
+		XmlValueReader procesIdReader;
+
 		@Mock
 		XmlValueReader messageTypeReader;
 
@@ -45,6 +48,7 @@ class XdomeaValueReaderFactoryTest {
 		@Test
 		@SneakyThrows
 		void shouldReturn() {
+			doReturn(procesIdReader).when(factory).createXmlValueReader(PROCESS_ID_XPATH);
 			doReturn(messageTypeReader).when(factory).createXmlValueReader(MESSAGE_TYPE_ID_SUFFIX_XPATH);
 			doReturn(authorIdReader).when(factory).createXmlValueReader(AUTHOR_ID_SUFFIX_XPATH);
 			doReturn(readerIdReader).when(factory).createXmlValueReader(READER_ID_SUFFIX_XPATH);
@@ -53,6 +57,7 @@ class XdomeaValueReaderFactoryTest {
 
 			assertThat(reader).usingRecursiveComparison().isEqualTo(XdomeaValueReader.builder()
 					.xmlValueReaders(Map.of(
+							PROCESS_ID_XPATH, procesIdReader,
 							MESSAGE_TYPE_ID_SUFFIX_XPATH, messageTypeReader,
 							AUTHOR_ID_SUFFIX_XPATH, authorIdReader,
 							READER_ID_SUFFIX_XPATH, readerIdReader
diff --git a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java
index ec4357b..99abcbe 100644
--- a/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java
+++ b/src/test/java/de/ozgcloud/xta/client/xdomea/reader/XdomeaValueReaderTest.java
@@ -33,6 +33,7 @@ class XdomeaValueReaderTest {
 	@Nested
 	class TestReadValues {
 
+		private static final String PROCESS_ID = "process id";
 		private static final String MESSAGE_TYPE_CODE = "message type code";
 		private static final String AUTHOR_ID_SUFFIX = "author id suffix";
 		private static final String READER_ID_SUFFIX = "reader id suffix";
@@ -43,11 +44,20 @@ class XdomeaValueReaderTest {
 		@BeforeEach
 		@SneakyThrows
 		void mock() {
+			doReturn(PROCESS_ID).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.PROCESS_ID_XPATH);
 			doReturn(MESSAGE_TYPE_CODE).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.MESSAGE_TYPE_ID_SUFFIX_XPATH);
 			doReturn(AUTHOR_ID_SUFFIX).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.AUTHOR_ID_SUFFIX_XPATH);
 			doReturn(READER_ID_SUFFIX).when(xdomeaValueReader).readRequiredValue(xdomeaXmlDocument, XdomeaValueReader.READER_ID_SUFFIX_XPATH);
 		}
 
+		@DisplayName("should return process id")
+		@Test
+		void shouldReturnProcessId() {
+			var result = readValues();
+
+			assertThat(result.processId()).isEqualTo(PROCESS_ID);
+		}
+
 		@DisplayName("should return message type code")
 		@Test
 		void shouldReturnMessageTypeCode() {
-- 
GitLab