diff --git a/common/pom.xml b/common/pom.xml index 7bcf1e69a7d60e3ba3f330eb38d46ddb401ff291..8c856ccd354a3ad583f589207700677fc4358541 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -31,7 +31,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> <artifactId>common</artifactId> diff --git a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java index 776ee42fb8666c317e1f59d0eeb7119a29500af8..26ff0c888125264f81d9d31ea6c8ba5ae8381384 100644 --- a/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/formdata/FormData.java @@ -48,7 +48,8 @@ public class FormData { @Builder.Default private FormHeader header = FormHeader.builder().build(); - private ZustaendigeStelle zustaendigeStelle; + @Singular + private List<ZustaendigeStelle> zustaendigeStelles; @ToString.Exclude private Antragsteller antragsteller; @ToString.Exclude diff --git a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java index 2286d30fcc4ef689fbe10756ec1207a36a623283..52dcddeaf62afa188e0716294bf84d615eb5c945 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/formdata/FormDataTestFactory.java @@ -51,6 +51,8 @@ public class FormDataTestFactory { public static final String ATTACHMENT_GROUP_2 = "FileGroup2"; + public static final String VORGANG_ID = "vorgangId"; + public static FormData create() { return createBuilder().build(); } diff --git a/enterprise-adapter/pom.xml b/enterprise-adapter/pom.xml index 2b493a100ac22855b3428759f89b1748c29dadce..c08136cc31e0159f9329078fbf87198970dd9e6d 100644 --- a/enterprise-adapter/pom.xml +++ b/enterprise-adapter/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>enterprise-adapter</artifactId> <name>EM - Enterprise Interface Adapter</name> diff --git a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java index 86d4309910b98191d19bfc9a33b8b97fed0f33c9..edde8e256ad108a7458f4325b7444c4a585f776d 100644 --- a/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java +++ b/enterprise-adapter/src/test/java/de/ozgcloud/eingang/enterprise/entry/EnterpriseEntryITCase.java @@ -64,6 +64,7 @@ class EnterpriseEntryITCase { assertThat(formData).isNotNull(); } + @Test void shouldHaveNoOfRepresentations() { var formData = doPostRequest(); diff --git a/fim-adapter/pom.xml b/fim-adapter/pom.xml index e7dde98a9f4d4cb33a1b755810a51be5287675d5..ea5d7e81c9b3605dfa58ed04af46467360b80100 100644 --- a/fim-adapter/pom.xml +++ b/fim-adapter/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>fim-adapter</artifactId> <name>Eingangs Adapter - FIM</name> diff --git a/formcycle-adapter/formcycle-adapter-impl/pom.xml b/formcycle-adapter/formcycle-adapter-impl/pom.xml index 4f85d9512aabbbe2a758a5893be9762303ff656e..b436b5b2683398a30e5f350fff013d2ca184e4a3 100644 --- a/formcycle-adapter/formcycle-adapter-impl/pom.xml +++ b/formcycle-adapter/formcycle-adapter-impl/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>formcycle-adapter</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java index 3aceb97490468096ade62e9803525e90f0cf8a03..5185c70c92b3dff61db99fa0458be3019195a840 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapper.java @@ -12,11 +12,13 @@ import org.mapstruct.ReportingPolicy; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; +import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; @Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, unmappedTargetPolicy = ReportingPolicy.WARN) interface FormCycleServiceKontoMapper { @Mapping(target = "postfachAddress", ignore = true) + @Mapping(target = "type", constant = ServiceKontoFactory.POSTFACH_TYPE_BAYERN_ID) @Mapping(target = "postfachAddresses", expression = "java(fromGrpcPostfachAddresses(serviceKonto))") ServiceKonto fromGrpc(FormCycleServiceKonto serviceKonto); diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java index feb214cccd2dca6533c39109f6f85619be567304..077a22039a5d9da064404d03e2ec4c24b6584915 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleFormDataMapperTest.java @@ -32,6 +32,7 @@ import org.mockito.InjectMocks; import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import de.ozgcloud.vorgang.common.grpc.GrpcFormDataMapper; class FormCycleFormDataMapperTest { @@ -59,7 +60,9 @@ class FormCycleFormDataMapperTest { void shouldMapZustaendigeStelle() { var mapped = mapper.toFormData(FormCycleFormDataTestFactory.create()); - assertThat(mapped.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo(FormCycleFormHeaderTestFactory.ORGANISATIONSEINHEIT_ID); + assertThat(mapped.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(FormCycleFormHeaderTestFactory.ORGANISATIONSEINHEIT_ID); } } diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java index b328284eb6b3ab4fdf010dd4240d4726ebd13209..562bd419be832ff41a59fd1eb2215ed32961d2bd 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormCycleServiceKontoMapperTest.java @@ -11,6 +11,7 @@ import org.mapstruct.factory.Mappers; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; +import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; class FormCycleServiceKontoMapperTest { @@ -20,6 +21,13 @@ class FormCycleServiceKontoMapperTest { @Nested class TestFromGrpcServiceKonto { + @Test + void shouldMapType() { + var result = mapper.fromGrpc(FormCycleServiceKontoTestFactory.create()); + + assertThat(result.getType()).isEqualTo(ServiceKontoFactory.POSTFACH_TYPE_BAYERN_ID); + } + @DisplayName("trustLevel") @Nested class TestTrustLevel { diff --git a/formcycle-adapter/formcycle-adapter-interface/pom.xml b/formcycle-adapter/formcycle-adapter-interface/pom.xml index d396e859955e6fe0fc0bead6994fb69e852e668f..917fad48d21b8e902c5ae8ba18941556cf984731 100644 --- a/formcycle-adapter/formcycle-adapter-interface/pom.xml +++ b/formcycle-adapter/formcycle-adapter-interface/pom.xml @@ -36,7 +36,7 @@ <groupId>de.ozgcloud.eingang</groupId> <artifactId>formcycle-adapter-interface</artifactId> <name>EM - Formcycle Adapter - Interface</name> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <properties> <vorgang-manager.version>2.0.0</vorgang-manager.version> diff --git a/formcycle-adapter/pom.xml b/formcycle-adapter/pom.xml index 6c060d69a936ed7a12926cd27db9f4788e720fb4..82c4f6bf13ce8340f6d24dd10a32103ed3f5fbfc 100644 --- a/formcycle-adapter/pom.xml +++ b/formcycle-adapter/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>formcycle-adapter</artifactId> diff --git a/formsolutions-adapter/pom.xml b/formsolutions-adapter/pom.xml index 325327a0b108097786653edf290990debcae1c97..1e08df0d029b0fbe57ec6363ee8fa303d5ced7cd 100644 --- a/formsolutions-adapter/pom.xml +++ b/formsolutions-adapter/pom.xml @@ -30,7 +30,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/forwarder/pom.xml b/forwarder/pom.xml index 39605a3df67fbdb757c543b6b89f4484b043dbb7..e0b5a6be46401028b29abd5a62ecf63cc59a8231 100644 --- a/forwarder/pom.xml +++ b/forwarder/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/intelliform-adapter/pom.xml b/intelliform-adapter/pom.xml index a3dfe80bb8058225d880fe2b0fb834ad91f00ab9..88ed01c34144fe964d07e4d1cef50e290271fbfc 100644 --- a/intelliform-adapter/pom.xml +++ b/intelliform-adapter/pom.xml @@ -31,7 +31,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java index 70c45a24ceb90e3f8a7f2e44ac7995823e3c8d22..131accf21541b7a9a13beab5e54e8392db53a07d 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/FormDataEndpointITCase.java @@ -382,15 +382,6 @@ class FormDataEndpointITCase { assertThat(file.getContent().size()).isZero(); } - @Test - void checkForAttachmentFileContentStream() { - sendRequest(); - - var fileStream = formDataCaptor.getValue().getAttachments().get(0).getFiles().get(0).getContentStream(); - - assertThat(fileStream).isNotNull(); - } - @Test void checkAttachmentGroup2Count() { sendRequest(); @@ -437,14 +428,6 @@ class FormDataEndpointITCase { assertThat(file.getContent().size()).isZero(); } - @Test - void checkForRepresentationFileContentStream() { - sendRequest(); - - var fileStream = formDataCaptor.getValue().getRepresentations().get(0).getContentStream(); - - assertThat(fileStream).isNotNull(); - } } @DisplayName("service konto") diff --git a/pom.xml b/pom.xml index fba630070f5be4925b023376aada420e23434577..c61ef2a0c8d485f187d074e2225dcbcad5b255a3 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <packaging>pom</packaging> <name>OZG-Cloud Eingang Manager</name> diff --git a/router/pom.xml b/router/pom.xml index 2ace78948a637913a36b0f781609cfaaca7843fb..92d6bf3f783ccc8dafc687ca6755e2891b980d5d 100644 --- a/router/pom.xml +++ b/router/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java b/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java index 74607f148396fb856dd86a4716f5f67f0d2f4019..c69b8397708151fa0c71aec866f6c2a5aeaceb4f 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/GrpcEingangMapper.java @@ -23,6 +23,7 @@ */ package de.ozgcloud.eingang.router; +import java.util.Optional; import java.util.UUID; import org.mapstruct.CollectionMappingStrategy; @@ -32,8 +33,6 @@ import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.ReportingPolicy; -import com.google.protobuf.ByteString; - import de.ozgcloud.eingang.common.formdata.Antragsteller; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; @@ -52,17 +51,17 @@ import de.ozgcloud.vorgang.vorgang.GrpcZustaendigeStelle; uses = { GrpcFormDataMapper.class, ServiceKontoMapper.class }) public interface GrpcEingangMapper { - @Mapping(source = "antragsteller.data", target = "antragsteller.otherData") - @Mapping(source = "attachments", target = "attachmentsList") - @Mapping(source = "representations", target = "representationsList") - GrpcEingang toEingang(FormData formData); - - default ByteString byteArrayToByteString(byte[] byteArray) { - if (byteArray == null) { - return null; - } + @Mapping(target = "antragsteller.otherData", source = "formData.antragsteller.data") + @Mapping(target = "attachmentsList", source = "formData.attachments") + @Mapping(target = "representationsList", source = "formData.representations") + @Mapping(target = "zustaendigeStelle", expression = "java( toZustaendigeStelle(getZustaendigeStelle(formData, organisationsEinheitenId)) )") + GrpcEingang toEingang(FormData formData, Optional<String> organisationsEinheitenId); - return ByteString.copyFrom(byteArray); + default ZustaendigeStelle getZustaendigeStelle(FormData formData, Optional<String> organisationsEinheitenId) { + return organisationsEinheitenId.flatMap(oeId -> formData.getZustaendigeStelles().stream() + .filter(zustaendigeStelle -> zustaendigeStelle.getOrganisationseinheitenId().equals(oeId)) + .findFirst()) + .orElseGet(() -> ZustaendigeStelle.builder().build()); } @Mapping(source = "files", target = "filesList") diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java index 2a50225927053555819bbd1ac937ed0598088dd4..260cdc3818a4af61e2f93d632a66afb75a31062f 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java @@ -75,7 +75,7 @@ public class VorgangRemoteService { logConnection(organisationsEinheitenId, vorgangServiceStub.get()); try { - return createVorgang(formData, grpcEingangMapper.toEingang(formData), vorgangServiceStub.get(), binaryFileServiceStub.get()); + return createVorgang(formData, grpcEingangMapper.toEingang(formData, organisationsEinheitenId), vorgangServiceStub.get(), binaryFileServiceStub.get()); } finally { finishStubConnections(List.of(vorgangServiceStub, binaryFileServiceStub)); } @@ -159,7 +159,7 @@ public class VorgangRemoteService { } String uploadIncomingFile(IncomingFile incomingFile) { - var fileContentStream = incomingFile.getContentStreamForFinalRead(); + var fileContentStream = incomingFile.getContentStream(); var resultFuture = GrpcFileUploadUtils.createSender(this::buildChunkRequest, fileContentStream, this::buildCallStreamObserver) diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java index de97243af9a356da303522e4555b1509b540dc16..a5ae891ce8936a906686b30057301f893e3da193 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangService.java @@ -23,31 +23,86 @@ */ package de.ozgcloud.eingang.router; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.springframework.stereotype.Service; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import lombok.AllArgsConstructor; +import lombok.extern.log4j.Log4j2; @AllArgsConstructor @Service +@Log4j2 public class VorgangService { private final VorgangRemoteService remoteService; public String createVorgang(FormData formData) { - var preparedFormData = preserveConsistency(formData); + var vorgangId = createVorgangForOrganisationsEinheitIds(getOrganisationsEinheitIds(formData), preserveConsistency(formData)); + cleanupFormDataFiles(formData); + return vorgangId; + } + + void cleanupFormDataFiles(FormData formData) { + getFormDataFiles(formData) + .map(IncomingFile::getFile) + .map(File::toPath) + .forEach(this::deleteIncomingFile); + } + + void deleteIncomingFile(Path path) { + try { + Files.deleteIfExists(path); + } catch (IOException e) { + logErrorOnDeleteFailure(e); + } + } + + void logErrorOnDeleteFailure(Exception e) { + LOG.error("Failed to delete temp-file of incoming file!", e); + } + + Stream<IncomingFile> getFormDataFiles(FormData formData) { + return Stream.concat( + formData.getRepresentations().stream(), + formData.getAttachments().stream() + .map(IncomingFileGroup::getFiles) + .flatMap(List::stream) + ); + } + + String createVorgangForOrganisationsEinheitIds(List<String> organisationsEinheitIds, FormData preparedFormData) { + return organisationsEinheitIds.isEmpty() + ? createVorgangOnMissingZustaendigeStelle(preparedFormData) + : createMultipleVorgangs(preparedFormData, organisationsEinheitIds).getFirst(); + } + + String createVorgangOnMissingZustaendigeStelle(FormData formData) { + return remoteService.createVorgang(formData, Optional.empty()); + } - return remoteService.createVorgang(preparedFormData, getOrganisationsEinheitId(preparedFormData)); + List<String> createMultipleVorgangs(FormData formData, List<String> organisationseinheitIds) { + return organisationseinheitIds.stream() + .map(oeId -> remoteService.createVorgang(formData, Optional.of(oeId))) + .toList(); } - private Optional<String> getOrganisationsEinheitId(FormData formData) { - return Optional.ofNullable(formData.getZustaendigeStelle()).map(ZustaendigeStelle::getOrganisationseinheitenId); + List<String> getOrganisationsEinheitIds(FormData formData) { + return formData.getZustaendigeStelles().stream() + .map(ZustaendigeStelle::getOrganisationseinheitenId) + .toList(); } FormData preserveConsistency(FormData formData) { diff --git a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java index 4150f6cef6d0574b78c6db89d9b61c068cd620e2..f3c15dea9839888f9895a6e440489ee6f09b9b8e 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperITCase.java @@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.*; import java.util.List; import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -58,8 +59,7 @@ class GrpcEingangMapperITCase { @Test void antragstellerShouldBeMapped() { - - var antragSteller = grpcEingangMapper.toEingang(FormDataTestFactory.create()).getAntragsteller(); + var antragSteller = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)).getAntragsteller(); assertThat(antragSteller.getPostfachId()).isEqualTo(AntragstellerTestFactory.POSTFACH_ID); assertThat(antragSteller.getVorname()).isEqualTo(AntragstellerTestFactory.VORNAME); @@ -68,8 +68,7 @@ class GrpcEingangMapperITCase { @Test void dataShouldBeMapped() { - - var antragsteller = grpcEingangMapper.toEingang(FormDataTestFactory.create()).getAntragsteller(); + var antragsteller = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)).getAntragsteller(); assertThat(antragsteller.getOtherData().getFieldList()).hasSize(1); assertThat(antragsteller.getOtherData().getField(0).getName()).isEqualTo(AntragstellerTestFactory.GEBIET_BEZEICHNUNG_KEY); @@ -82,13 +81,21 @@ class GrpcEingangMapperITCase { class TestZustaendigeStelle { @Test void eingangShouldHaveZustaendigeStelle() { - - var zustaendigeStelle = grpcEingangMapper.toEingang(FormDataTestFactory.create()).getZustaendigeStelle(); + var zustaendigeStelle = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)).getZustaendigeStelle(); assertThat(zustaendigeStelle).isNotNull(); assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEqualTo(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); assertThat(zustaendigeStelle.getEmail()).isEqualTo(ZustaendigeStelleTestFactory.EMAIL); } + + @DisplayName("should map empty organisationeinheitId if missing") + @Test + void shouldMapEmptyOrganisationeinheitIdIfMissing() { + var zustaendigeStelle = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.empty()).getZustaendigeStelle(); + + assertThat(zustaendigeStelle).isNotNull(); + assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEmpty(); + } } @Nested @@ -100,7 +107,7 @@ class GrpcEingangMapperITCase { @BeforeEach void init() { - eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create()); + eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.empty()); } @Test @@ -159,7 +166,7 @@ class GrpcEingangMapperITCase { @Test void testRepresentations() { - GrpcEingang eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create()); + GrpcEingang eingang = grpcEingangMapper.toEingang(FormDataTestFactory.create(), Optional.empty()); assertThat(eingang.getRepresentationsCount()).isEqualTo(1); @@ -180,7 +187,7 @@ class GrpcEingangMapperITCase { void valueListShouldGenerateFields() { GrpcEingang eingang = grpcEingangMapper - .toEingang(FormDataTestFactory.createBuilder().formData(Map.of("key", List.of("value1", "value2"))).build()); + .toEingang(FormDataTestFactory.createBuilder().formData(Map.of("key", List.of("value1", "value2"))).build(), Optional.empty()); assertThat(eingang.getFormData().getFieldCount()).isEqualTo(2); } @@ -190,7 +197,7 @@ class GrpcEingangMapperITCase { GrpcEingang eingang = grpcEingangMapper .toEingang(FormDataTestFactory.createBuilder() - .formData(Map.of("key-1", List.of(Map.of("sub_key", "value1"), Map.of("sub_key", "value2")))).build()); + .formData(Map.of("key-1", List.of(Map.of("sub_key", "value1"), Map.of("sub_key", "value2")))).build(), Optional.empty()); assertThat(eingang.getFormData().getFormCount()).isEqualTo(2); assertThat(eingang.getFormData().getForm(0).getFieldCount()).isEqualTo(1); diff --git a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java index 3909125566b6f297d16633590aa4dcc05644611b..df68e82b76e4175a69dde4153eceb108cde21872 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/GrpcEingangMapperTest.java @@ -27,6 +27,8 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Optional; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -212,7 +214,7 @@ class GrpcEingangMapperTest { } private GrpcEingang toEingang() { - return mapper.toEingang(FormDataTestFactory.create()); + return mapper.toEingang(FormDataTestFactory.create(), Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); } } } \ No newline at end of file diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java index 993c973ca2f71c645734db5ab5039151b9a0543f..0fd01eaa035fb5ceeb124fffc5f32e5dc66a0c2b 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java @@ -117,7 +117,7 @@ class VorgangRemoteServiceTest { when(resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(any())).thenReturn(managableBinaryFileServiceStub); when(managableBinaryFileServiceStub.get()).thenReturn(binaryFileServiceStub); - when(eingangMapper.toEingang(any())).thenReturn(eingang); + when(eingangMapper.toEingang(any(), any())).thenReturn(eingang); doNothing().when(remoteService).logConnection(any(), any()); doNothing().when(remoteService).finishStubConnections(any()); @@ -159,7 +159,7 @@ class VorgangRemoteServiceTest { void shouldCallEingangMapper() { createVorgang(); - verify(eingangMapper).toEingang(formData); + verify(eingangMapper).toEingang(formData, organisationsEinheitId); } @Test @@ -431,6 +431,55 @@ class VorgangRemoteServiceTest { } } + @DisplayName("update incoming file") + @Nested + class TestUpdateIncomingFile { + + @Mock + private IncomingFile incomingFile; + + @Mock + private InputStream inputStream; + + @Mock + private GrpcUploadBinaryFileResponse response; + + @Mock + private GrpcUploadBinaryFileRequest request; + + @BeforeEach + void mock() { + doReturn(response).when(vorgangCreator).waitUntilFutureToComplete(any(), any()); + when(incomingFile.getContentStream()).thenReturn(inputStream); + doReturn(request).when(vorgangCreator).buildMetaDataRequest(any()); + } + + @DisplayName("should call get content stream") + @Test + void shouldCallGetContentStream() { + vorgangCreator.uploadIncomingFile(incomingFile); + + verify(incomingFile).getContentStream(); + } + + @DisplayName("should call build request with incoming file") + @Test + void shouldCallBuildRequestWithIncomingFile() { + vorgangCreator.uploadIncomingFile(incomingFile); + + verify(vorgangCreator).buildMetaDataRequest(incomingFile); + } + + @DisplayName("should call wait until future complete") + @Test + void shouldCallWaitUntilFutureComplete() { + vorgangCreator.uploadIncomingFile(incomingFile); + + verify(vorgangCreator).waitUntilFutureToComplete(any(), eq(inputStream)); + } + + } + @Nested class TestWaitUntilFutureToComplete { diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java index 2db3d04b7e3ad7bdb2240c7a1a66d8b39cbb4ca8..74cd1e901ea5260c9ab606fd0f7b00d00fd6fb23 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangServiceTest.java @@ -23,11 +23,18 @@ */ package de.ozgcloud.eingang.router; +import static de.ozgcloud.eingang.common.formdata.FormDataTestFactory.*; +import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -41,6 +48,8 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import de.ozgcloud.eingang.common.formdata.IncomingFile; +import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory; @@ -51,20 +60,22 @@ class VorgangServiceTest { @InjectMocks private VorgangService service; @Mock - private GrpcEingangMapper eingangMapper; - @Mock private VorgangRemoteService remoteService; + private final FormData formData = FormDataTestFactory.create(); + @DisplayName("Create vorgang") @Nested class TestCreateVorgang { - - private final FormData formData = FormDataTestFactory.create(); private final FormData preservedFormData = FormDataTestFactory.create(); + private final List<String> organisationseinheitIds = List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); @BeforeEach void mockEingangMapper() { - doReturn(preservedFormData).when(service).preserveConsistency(formData); + doReturn(preservedFormData).when(service).preserveConsistency(any()); + doReturn(organisationseinheitIds).when(service).getOrganisationsEinheitIds(any()); + doReturn(VORGANG_ID).when(service).createVorgangForOrganisationsEinheitIds(any(), any()); + doNothing().when(service).cleanupFormDataFiles(any()); } @Test @@ -74,15 +85,231 @@ class VorgangServiceTest { verify(service).preserveConsistency(formData); } + @DisplayName("should call create vorgang for organisationseinheitIds") @Test - void shouldCallRemoteService() { + void shouldCallCreateVorgangForOrganisationseinheitIds() { callCreateVorgang(); - verify(remoteService).createVorgang(preservedFormData, Optional.ofNullable(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + verify(service).createVorgangForOrganisationsEinheitIds(organisationseinheitIds, preservedFormData); + } + + @DisplayName("should call get organisationseinheit ids") + @Test + void shouldCallGetOrganisationseinheitIds() { + callCreateVorgang(); + + verify(service).getOrganisationsEinheitIds(formData); + } + + @DisplayName("should return vorgang id") + @Test + void shouldReturn() { + var vorgangId = callCreateVorgang(); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } + + @DisplayName("should call cleanup form data files") + @Test + void shouldCallCleanupFormDataFiles() { + callCreateVorgang(); + + verify(service).cleanupFormDataFiles(formData); + } + + private String callCreateVorgang() { + return service.createVorgang(formData); + } + } + + @DisplayName("cleanup form data files") + @Nested + class TestCleanupFormDataFiles { + private final IncomingFile incomingFile = IncomingFileTestFactory.create(); + + @BeforeEach + void mock() { + doReturn(Stream.of(incomingFile)).when(service).getFormDataFiles(formData); + } + + @DisplayName("should call delete incoming file") + @Test + void shouldCallDeleteIncomingFile() { + service.cleanupFormDataFiles(formData); + + verify(service).deleteIncomingFile(incomingFile.getFile().toPath()); } + } + + @DisplayName("get form data files") + @Nested + class TestGetFormDataFiles { + + private final FormData formData = FormDataTestFactory.create(); + + @DisplayName("should return attachments and representations") + @Test + void shouldReturnAttachmentsAndRepresentations() { + var files = service.getFormDataFiles(formData).toList(); + + assertThat(files).hasSize(3); + } + } + + @DisplayName("delete incoming file") + @Nested + class TestDeleteIncomingFile { + + @Mock + private Path path; + + @DisplayName("should call deleteIfExists") + @Test + void shouldCallDeleteIfExists() { + try (var staticMock = mockStatic(Files.class)) { + service.deleteIncomingFile(path); + + staticMock.verify(() -> Files.deleteIfExists(path)); + } + } + + @DisplayName("should return") + @Test + void shouldReturn() { + try (var staticMock = mockStatic(Files.class)) { + staticMock.when(() -> Files.deleteIfExists(path)).thenReturn(true); + + service.deleteIncomingFile(path); + } + } + + @DisplayName("should log on error") + @Test + void shouldLogOnError() { + var exception = new IOException(); + try (var staticMock = mockStatic(Files.class)) { + staticMock.when(() -> Files.deleteIfExists(path)).thenThrow(exception); + + service.deleteIncomingFile(path); + + verify(service).logErrorOnDeleteFailure(exception); + } + } + + } + + @DisplayName("create vorgang for organisationsEinheitIds") + @Nested + class TestCreateVorgangForOrganisationsEinheitIds { + private final FormData preservedFormData = FormDataTestFactory.create(); + private final List<String> organisationseinheitIds = List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); + + @DisplayName("should call create multiple vorgangs") + @Test + void shouldCallCreateMultipleVorgangs() { + service.createVorgangForOrganisationsEinheitIds(organisationseinheitIds, preservedFormData); + + verify(service).createMultipleVorgangs(preservedFormData, organisationseinheitIds); + } + + @DisplayName("should return first vorgang id with multiple organisationseinheits") + @Test + void shouldReturnFirstVorgangIdWithMultipleOrganisationseinheits() { + doReturn(List.of(VORGANG_ID)).when(service).createMultipleVorgangs(any(), any()); + + var vorgangId = service.createVorgangForOrganisationsEinheitIds(organisationseinheitIds, preservedFormData); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } + + @DisplayName("should call create vorgang on missing zustaendige stelle if organisationseinheit is missing") + @Test + void shouldCallCreateVorgangOnMissingZustaendigeStelleIfOrganisationseinheitIsMissing() { + service.createVorgangForOrganisationsEinheitIds(emptyList(), preservedFormData); + + verify(service).createVorgangOnMissingZustaendigeStelle(eq(preservedFormData)); + } + + @DisplayName("should return single vorgang id if organisationseinheit is missing") + @Test + void shouldReturnSingleVorgangIdIfOrganisationseinheitIsMissing() { + doReturn(VORGANG_ID).when(service).createVorgangOnMissingZustaendigeStelle(any()); + + var firstVorgangId = service.createVorgangForOrganisationsEinheitIds(emptyList(), preservedFormData); + + assertThat(firstVorgangId).isEqualTo(VORGANG_ID); + } + + } + + @DisplayName("create vorgang on missing zustaendige stelle") + @Nested + class TestVorgangOnMissingZustaendigeStelle { + @Mock + private FormData formData; + + @BeforeEach + void mock() { + when(remoteService.createVorgang(any(), any())).thenReturn(VORGANG_ID); + } + + @DisplayName("should call create vorgang") + @Test + void shouldCallCreateVorgang() { + service.createVorgangOnMissingZustaendigeStelle(formData); + + verify(remoteService).createVorgang(formData, Optional.empty()); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var vorgangId = service.createVorgangOnMissingZustaendigeStelle(formData); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } + } + + @DisplayName("create multiple vorgangs") + @Nested + class TestCreateMultipleVorgangs { + + @Mock + private FormData formData; + + @BeforeEach + void mock() { + when(remoteService.createVorgang(any(), any())).thenReturn(VORGANG_ID); + } + + @DisplayName("should call create vorgang twice") + @Test + void shouldCallCreateVorgangTwice() { + service.createMultipleVorgangs(formData, List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + + verify(remoteService).createVorgang(formData, Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var vorgangIds = service.createMultipleVorgangs(formData, List.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID)); + + assertThat(vorgangIds).containsExactly(VORGANG_ID); + } + } + + @DisplayName("get organisationseinheit ids") + @Nested + class TestGetOrganisationseinheitIds { + private final FormData preservedFormData = FormDataTestFactory.create(); + + @DisplayName("should return") + @Test + void shouldReturn() { + var organisationseinheitIds = service.getOrganisationsEinheitIds(preservedFormData); - private void callCreateVorgang() { - service.createVorgang(formData); + assertThat(organisationseinheitIds).containsExactly(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); } } @@ -102,7 +329,7 @@ class VorgangServiceTest { assertThat(consistentFormData.getHeader().getServiceKonto()).isNull(); } - @DisplayName("should keep serviceKonto if postfachAddress eixsts") + @DisplayName("should keep serviceKonto if postfachAddress exists") @Test void shouldKeepServiceKonto() { var consistentFormData = service.preserveConsistency(FormDataTestFactory.create()); diff --git a/semantik-adapter/pom.xml b/semantik-adapter/pom.xml index 18c5fe1bb8ace2afd5e890daf9196ed782046a29..1bc88f3a6f599fa7cee5c72324e261b5c6fa2c9a 100644 --- a/semantik-adapter/pom.xml +++ b/semantik-adapter/pom.xml @@ -30,7 +30,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>semantik-adapter</artifactId> diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java index 9168807d8b4e2a6c52ae95c8bb509ffd04ecd1d8..65c69a87ebc51b3313b8b4ec84d24f7d10170cf0 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/SemantikAdapter.java @@ -34,7 +34,6 @@ import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.formbased.FormBasedSemantikAdapter; import lombok.extern.log4j.Log4j2; - @Log4j2 @Service public class SemantikAdapter { diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java index 1e057c6e81f5c937a429d8050c2c8996742026c9..4fff0ea90b799476bac4f0b3b3c39e4e8378935f 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapper.java @@ -72,7 +72,9 @@ class AfmZustaendigeStelleMapper implements AfmEngineBasedMapper { .organisationseinheitenId(organisationseinheitenID) .build(); - return formData.toBuilder().formData(addMetaDataFlag(formData)).zustaendigeStelle(zustaendigeStelle).build(); + return formData.toBuilder() + .formData(addMetaDataFlag(formData)) + .zustaendigeStelle(zustaendigeStelle).build(); } String getOrganisationseinheitenId(FormData formData) { diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java index 4b417bd36dc8421632a5e26447d1b7b669f249dd..a99ae318b214154314e9cf5752dcf13ce03d89fe 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapper.java @@ -45,7 +45,8 @@ public class ZustaendigeStelleMetadataMapper { return formData.getRepresentations().stream().filter(IS_BEHOERDE_METADATA).findAny() .map(this::readZustaendigeStelleMetadata) .map(this::mapZustaendigeStelle) - .map(zustaendigeStelle -> formData.toBuilder().zustaendigeStelle(zustaendigeStelle).build()) + .map(zustaendigeStelle -> formData.toBuilder() + .zustaendigeStelle(zustaendigeStelle).build()) .orElse(formData); } diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java index a89ba548f5247f858cea72a3443f89d5cd014cda..82d0967071bcfcabad3b9a7803d0e23c77e69a7a 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java @@ -2,6 +2,7 @@ package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -100,22 +101,32 @@ public class DFoerdermittelEngineBasedSemantikAdapter implements EngineBasedSema FormData addOrganisationsEinheitId(FormData formData) { return Optional.ofNullable((String) getFachnachricht(formData).get(KEY_ORGANISATIONS_EINHEIT_ID)) - .map(orgaId -> addOrganisationsEinheitId(orgaId, formData.getZustaendigeStelle())) - .map(zustStelle -> formData.toBuilder().zustaendigeStelle(zustStelle).build()) + .map(orgaId -> addOrganisationsEinheitId(orgaId, formData.getZustaendigeStelles())) + .map(zustStelle -> formData.toBuilder() + .zustaendigeStelle(zustStelle) + .build()) .orElse(formData); } - private ZustaendigeStelle addOrganisationsEinheitId(String orgaId, ZustaendigeStelle zustaendigeStelle) { + private ZustaendigeStelle addOrganisationsEinheitId(String orgaId, Collection<ZustaendigeStelle> zustaendigeStelles) { ZustaendigeStelle.ZustaendigeStelleBuilder zustaendigeStelleBuilder; - if (Objects.isNull(zustaendigeStelle)) { + if (Objects.isNull(zustaendigeStelles) || zustaendigeStelles.isEmpty()) { zustaendigeStelleBuilder = ZustaendigeStelle.builder(); } else { + var zustaendigeStellesIterator = zustaendigeStelles.iterator(); + var zustaendigeStelle = zustaendigeStellesIterator.next(); + logErrorForExistingZustaendigeStelle(); zustaendigeStelleBuilder = zustaendigeStelle.toBuilder(); } return zustaendigeStelleBuilder.organisationseinheitenId(orgaId).build(); } + void logErrorForExistingZustaendigeStelle() { + LOG.error( + "Expect no existing ZustaendigeStelle for DFoerdermittel! Continuing with two ZustaendigeStelles, the original(s) and a copy of the first with overridden OrganisationsEinheitId."); + } + FormData addFormName(FormData formData) { return mapWithModifiedHeader(formData, headerBuilder -> headerBuilder.formName( getNonEmptyFachnachrichtValueByKey(formData, KEY_FORM_NAME) diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java index 29e2c0834d9a05e11519f371cdd2686faa549ed4..d7fa85a1d87e3ac6776068e6a5a062a8b96de3d3 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapper.java @@ -18,7 +18,6 @@ import org.springframework.boot.context.properties.bind.Binder; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; -import de.ozgcloud.eingang.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; @@ -67,78 +66,52 @@ public class MantelantragZustaendigeStelleMapper implements FormBasedMapper { @Override public FormData parseFormData(FormData formData) { - try { - return adaptFormDataWithPossibleException(formData); - } catch (TechnicalException exception) { - logWarningForFailure(exception); - return formData; - } + return formData.toBuilder() + .clearZustaendigeStelles() + .zustaendigeStelles(getZustaendigeStelles(formData)) + .build(); } - void logWarningForFailure(Exception exception) { - LOG.warn("Failed mapping Zustaendigestelle of Mantelantrag: %s".formatted(exception.getMessage())); + List<ZustaendigeStelle> getZustaendigeStelles(FormData formData) { + var fieldMap = formData.getFormData(); + var matchingSlots = getMatchingSlots(fieldMap); + if (matchingSlots.isEmpty()) { + logErrorForNoMatchingIdentifiers(); + } + return matchingSlots.stream() + .map(slotIndex -> getZustaendigeStelle(fieldMap, slotIndex)) + .toList(); } - FormData adaptFormDataWithPossibleException(FormData formData) { - var fieldMap = formData.getFormData(); - var slotIndex = findSlotIndex(fieldMap); - return adaptFormDataWithValueGetter(formData, field -> getFieldByKeyOrEmpty( + ZustaendigeStelle getZustaendigeStelle(Map<String, Object> fieldMap, int slotIndex) { + UnaryOperator<String> getValueOrEmpty = field -> getFieldByKeyOrEmpty( fieldMap, getNameForSlotIndex(field, slotIndex) - )); - } - - private FormData adaptFormDataWithValueGetter(FormData formData, UnaryOperator<String> getValueOrEmpty) { - return formData.toBuilder() - .zustaendigeStelle(ZustaendigeStelle.builder() - .organisationseinheitenId(getOrganisationseinheitId(getValueOrEmpty)) - .bezeichnung(getValueOrEmpty.apply(BEZEICHNUNG_FIELD)) - .email(getValueOrEmpty.apply(EMAIL_FIELD)) - .hausanschriftStrasse(getValueOrEmpty.apply(HAUSANSCHRIFT_STRASSE_FIELD)) - .hausanschriftPlz(getValueOrEmpty.apply(HAUSANSCHRIFT_PLZ_FIELD)) - .hausanschriftOrt(getValueOrEmpty.apply(HAUSANSCHRIFT_ORT_FIELD)) - .telefon(getValueOrEmpty.apply(TELEFON_FIELD)) - .build()) - .build(); - } - - private String getOrganisationseinheitId(UnaryOperator<String> getValueOrEmpty) { + ); var organisationseinheitId = getValueOrEmpty.apply(ORGANISATIONSEINHEIT_ID_FIELD); - if (organisationseinheitId.isBlank()) { - throw new TechnicalException("OrganistaionseinheitId not found!"); - } - - return organisationseinheitId; - } - - int findSlotIndex(Map<String, Object> fieldMap) { - var matchingSlots = getMatchingSlots(fieldMap); - verifyOneMatchingIdentifier(matchingSlots); - return matchingSlots.getFirst(); - } - - private void verifyOneMatchingIdentifier(List<Integer> matchingSlots) { - if (matchingSlots.size() != 1) { - var message = getMultipleSlotsMessage(matchingSlots); - if (matchingSlots.isEmpty()) { - throw new TechnicalException(message); - } else { - logWarningForUnexpected(message); - } + logWarningForEmptyOrganisationseinheitId(slotIndex); } + return ZustaendigeStelle.builder() + .organisationseinheitenId(organisationseinheitId) + .bezeichnung(getValueOrEmpty.apply(BEZEICHNUNG_FIELD)) + .email(getValueOrEmpty.apply(EMAIL_FIELD)) + .hausanschriftStrasse(getValueOrEmpty.apply(HAUSANSCHRIFT_STRASSE_FIELD)) + .hausanschriftPlz(getValueOrEmpty.apply(HAUSANSCHRIFT_PLZ_FIELD)) + .hausanschriftOrt(getValueOrEmpty.apply(HAUSANSCHRIFT_ORT_FIELD)) + .telefon(getValueOrEmpty.apply(TELEFON_FIELD)) + .build(); } - void logWarningForUnexpected(String message) { - LOG.warn("Unexpected Zustaendigestelle in Mantelantrag: %s".formatted(message)); + void logWarningForEmptyOrganisationseinheitId(int slotIndex) { + LOG.warn("[Mantelantrag] OrganisationseinheitId for slot {} is empty!", slotIndex); } - String getMultipleSlotsMessage(List<Integer> matchingSlots) { - return "Found %d matching nachrichtenbroker addresses! Expected one of '%s'.".formatted(matchingSlots.size(), - Strings.join(xtaIdentifiers, ',')); + void logErrorForNoMatchingIdentifiers() { + LOG.error("[Mantelantrag] No matching Zustaendigestelle found! For identifiers: '{}'.", Strings.join(xtaIdentifiers, ',')); } - private List<Integer> getMatchingSlots(Map<String, Object> fieldMap) { + List<Integer> getMatchingSlots(Map<String, Object> fieldMap) { return IntStream.range(0, 3) .filter(slotIndex -> xtaIdentifiers.contains(getXtaIdentifierOfSlot(fieldMap, slotIndex))) .boxed() diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java index 754667f0298c9d867846cafee6f28d6b82677fd2..ea63f2379a7391af25178495e00d3af611cb04e4 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/SemantikAdapterTest.java @@ -23,6 +23,7 @@ */ package de.ozgcloud.eingang.semantik; +import static de.ozgcloud.eingang.common.formdata.FormDataTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -98,6 +99,7 @@ class SemantikAdapterTest { doReturn(List.of(engineAdapter)).when(adapter).getResponsibleEngineAdapters(formData); when(engineAdapter.parseFormData(any())).thenReturn(engineAdapterResponse); when(formAdapter.parseFormData(any())).thenReturn(formAdapterResponse); + when(vorgangService.createVorgang(any())).thenReturn(VORGANG_ID); } @Test @@ -127,5 +129,13 @@ class SemantikAdapterTest { verify(vorgangService).createVorgang(formAdapterResponse); } + + @DisplayName("should return first vorgang id") + @Test + void shouldReturnFirstVorgangId() { + var vorgangId = adapter.processFormData(formData); + + assertThat(vorgangId).isEqualTo(VORGANG_ID); + } } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java index cfbf8d3481cd4679412ceceb84f886152467c30a..0375100ea49c6ac7f0c68bdff8a41d8d988bd3ad 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/FilesMapperHelperTest.java @@ -171,7 +171,7 @@ class FilesMapperHelperTest { assertThat(cleanedFormData.getId()).isEqualTo(formData.getId()); assertThat(cleanedFormData.getHeader()).isEqualTo(formData.getHeader()); - assertThat(cleanedFormData.getZustaendigeStelle()).isEqualTo(formData.getZustaendigeStelle()); + assertThat(cleanedFormData.getZustaendigeStelles()).isEqualTo(formData.getZustaendigeStelles()); assertThat(cleanedFormData.getAntragsteller()).isEqualTo(formData.getAntragsteller()); assertThat(cleanedFormData.getNumberOfAttachments()).isEqualTo(formData.getNumberOfAttachments()); assertThat(cleanedFormData.getAttachments()).isEqualTo(formData.getAttachments()); diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java index 4f83cb409499a33c332c3b8226012cf210949ae8..e9abbeff9c2dc8b2af9f03c35006fe667cc3acbc 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmZustaendigeStelleMapperTest.java @@ -37,6 +37,7 @@ import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; class AfmZustaendigeStelleMapperTest { @@ -78,22 +79,27 @@ class AfmZustaendigeStelleMapperTest { void shouldMapOrganisationseinheitenId() { var parsedFormData = parseZustaendigeStelleData(formData); - assertThat(parsedFormData.getZustaendigeStelle().getOrganisationseinheitenId()) - .isEqualTo(AfmZustaendigeStelleTestFactory.ORGANISATIONSEINHEITEN_ID); + assertThat(parsedFormData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(AfmZustaendigeStelleTestFactory.ORGANISATIONSEINHEITEN_ID); } @Test void shouldMapBezeichnung() { var parsedFormData = parseZustaendigeStelleData(formData); - assertThat(parsedFormData.getZustaendigeStelle().getBezeichnung()).isEqualTo(BEZEICHNUNG); + assertThat(parsedFormData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getBezeichnung) + .containsExactly(BEZEICHNUNG); } @Test void shouldMapEmail() { var parsedFormData = parseZustaendigeStelleData(formData); - assertThat(parsedFormData.getZustaendigeStelle().getEmail()).isEqualTo(AfmZustaendigeStelleTestFactory.EMAIL); + assertThat(parsedFormData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getEmail) + .containsExactly(AfmZustaendigeStelleTestFactory.EMAIL); } @Test diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java index 5da34d86397802416e222b17f31722392944791d..56058ec127401eeff1744df316e1aa60ef62449e 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/ZustaendigeStelleMetadataMapperTest.java @@ -44,7 +44,7 @@ class ZustaendigeStelleMetadataMapperTest { behoerdeMetadataFile = IncomingFileTestFactory.createBuilder().name(ZustaendigeStelleMetadataMapper.BEHOERDE_METADATA_FILE_NAME) .build(); formData = FormDataTestFactory.createBuilder() - .zustaendigeStelle(null) + .clearZustaendigeStelles() .representation(behoerdeMetadataFile).build(); } @@ -76,17 +76,15 @@ class ZustaendigeStelleMetadataMapperTest { var result = mapper.parseZustaendigeStelleData(formData); - assertThat(result.getZustaendigeStelle()).isEqualTo(zustaendigeStelle); + assertThat(result.getZustaendigeStelles()).containsExactly(zustaendigeStelle); } } @Nested class TestReadBehoerdeMetadata { - private File brokenFile; - } @Nested diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java index 2445fe3b2f3f7119bc53e33031595a02e6b7c20c..512d0a840d9c9018c5eb0b3c81495b470636f8e1 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java @@ -27,6 +27,7 @@ import de.ozgcloud.eingang.common.formdata.PostfachAddressTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory; import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; class DFoerdermittelEngineBasedSemantikAdapterTest { @@ -217,12 +218,44 @@ class DFoerdermittelEngineBasedSemantikAdapterTest { @Nested class TestAddOrganisationsEinheitId { - @Test - void shouldHaveOrganisationsEinheitId() { - var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); - assertThat(formData.getZustaendigeStelle()).isNotNull().extracting(ZustaendigeStelle::getOrganisationseinheitenId) - .isEqualTo(ORGANISATIONS_EINHEIT_ID); + @DisplayName("with no existing zustaendige stelles") + @Nested + class TestWithNoExistingZustaendigeStelles { + @Test + void shouldHaveOrganisationsEinheitId() { + var inputFormData = DFoerdermittelFormDataTestFactory.createBuilder() + .clearZustaendigeStelles() + .build(); + + var formData = adapter.addOrganisationsEinheitId(inputFormData); + + assertThat(formData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(ORGANISATIONS_EINHEIT_ID); + } + } + + @DisplayName("with one existing zustaendige stelle") + @Nested + class TestWithOneExistingZustaendigeStelle { + + @Test + void shouldHaveOrganisationsEinheitId() { + var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); + + assertThat(formData.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID, ORGANISATIONS_EINHEIT_ID); + } + + @DisplayName("should log error for existing zustaendige stelle") + @Test + void shouldLogErrorForExistingZustaendigeStelle() { + adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); + + verify(adapter).logErrorForExistingZustaendigeStelle(); + } } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java index 8b8c9bf4103b13f085a7910361925a11e7b90297..7bd4cc6a52d36405595a47500be02c2919066c6f 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java @@ -8,6 +8,7 @@ import java.util.function.Predicate; import java.util.stream.IntStream; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; import lombok.Builder; @@ -35,7 +36,7 @@ class DFoerdermittelFormDataTestFactory { } static FormData.FormDataBuilder createBuilderWithFachnachricht(Fachnachricht fachnachricht) { - return FormData.builder() + return FormDataTestFactory.createBuilder() .header(FormHeaderTestFactory.create()) .formData(Map.of("Fachnachricht", createFachnachrichtMapWithFachnachricht(fachnachricht))); } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java index 8683b1c5df30197b6f082d8d0e8a32d27e8c3ec8..974eb2a59be5dea1e0097b5f810566965332f3fe 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsEngineBasedAdapterITCase.java @@ -50,6 +50,7 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; import de.ozgcloud.eingang.semantik.SemantikAdapter; import lombok.SneakyThrows; @@ -236,14 +237,16 @@ public class FormSolutionsEngineBasedAdapterITCase { void shouldMap() { var data = engineAdapter.parseFormData(formData); - assertThat(data.getZustaendigeStelle()).isNotNull(); + assertThat(data.getZustaendigeStelles()).isNotNull().isNotEmpty(); } @Test void shouldMapOrganistaionseinheitenId() { var data = engineAdapter.parseFormData(formData); - assertThat(data.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo("test"); + assertThat(data.getZustaendigeStelles()) + .extracting(ZustaendigeStelle::getOrganisationseinheitenId) + .containsExactly("test"); } } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java index 1e019f49a47345092a4c9c2b5e6196871c621417..bd31c4218074b8bc343d3327e10455885df7371a 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsZustaendigeStelleMapperTest.java @@ -37,7 +37,6 @@ import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; -import de.ozgcloud.eingang.semantik.enginebased.formsolutions.FormSolutionsZustaendigeStelleMapper; class FormSolutionsZustaendigeStelleMapperTest { @@ -53,7 +52,6 @@ class FormSolutionsZustaendigeStelleMapperTest { @BeforeEach void setup() { formData = FormDataTestFactory.createBuilder() - .zustaendigeStelle(null) .formData(Map.of( FormDataTestFactory.SIMPLE_VALUE_KEY, FormDataTestFactory.SIMPLE_VALUE, FormSolutionsZustaendigeStelleMapper.ZUSTAENDIGE_STELLE, ORGANISATIONSEINHEIT_ID)) @@ -64,7 +62,7 @@ class FormSolutionsZustaendigeStelleMapperTest { void shouldParseFormData() { var resultFormData = mapper.parseFormData(formData); - assertThat(resultFormData.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo(ORGANISATIONSEINHEIT_ID); + assertThat(resultFormData.getZustaendigeStelles().getFirst().getOrganisationseinheitenId()).isEqualTo(ORGANISATIONSEINHEIT_ID); assertThat(resultFormData.getFormData()).doesNotContainKey(ZUSTAENDIGE_STELLE); } @@ -73,7 +71,7 @@ class FormSolutionsZustaendigeStelleMapperTest { void shouldNotChangeAnother() { var resultFormData = mapper.parseFormData(formData); - assertThat(resultFormData).usingRecursiveComparison().ignoringFields("zustaendigeStelle", "formData").isEqualTo(formData); + assertThat(resultFormData).usingRecursiveComparison().ignoringFields("zustaendigeStelles", "formData").isEqualTo(formData); assertThat(resultFormData.getFormData()) .containsAllEntriesOf(Map.of(FormDataTestFactory.SIMPLE_VALUE_KEY, FormDataTestFactory.SIMPLE_VALUE)); } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java index a4951086c82837ebc3c01ef5f19b8833882b0e3c..e80eeca2598ef00dc45d827401744d80eb10ba4c 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragITCase.java @@ -1,5 +1,6 @@ package de.ozgcloud.eingang.semantik.formbased.mantelantrag; +import static de.ozgcloud.eingang.common.formdata.FormDataTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -7,69 +8,154 @@ import static org.mockito.Mockito.*; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.List; +import java.util.Optional; +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.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; import de.ozgcloud.common.binaryfile.TempFileUtils; import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.eingang.Application; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; -import de.ozgcloud.eingang.router.VorgangService; +import de.ozgcloud.eingang.router.VorgangRemoteService; import de.ozgcloud.eingang.semantik.SemantikAdapter; import de.ozgcloud.eingang.semantik.enginebased.formsolutions.FormSolutionsEngineBasedAdapterITCase; import lombok.SneakyThrows; @ActiveProfiles({ "local", "itcase" }) -@SpringBootTest(classes = Application.class, properties = { "ozgcloud.xta.identifiers=afmsh:ozg-cloud-utopia-test" }) +@SpringBootTest(classes = Application.class) public class MantelantragITCase { private static final String FILE_NAME_XDOMEA = "mantelantrag/4620-EH6C_b3c9168a-6ae9-4361-8b2f-6837bb341021_Geschaeftsgang.Geschaeftsgang.0201.xml"; private static final String FILE_NAME_MANTELANTRAG = "mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml"; @MockBean - VorgangService vorgangService; + VorgangRemoteService vorgangRemoteService; @SpyBean SemantikAdapter semantikAdapter; + @Captor + ArgumentCaptor<FormData> formDataCaptor; + private FormData formData; + + @Captor + ArgumentCaptor<Optional<String>> oeIdCaptor; + + @Autowired + MantelantragZustaendigeStelleMapper mantelantragZustaendigeStelleMapper; + + static List<String> xtaIdentifiers = Collections.emptyList(); + + @BeforeEach + void mock() { + clearInvocations(vorgangRemoteService); + doReturn(VORGANG_ID).when(vorgangRemoteService).createVorgang(any(FormData.class), any()); + formData = prepareTestData(); + mantelantragZustaendigeStelleMapper.init(); + } + + @DynamicPropertySource + static void dynamicProperties(DynamicPropertyRegistry registry) { + registry.add("ozgcloud.xta.identifiers", () -> xtaIdentifiers); + } + + @DisplayName("without matching zustaendige stelle") @Nested - class TestZustaendigeStelle { + class TestWithoutMatchingZustaendigeStelle { - @Captor - ArgumentCaptor<FormData> formDataCaptor; + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:unknown"); + } + + @DisplayName("should create one vorgang") + @Test + void shouldCreateOneVorgang() { + semantikAdapter.processFormData(formData); + + verify(vorgangRemoteService, times(1)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getValue()).isEmpty(); + } + } + + @DisplayName("with one matching zustaendige stelle") + @Nested + class TestWithOneMatchingZustaendigeStelle { + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:ozg-cloud-utopia-test"); + } + @DisplayName("should create one vorgang") @Test - void zustaendigeStelleExists() { - var formData = prepareTestData(); - doReturn("test").when(vorgangService).createVorgang(any(FormData.class)); + void shouldCreateOneVorgang() { semantikAdapter.processFormData(formData); - verify(vorgangService).createVorgang(formDataCaptor.capture()); - FormData capturedFormData = formDataCaptor.getValue(); - assertThat(capturedFormData).isNotNull(); + verify(vorgangRemoteService, times(1)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getValue()).contains("123"); } + } + @DisplayName("with two matching zustaendige stelle") + @Nested + class TestWithTwoMatchingZustaendigeStelle { + + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:ozg-cloud-utopia-test", "gae:ozg-cloud-itcase-test"); + } + + @DisplayName("should create two vorangs with partially matching zustaendigeStelle") @Test - void zustaendigeStelleIsUtopia() { - var formData = prepareTestData(); - doReturn("test").when(vorgangService).createVorgang(any(FormData.class)); + void shouldCreateTwoVorangsWithPartiallyMatchingZustaendigeStelle() { semantikAdapter.processFormData(formData); - verify(vorgangService).createVorgang(formDataCaptor.capture()); - FormData capturedFormData = formDataCaptor.getValue(); + verify(vorgangRemoteService, times(2)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getAllValues()).contains(Optional.of("123"), Optional.of("444")); + } + } - assertThat(capturedFormData.getZustaendigeStelle().getOrganisationseinheitenId()).isEqualTo("123"); + @DisplayName("with three matching zustaendige stelles") + @Nested + class TestWithThreeMatchingZustaendigeStelles { + + @BeforeAll + static void setup() { + xtaIdentifiers = List.of("afmsh:ozg-cloud-utopia-test", "gae:ozg-cloud-itcase-test", "afmsh:ozg-cloud-bad-segeberg-kreis"); + } + + @DisplayName("should create three vorgangs") + @Test + void shouldCreateThreeVorgangs() { + semantikAdapter.processFormData(formData); + + verify(vorgangRemoteService, times(3)).createVorgang(formDataCaptor.capture(), oeIdCaptor.capture()); + assertThat(oeIdCaptor.getAllValues()).contains(Optional.of("123"), Optional.of("321"), Optional.of("444")); } + } + + @DisplayName("should return first vorgangId") + @Test + void shouldReturnFirstVorgangId() { + var result = semantikAdapter.processFormData(formData); + assertThat(result).isEqualTo(VORGANG_ID); } private FormData prepareTestData() { diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java index ffc88cabe17fb7e087abab038e13dfff3b8b14d1..782209dff8ebd6174a29942c0812b90f8b5753ca 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/mantelantrag/MantelantragZustaendigeStelleMapperTest.java @@ -1,6 +1,7 @@ package de.ozgcloud.eingang.semantik.formbased.mantelantrag; import static de.ozgcloud.eingang.semantik.formbased.mantelantrag.MantelantragZustaendigeStelleMapper.*; +import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -18,13 +19,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; -import de.ozgcloud.eingang.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; @@ -107,53 +105,104 @@ class MantelantragZustaendigeStelleMapperTest { } } - @DisplayName("adapt form data") + @DisplayName("parse form data") @Nested - class TestAdaptFormData { + class TestParseFormData { + + private FormData formData; @Mock + private ZustaendigeStelle zustaendigeStelle; + + @BeforeEach + void mock() { + formData = FormDataTestFactory.create(); + } + + @DisplayName("should override zustaendige stelles") + @Test + void shouldOverrideZustaendigeStelles() { + doReturn(List.of(zustaendigeStelle)).when(mapper).getZustaendigeStelles(formData); + + var result = mapper.parseFormData(formData); + + assertThat(result.getZustaendigeStelles()).containsExactly(zustaendigeStelle); + } + + @DisplayName("should keep other formdata fields") + @Test + void shouldKeepOtherFormdataFields() { + doReturn(formData.getZustaendigeStelles()).when(mapper).getZustaendigeStelles(formData); + + var result = mapper.parseFormData(formData); + + assertThat(result).usingRecursiveComparison().isEqualTo(formData); + } + } + + @DisplayName("get zustaendige stelles") + @Nested + class TestGetZustaendigeStelles { + private FormData formData; @Mock - private FormData formData2; + private Map<String, Object> fieldMap; + + @Mock + private ZustaendigeStelle stelle1; + + @Mock + private ZustaendigeStelle stelle2; + + @Mock + private ZustaendigeStelle stelle3; - @DisplayName("should return adapted value") + @BeforeEach + void mock() { + formData = FormDataTestFactory.createBuilder() + .formData(fieldMap) + .build(); + } + + @DisplayName("should return") @Test - void shouldReturnAdaptedValue() { - doReturn(formData2).when(mapper).adaptFormDataWithPossibleException(formData); + void shouldReturn() { + doReturn(emptyList()).when(mapper).getMatchingSlots(fieldMap); - var resultFormData = mapper.parseFormData(formData); + var result = mapper.getZustaendigeStelles(formData); - assertThat(resultFormData).isEqualTo(formData2); + assertThat(result).isEmpty(); } - @DisplayName("should return original value with exception") + @DisplayName("should log error for no matching identifiers") @Test - void shouldReturnOriginalValueWithException() { - doThrow(new TechnicalException("some error")).when(mapper).adaptFormDataWithPossibleException(formData); + void shouldLogErrorForNoMatchingIdentifiers() { + doReturn(emptyList()).when(mapper).getMatchingSlots(fieldMap); - var resultFormData = mapper.parseFormData(formData); + mapper.getZustaendigeStelles(formData); - assertThat(resultFormData).isEqualTo(formData); + verify(mapper).logErrorForNoMatchingIdentifiers(); } - @DisplayName("should log warning with exception") + @DisplayName("should return with three zustaendige stelle") @Test - void shouldLogWarningWithException() { - var exception = new TechnicalException("some error"); - doThrow(exception).when(mapper).adaptFormDataWithPossibleException(formData); + void shouldReturnWithThreeZustaendigeStelle() { + doReturn(List.of(0, 1, 2)).when(mapper).getMatchingSlots(fieldMap); + doReturn(stelle1).when(mapper).getZustaendigeStelle(fieldMap, 0); + doReturn(stelle2).when(mapper).getZustaendigeStelle(fieldMap, 1); + doReturn(stelle3).when(mapper).getZustaendigeStelle(fieldMap, 2); - mapper.parseFormData(formData); + var result = mapper.getZustaendigeStelles(formData); - verify(mapper).logWarningForFailure(exception); + assertThat(result).containsExactly(stelle1, stelle2, stelle3); } } - @DisplayName("adapt form data with possible exception") + @DisplayName("get zustaendige stelle") @Nested - class TestAdaptFormDataWithPossibleException { + class TestGetZustaendigeStelle { - static final String TARGET_OPTIONAL_FIELD_VALUE = "optionalFieldValue"; static final Map<String, Function<ZustaendigeStelle, String>> FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR = Map.of( BEZEICHNUNG_FIELD, ZustaendigeStelle::getBezeichnung, EMAIL_FIELD, ZustaendigeStelle::getEmail, @@ -162,17 +211,8 @@ class MantelantragZustaendigeStelleMapperTest { HAUSANSCHRIFT_ORT_FIELD, ZustaendigeStelle::getHausanschriftOrt, TELEFON_FIELD, ZustaendigeStelle::getTelefon ); - private FormData formData; private Map<String, Object> fieldMap; - private static Stream<Arguments> fieldNameAndSlotIndex() { - return Stream.of(0, 1, 2) - .flatMap(slotIndex -> FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR - .keySet().stream() - .map(fieldName -> Arguments.of(slotIndex, fieldName)) - ); - } - @BeforeEach void mock() { fieldMap = new HashMap<>(Map.of( @@ -180,21 +220,6 @@ class MantelantragZustaendigeStelleMapperTest { getOrganisationseinheitIDFieldName(2), "", getOrganisationseinheitIDFieldName(10), "1111111" )); - formData = FormDataTestFactory.createBuilder() - .formData(fieldMap) - .build(); - } - - @DisplayName("should keep form data except zustaendigestelle") - @Test - void shouldKeepFormDataExceptZustaendigestelle() { - doReturn(10).when(mapper).findSlotIndex(fieldMap); - - var resultFormData = mapper.parseFormData(formData); - - assertThat(resultFormData.getId()).isEqualTo(formData.getId()); - assertThat(resultFormData.getHeader()).isEqualTo(formData.getHeader()); - assertThat(resultFormData.getAntragsteller()).isEqualTo(formData.getAntragsteller()); } @DisplayName("should map organisationseinheitId") @@ -203,7 +228,7 @@ class MantelantragZustaendigeStelleMapperTest { void shouldMapOrganisationseinheitId(int slotIndex) { mockWithOEID(slotIndex, TARGET_OEID); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); assertThat(zustaendigeStelle.getOrganisationseinheitenId()).isEqualTo(TARGET_OEID); } @@ -212,62 +237,60 @@ class MantelantragZustaendigeStelleMapperTest { return mapper.getNameForSlotIndex(ORGANISATIONSEINHEIT_ID_FIELD, slotIndex); } - @DisplayName("should throw if organistaionseinheitId is missing") + @DisplayName("should log warning if organistaionseinheitId is missing") @ParameterizedTest @ValueSource(ints = { 0, 1, 2 }) - void shouldThrowIfOrganistationseinheitIdIsMissing(int slotIndex) { - doReturn(slotIndex).when(mapper).findSlotIndex(fieldMap); + void shouldLogWarningIfOrganistaionseinheitIdIsMissing(int slotIndex) { + getZustaendigeStelle(slotIndex); - assertThatThrownBy(this::getAdaptedZustaendigeStelle) - .isInstanceOf(TechnicalException.class); - } - - @DisplayName("should throw if organistationseinheitId is empty") - @ParameterizedTest - @ValueSource(ints = { 0, 1, 2 }) - void shouldThrowIfOrganistationseinheitIdIsEmpty(int slotIndex) { - mockWithOEID(slotIndex, ""); - - assertThatThrownBy(this::getAdaptedZustaendigeStelle) - .isInstanceOf(TechnicalException.class); + verify(mapper).logWarningForEmptyOrganisationseinheitId(slotIndex); } @DisplayName("should map optional field") @ParameterizedTest - @MethodSource("fieldNameAndSlotIndex") + @MethodSource("generateFieldNameAndSlotIndex") void shouldMapOptionalField(int slotIndex, String fieldName) { mockWithSomeOEID(slotIndex); - fieldMap.put(mapper.getNameForSlotIndex(fieldName, slotIndex), TARGET_OPTIONAL_FIELD_VALUE); + var optionalFieldValue = "value of '%s'".formatted(fieldName); + fieldMap.put(mapper.getNameForSlotIndex(fieldName, slotIndex), optionalFieldValue); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); - assertThat(getExpectedByFieldName(zustaendigeStelle, fieldName)).isEqualTo(TARGET_OPTIONAL_FIELD_VALUE); + assertThat(getExpectedValueByFieldName(zustaendigeStelle, fieldName)).isEqualTo(optionalFieldValue); } @DisplayName("should map missing optional fields to empty") @ParameterizedTest - @MethodSource("fieldNameAndSlotIndex") + @MethodSource("generateFieldNameAndSlotIndex") void shouldMapMissingOptionalFieldsToEmpty(int slotIndex, String fieldName) { mockWithSomeOEID(slotIndex); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); - assertThat(getExpectedByFieldName(zustaendigeStelle, fieldName)).isEmpty(); + assertThat(getExpectedValueByFieldName(zustaendigeStelle, fieldName)).isEmpty(); } @DisplayName("should map empty optional fields to empty") @ParameterizedTest - @MethodSource("fieldNameAndSlotIndex") + @MethodSource("generateFieldNameAndSlotIndex") void shouldMapEmptyOptionalFieldsToEmpty(int slotIndex, String fieldName) { mockWithSomeOEID(slotIndex); fieldMap.put(mapper.getNameForSlotIndex(fieldName, slotIndex), ""); - var zustaendigeStelle = getAdaptedZustaendigeStelle(); + var zustaendigeStelle = getZustaendigeStelle(slotIndex); - assertThat(getExpectedByFieldName(zustaendigeStelle, fieldName)).isEmpty(); + assertThat(getExpectedValueByFieldName(zustaendigeStelle, fieldName)).isEmpty(); } - private String getExpectedByFieldName(ZustaendigeStelle zustaendigeStelle, String fieldName) { + private static Stream<Arguments> generateFieldNameAndSlotIndex() { + return Stream.of(0, 1, 2) + .flatMap(slotIndex -> FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR + .keySet().stream() + .map(fieldName -> Arguments.of(slotIndex, fieldName)) + ); + } + + private String getExpectedValueByFieldName(ZustaendigeStelle zustaendigeStelle, String fieldName) { var valueExtractor = FIELD_NAME_TO_EXPECTED_VALUE_EXTRACTOR.get(fieldName); return valueExtractor.apply(zustaendigeStelle); } @@ -278,25 +301,20 @@ class MantelantragZustaendigeStelleMapperTest { private void mockWithOEID(int slotIndex, String targetOeid) { fieldMap.put(getOrganisationseinheitIDFieldName(slotIndex), targetOeid); - doReturn(slotIndex).when(mapper).findSlotIndex(fieldMap); } - private ZustaendigeStelle getAdaptedZustaendigeStelle() { - var formDataResult = mapper.adaptFormDataWithPossibleException(formData); - return formDataResult.getZustaendigeStelle(); + private ZustaendigeStelle getZustaendigeStelle(int slotIndex) { + return mapper.getZustaendigeStelle(fieldMap, slotIndex); } } - @DisplayName("find slot index") + @DisplayName("get matching slots") @Nested - class TestFindSlotIndex { + class TestGetMatchingSlots { private Map<String, Object> fieldMap; - @Captor - private ArgumentCaptor<String> warningCaptor; - @BeforeEach void mock() { fieldMap = new HashMap<>(Map.of( @@ -305,15 +323,23 @@ class MantelantragZustaendigeStelleMapperTest { )); } - @DisplayName("should return matching slot") + @DisplayName("should return empty") + @Test + void shouldReturnEmpty() { + var resultSlotIndices = mapper.getMatchingSlots(fieldMap); + + assertThat(resultSlotIndices).isEmpty(); + } + + @DisplayName("should return matching slots") @ParameterizedTest @ValueSource(ints = { 0, 1, 2 }) void shouldReturnMatchingSlot(int slotIndex) { fieldMap.put(getZustaendigeStelleName(slotIndex), IDENTIFIER); - var resultSlotIndex = mapper.findSlotIndex(fieldMap); + var resultSlotIndices = mapper.getMatchingSlots(fieldMap); - assertThat(resultSlotIndex).isEqualTo(slotIndex); + assertThat(resultSlotIndices).containsExactly(slotIndex); } @DisplayName("should return matching slot with upper-/lowercase difference in identifiers") @@ -322,33 +348,14 @@ class MantelantragZustaendigeStelleMapperTest { void shouldReturnMatchingSlotWithUppercaseIdentifier(int slotIndex) { fieldMap.put(getZustaendigeStelleName(slotIndex), IDENTIFIER2UPPERCASE); - var resultSlotIndex = mapper.findSlotIndex(fieldMap); + var resultSlotIndex = mapper.getMatchingSlots(fieldMap); - assertThat(resultSlotIndex).isEqualTo(slotIndex); + assertThat(resultSlotIndex).containsExactly(slotIndex); } private String getZustaendigeStelleName(int slotIndex) { return mapper.getNameForSlotIndex(ZUSTELLUNG_NACHRICHTENBROKER_FIELD, slotIndex); } - - @DisplayName("should throw if no slot matches") - @Test - void shouldThrowIfNoSlotMatches() { - assertThatThrownBy(() -> mapper.findSlotIndex(fieldMap)) - .isInstanceOf(TechnicalException.class); - } - - @DisplayName("should log warning if multiple slots match") - @Test - void shouldLogWarningIfMultipleSlotsMatch() { - fieldMap.put(getZustaendigeStelleName(0), IDENTIFIER2); - fieldMap.put(getZustaendigeStelleName(2), IDENTIFIER); - - mapper.findSlotIndex(fieldMap); - - verify(mapper).logWarningForUnexpected(warningCaptor.capture()); - assertThat(warningCaptor.getValue()).isEqualTo(mapper.getMultipleSlotsMessage(List.of(0, 2))); - } } @DisplayName("get name for slot index") diff --git a/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml b/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml index 6c7c4e94203d54e765188787a2ef449b7dfcda02..3872cdb8d4bbff8112620fdc044f0bc70aeb6468 100644 --- a/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml +++ b/semantik-adapter/src/test/resources/mantelantrag/4620-EH6C_7d703670-15b6-42b2-8cd1-88a7e4c494b9_Antrag_Max_Mustermann_SGBXII.xml @@ -83,7 +83,7 @@ <zustellung_nachrichtenbroker2>afmsh:ozg-cloud-bad-segeberg-kreis</zustellung_nachrichtenbroker2> <zustellung_email_ln2/> <zustellung_webservice2/> - <kontaktsystem_oeid3/> + <kontaktsystem_oeid3>444</kontaktsystem_oeid3> <OrganisationseinheitenBEZEICHNUNG3/> <zust_strasse3/> <zust_hausnummer3/> @@ -93,7 +93,7 @@ <zust_telefonnummer3/> <zust_faxnummer3/> <zust_emailadresse3/> - <zustellung_nachrichtenbroker3/> + <zustellung_nachrichtenbroker3>gae:ozg-cloud-itcase-test</zustellung_nachrichtenbroker3>> <zustellung_email_ln3/> <zustellung_webservice3/> <grund>Hilfe</grund> diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml index c68b9d69be88de512c6cca216e756aad79d6f46f..b59bb1cc41fbfbba0098590a4986042bd510300e 100644 --- a/src/main/helm/templates/deployment.yaml +++ b/src/main/helm/templates/deployment.yaml @@ -79,7 +79,7 @@ spec: - name: ozgcloud_adapter_targetVorgangManagerName value: {{ (.Values.routing).targetVorgangManagerName}} - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName}}_address - value: 'vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' + value: 'dns:///vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName}}_negotiationType value: {{ (.Values.routing).negotiationType | default "TLS" }} {{- end }} diff --git a/src/test/helm/deployment_routing_strategy_env_test.yaml b/src/test/helm/deployment_routing_strategy_env_test.yaml index 8ae56386a24a3f0f74e3bdb3395b2aed9f4d2be4..e70cff6f10669ad7574fb80dcbf96f3c11aee715 100644 --- a/src/test/helm/deployment_routing_strategy_env_test.yaml +++ b/src/test/helm/deployment_routing_strategy_env_test.yaml @@ -50,6 +50,12 @@ tests: content: name: grpc_client_vorgang-manager-vorgang-manager_negotiationType value: TLS + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_vorgang-manager-vorgang-manager_address + value: dns:///vorgang-manager.sh-helm-test:9090 + - it: validate routing infos set: routing: diff --git a/src/test/helm/ingress_create_or_not.yaml b/src/test/helm/ingress_create_or_not_test.yaml similarity index 100% rename from src/test/helm/ingress_create_or_not.yaml rename to src/test/helm/ingress_create_or_not_test.yaml diff --git a/src/test/helm/ingress_nginx_tests.yaml b/src/test/helm/ingress_nginx_test.yaml similarity index 100% rename from src/test/helm/ingress_nginx_tests.yaml rename to src/test/helm/ingress_nginx_test.yaml diff --git a/xta-adapter/pom.xml b/xta-adapter/pom.xml index e96fb6c3dd46267839a27a0e6c9b19dea237b91d..e350593e7679b71e644bd6cb19efef3f2d12c7f7 100644 --- a/xta-adapter/pom.xml +++ b/xta-adapter/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.13.0-SNAPSHOT</version> + <version>2.15.0-SNAPSHOT</version> </parent> <artifactId>xta-adapter</artifactId> <name>Eingangs Adapter - XTA</name> diff --git a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml index 3835e3ec440eebbd71cdb1bb5c21bf366add83c6..761959137f507e67d20c246ec86bc7393c52a75d 100644 --- a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml +++ b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml @@ -81,7 +81,7 @@ spec: - name: ozgcloud_adapter_targetVorgangManagerName value: {{ (.Values.routing).targetVorgangManagerName}} - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName }}_address - value: 'vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' + value: 'dns:///vorgang-manager.{{ coalesce (.Values.routing).targetNamespace .Release.Namespace }}:9090' - name: grpc_client_vorgang-manager-{{ (.Values.routing).targetVorgangManagerName }}_negotiationType value: {{ (.Values.routing).negotiationType | default "PLAINTEXT" }} {{- end }} diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java index 8041810ed8fbc3222fd10c06a4e64a6a760e9bf4..891512d2f4b878594ee813dbe3cdf5d9c4bfdb4c 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapper.java @@ -26,10 +26,8 @@ package de.ozgcloud.eingang.xta; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.function.Predicate; import java.util.stream.Stream; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import org.springframework.stereotype.Component; import de.ozgcloud.eingang.common.formdata.IncomingFile; @@ -44,14 +42,11 @@ class XtaIncomingFilesMapper { private final ZipFileExtractor zipFileExtractor; - public static final String ZIP_CONTENT_TYPE = "application/zip"; - static final Predicate<IncomingFile> IS_ZIP_FILE = contentType -> ZIP_CONTENT_TYPE.equals(contentType.getContentType()); - public List<IncomingFile> toIncomingFiles(Collection<XtaFile> messageFiles) { if (Objects.nonNull(messageFiles)) { return messageFiles.stream() .map(this::toIncomingFile) - .flatMap(this::extractZip) + .flatMap(this::tryToExtractZip) .toList(); } return List.of(); @@ -66,16 +61,11 @@ class XtaIncomingFilesMapper { .build(); } - Stream<IncomingFile> extractZip(IncomingFile incomingFile) { - if (IS_ZIP_FILE.test(incomingFile)) { - try { - List<IncomingFile> extractedZips = zipFileExtractor.extractIncomingFilesSafely(incomingFile); - return extractedZips.stream(); - } catch (RuntimeException e) { - LOG.error("Cannot read source ZIP. Not extracting file", e); - return Stream.of(incomingFile); - } - } else { + Stream<IncomingFile> tryToExtractZip(IncomingFile incomingFile) { + try { + List<IncomingFile> extractedZips = zipFileExtractor.extractIncomingFilesSafely(incomingFile); + return extractedZips.stream(); + } catch (RuntimeException e) { return Stream.of(incomingFile); } } diff --git a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java index c6a31ed094484414d39444c0caeda6a4a83dcbd9..500e78da873a6acfc55c01a880f4ec953a875d4a 100644 --- a/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java +++ b/xta-adapter/src/main/java/de/ozgcloud/eingang/xta/XtaService.java @@ -46,7 +46,10 @@ class XtaService { private XtaCurrentIdentifierService service; public Stream<FormData> getMessages() { - return createXtaMessageStream().filter(this::isSupportedMessageType).map(this::getFormData); + return createXtaMessageStream() + .filter(this::isSupportedMessageType) + .map(this::getFormDataIfNoRuntimeException) + .flatMap(Optional::stream); } Stream<XtaMessageMetaData> createXtaMessageStream() { @@ -68,7 +71,16 @@ class XtaService { return false; } - public FormData getFormData(@NonNull XtaMessageMetaData metaData) { + Optional<FormData> getFormDataIfNoRuntimeException(@NonNull XtaMessageMetaData metaData) { + try { + return Optional.of(getFormData(metaData)); + } catch (RuntimeException exception) { + LOG.error("Failed to process xta message (id: %s)".formatted(metaData.getMessageId()), exception); + return Optional.empty(); + } + } + + FormData getFormData(@NonNull XtaMessageMetaData metaData) { var msg = remoteService.getMessage(metaData.getMessageId()); var incomingFiles = xtaIncomingFilesMapper.toIncomingFiles(msg.getMessageFiles()); var representationsAttachmentsPair = getRepresentationsAttachmentsPair(metaData, incomingFiles); diff --git a/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml index 77547800e84d3f8f60fe508c57df9e5f7d0a0de6..e247e20d6703fa518cf1eb74616e5447f4fd8a2e 100644 --- a/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml +++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_env_test.yaml @@ -107,7 +107,7 @@ tests: path: spec.jobTemplate.spec.template.spec.containers[0].env content: name: grpc_client_vorgang-manager-vorgang-manager_address - value: 'vorgang-manager.helm-test:9090' + value: 'dns:///vorgang-manager.helm-test:9090' - contains: path: spec.jobTemplate.spec.template.spec.containers[0].env content: @@ -152,7 +152,7 @@ tests: path: spec.jobTemplate.spec.template.spec.containers[0].env content: name: grpc_client_vorgang-manager-vorgang-manager_address - value: 'vorgang-manager.helm-test:9090' + value: 'dns:///vorgang-manager.helm-test:9090' - contains: path: spec.jobTemplate.spec.template.spec.containers[0].env content: diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java index 1ae7d692986e14c57e983b2af836c8b637c33c92..8adbed4598d7224e121e0d723c6c29baf0456361 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaIncomingFilesMapperTest.java @@ -27,10 +27,8 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.List; -import java.util.UUID; import java.util.stream.Stream; -import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -49,8 +47,6 @@ class XtaIncomingFilesMapperTest { @Mock private ZipFileExtractor extractor; - private static final String ZIP_CONTENT_TYPE = "application/zip"; - @Nested class TestToIncomingFiles { @@ -59,12 +55,12 @@ class XtaIncomingFilesMapperTest { var xtaFile = XtaFileTestFactory.create(); var incomingFile = IncomingFileTestFactory.create(); when(mapper.toIncomingFile(xtaFile)).thenReturn(incomingFile); - when(mapper.extractZip(incomingFile)).thenAnswer(x -> Stream.of(incomingFile)); + when(mapper.tryToExtractZip(incomingFile)).thenAnswer(x -> Stream.of(incomingFile)); mapper.toIncomingFiles(List.of(xtaFile, xtaFile)); inOrder(mapper).verify(mapper, calls(2)).toIncomingFile(xtaFile); - inOrder(mapper).verify(mapper, calls(2)).extractZip(incomingFile); + inOrder(mapper).verify(mapper, calls(2)).tryToExtractZip(incomingFile); } @Test @@ -107,7 +103,7 @@ class XtaIncomingFilesMapperTest { } @Nested - class TestExtractZip { + class TestTryToExtractZip { @Mock IncomingFile outFile1; @@ -115,40 +111,29 @@ class XtaIncomingFilesMapperTest { @Mock IncomingFile outFile2; + private final IncomingFile zipFile = IncomingFileTestFactory.createBuilder() + .name("attachments.zip") + .build(); @Test void shouldExtractZipFiles() { var expectedExtractedFiles = List.of(outFile1, outFile2); - var zipFile = createTestIncomingFile(); when(extractor.extractIncomingFilesSafely(zipFile)).thenReturn(expectedExtractedFiles); - var extractedFiles = mapper.extractZip(zipFile).toList(); + var extractedFiles = mapper.tryToExtractZip(zipFile).toList(); assertThat(extractedFiles).isEqualTo(expectedExtractedFiles); } - IncomingFile createTestIncomingFile() { - return IncomingFileTestFactory.createBuilder() - .name("attachments.zip") - .contentType(ZIP_CONTENT_TYPE) - .build(); - } - @Test void shouldIgnoreNonZipFiles() { + when(extractor.extractIncomingFilesSafely(zipFile)).thenThrow(new RuntimeException()); var incomingFile = IncomingFileTestFactory.create(); - var extractedFiles = mapper.extractZip(incomingFile).toList(); + var extractedFiles = mapper.tryToExtractZip(incomingFile).toList(); assertThat(extractedFiles).containsExactly(incomingFile); } } - @Test - void testIsZipFilePredicate() { - assertThat(XtaIncomingFilesMapper.IS_ZIP_FILE.test(IncomingFileTestFactory.create())).isFalse(); - assertThat(XtaIncomingFilesMapper.IS_ZIP_FILE.test(IncomingFileTestFactory.createBuilder().contentType(ZIP_CONTENT_TYPE).build())) - .isTrue(); - } - } diff --git a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java index 1c1ad94981bcdf2c3af38f8aa14d78dce45ffe19..effc877a5d5045273819eef3e441eb6893da1f02 100644 --- a/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java +++ b/xta-adapter/src/test/java/de/ozgcloud/eingang/xta/XtaServiceTest.java @@ -52,52 +52,93 @@ class XtaServiceTest { @Mock private XtaCurrentIdentifierService currentIdentifierService; + @Mock + private FormData formData; + + @Mock + private FormData formData2; + @Nested class TestGetMessagesAsFormData { private final XtaMessageMetaData messageMetaData = XtaMessageMetaDataTestFactory.create(); private final XtaMessage message = XtaMessageTestFactory.create(); - @BeforeEach - void setup() { - doReturn(Stream.of(messageMetaData)).when(service).createXtaMessageStream(); - } + @DisplayName("with one message") + @Nested + class TestWithOneMessage { + @BeforeEach + void setup() { + doReturn(Stream.of(messageMetaData)).when(service).createXtaMessageStream(); + } - @Test - void shouldCallCreateStream() { - service.getMessages(); + @Test + void shouldCallCreateStream() { + service.getMessages(); - verify(service).createXtaMessageStream(); - } + verify(service).createXtaMessageStream(); + } - @Test - void shouldCallFilterByMessageType() { - setupMocks(); + @Test + void shouldCallFilterByMessageType() { + setupMocks(); - service.getMessages().toList(); + service.getMessages().toList(); - verify(service).isSupportedMessageType(messageMetaData); - } + verify(service).isSupportedMessageType(messageMetaData); + } - @Test - void shouldCallGetFormData() { - setupMocks(); - doReturn(true).when(service).isSupportedMessageType(messageMetaData); + @Test + void shouldCallGetFormDataIfNoRuntimeException() { + setupMocks(); + doReturn(true).when(service).isSupportedMessageType(messageMetaData); - service.getMessages().toList(); + service.getMessages().toList(); - verify(service).getFormData(messageMetaData); + verify(service).getFormData(messageMetaData); + } + + @Test + void shouldNotCallGetFormDataIfNoRuntimeException() { + doReturn(false).when(service).isSupportedMessageType(messageMetaData); + + service.getMessages().toList(); + + verify(service, never()).getFormDataIfNoRuntimeException(any()); + } } - @Test - void shouldNotCallGetFormData() { - doReturn(false).when(service).isSupportedMessageType(messageMetaData); + @DisplayName("with multiple messages") + @Nested + class TestWithMultipleMessages { + private final XtaMessageMetaData messageMetaData2 = XtaMessageMetaDataTestFactory.createBuilder() + .messageId(XtaMessageId.from("messageId2")) + .build(); + private final XtaMessageMetaData messageMetaData3 = XtaMessageMetaDataTestFactory.createBuilder() + .messageId(XtaMessageId.from("messageId3")) + .build(); + + @BeforeEach + void setup() { + doReturn(Stream.of(messageMetaData, messageMetaData2, messageMetaData3)).when(service).createXtaMessageStream(); + } - service.getMessages().toList(); + @DisplayName("should return stream of messages") + @Test + void shouldReturnStreamOfMessages() { + doReturn(true).when(service).isSupportedMessageType(messageMetaData); + doReturn(false).when(service).isSupportedMessageType(messageMetaData3); + doReturn(true).when(service).isSupportedMessageType(messageMetaData2); + doReturn(Optional.of(formData)).when(service).getFormDataIfNoRuntimeException(messageMetaData); + doReturn(Optional.of(formData2)).when(service).getFormDataIfNoRuntimeException(messageMetaData2); - verify(service, never()).getFormData(any()); + var result = service.getMessages().toList(); + + assertThat(result).containsExactly(formData, formData2); + } } + private void setupMocks() { var testFormData = FormDataTestFactory.create(); when(mapper.toFormData(any(), any(), eq(vorgangNummerSupplier))).thenReturn(testFormData); @@ -132,6 +173,53 @@ class XtaServiceTest { } } + @DisplayName("get form data if no runtime exception") + @Nested + class TestGetFormDataIfNoRuntimeException { + + @Mock + XtaMessageMetaData messageMetaData; + + @Mock + FormData formData; + + @DisplayName("should call get formdata") + @Test + void shouldCallGetFormdata() { + service.getFormDataIfNoRuntimeException(messageMetaData); + + verify(service).getFormData(messageMetaData); + } + + @DisplayName("with exception") + @Nested + class TestWithException { + @DisplayName("should return empty") + @Test + void shouldReturnEmpty() { + doThrow(new RuntimeException("test-error")).when(service).getFormData(any()); + + var result = service.getFormDataIfNoRuntimeException(messageMetaData); + + assertThat(result).isEmpty(); + } + } + + @DisplayName("without exception") + @Nested + class TestWithoutException { + @DisplayName("should return") + @Test + void shouldReturn() { + doReturn(formData).when(service).getFormData(any()); + + var result = service.getFormDataIfNoRuntimeException(messageMetaData); + + assertThat(result).contains(formData); + } + } + } + @Nested class TestGetFormData {