diff --git a/Jenkinsfile b/Jenkinsfile index 9bb110e4afb5ce6d635a114f7830aa44d82a9536..89a513ae03d2827c8f7802a336d9bb6fce4085fa 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -134,11 +134,9 @@ pipeline { FAILED_STAGE=env.STAGE_NAME HELM_CHART_VERSION = generateHelmChartVersion() - dir('src/main/helm') { - sh "helm lint -f ../../test/helm-linter-values.yaml" - - sh "helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/unit-values.yaml' ." + sh "./run_helm_test.sh" + dir('src/main/helm') { sh "helm package --version=${HELM_CHART_VERSION} ." deployHelmChart("Intelliform-Adapter", HELM_CHART_VERSION) @@ -152,12 +150,12 @@ pipeline { script { FAILED_STAGE=env.STAGE_NAME HELM_CHART_VERSION = generateHelmChartVersion() + + dir('xta-adapter') { + sh "./run_helm_test.sh" + } dir('xta-adapter/src/main/helm') { - sh "helm lint -f test-values.yaml" - - sh "helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/helm/values/unit-values.yaml' ." - sh "helm package --version=${HELM_CHART_VERSION} ." deployHelmChart("xta-adapter", HELM_CHART_VERSION) diff --git a/common/pom.xml b/common/pom.xml index bafba4f676cc13169cfa5aafa255aa03891ade58..cbddecc30e0ea26a777b402a11115b839b9a377c 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> <artifactId>common</artifactId> diff --git a/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java b/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java index 5d1468262c469c9595dabe39e5a7159a3f70a2de..510b7c92779fa39758cf3da4855a7af4dec20fe1 100644 --- a/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java +++ b/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java @@ -1,32 +1,26 @@ package de.ozgcloud.eingang.common.vorgang; -import java.time.Instant; import java.time.LocalDate; +import org.apache.commons.lang3.RandomStringUtils; import org.springframework.stereotype.Component; +import lombok.RequiredArgsConstructor; + @Component +@RequiredArgsConstructor public class VorgangNummerSupplier { - static final String BASE30_ALPHABET = "23456789ABCDEFGHJKMNPQRSTVWXYZ"; + static final String VORGANGNUMMER_TEMPLATE = "%d%X%02d-%s"; + static final char[] BASE30_ALPHABET = { '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', + 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z' }; static final int SUFFIX_LENGTH = 6; public String get() { - var resultBuilder = initWithPrefix(); - long currentTimeSeconds = Instant.now().toEpochMilli(); - for (int i = 0; i < SUFFIX_LENGTH; i++) { - resultBuilder.append(BASE30_ALPHABET.charAt((int) (currentTimeSeconds % 30))); - currentTimeSeconds /= 30; - } - return resultBuilder.toString(); - } - - StringBuilder initWithPrefix() { var today = LocalDate.now(); var lastYearNumber = today.getYear() % 10; - var monthValue = "%02d".formatted(today.getMonthValue()); - var dayValue = "%02d".formatted(today.getDayOfMonth()); - return new StringBuilder().append(lastYearNumber).append(monthValue).append(dayValue).append("-"); + return VORGANGNUMMER_TEMPLATE.formatted(lastYearNumber, today.getMonthValue(), today.getDayOfMonth(), + RandomStringUtils.random(SUFFIX_LENGTH, BASE30_ALPHABET)); } } diff --git a/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java b/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java index d474cd190edfb39454d96c98a67d2d1a0886690d..2fc9a524f5e23d2bebd9721eb5612d96ad879782 100644 --- a/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java +++ b/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java @@ -4,12 +4,15 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.time.LocalDate; +import java.util.Random; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Spy; +import org.springframework.test.util.ReflectionTestUtils; class VorgangNummerSupplierTest { @@ -17,71 +20,67 @@ class VorgangNummerSupplierTest { @InjectMocks private VorgangNummerSupplier vorgangNummerSupplier; - @Nested - @DisplayName("Get Vorgang Nummer") - class TestGetVorgangNummer { - @Test - void shouldCallAddPrefix() { - vorgangNummerSupplier.get(); - - verify(vorgangNummerSupplier).initWithPrefix(); - } + @Test + @DisplayName("should add random suffix of length 6") + void shouldAddSuffix() { + var result = vorgangNummerSupplier.get(); - @Test - @DisplayName("should add random suffix of length 6") - void shouldAddSuffix() { - doReturn(new StringBuilder()).when(vorgangNummerSupplier).initWithPrefix(); + assertThat(result).hasSize(11); + } - var result = vorgangNummerSupplier.get(); + @Test + void shouldCallGetRandomString() { + try (var randomStringUtils = mockStatic(RandomStringUtils.class)) { + vorgangNummerSupplier.get(); - assertThat(result).hasSize(6); + randomStringUtils.verify(() -> RandomStringUtils.random(VorgangNummerSupplier.SUFFIX_LENGTH, VorgangNummerSupplier.BASE30_ALPHABET)); } } - @Nested - class TestAddPrefix { + @Test + void shouldHaveSize() { + var result = vorgangNummerSupplier.get(); - @Test - void shouldHaveSize() { - var resultBuilder = vorgangNummerSupplier.initWithPrefix(); + assertThat(getPrefix(result)).hasSize(5); + } - assertThat(resultBuilder).hasSize(6); - } + private String getPrefix(String string) { + return string.substring(0, string.indexOf('-') + 1); + } - @Test - void shouldAddLastYearNumberFirst() { - var lastYearNumber = "" + LocalDate.now().getYear() % 10; + @Test + void shouldAddLastYearNumberFirst() { + var lastYearNumber = "" + LocalDate.now().getYear() % 10; - var resultBuilder = vorgangNummerSupplier.initWithPrefix(); + var result = vorgangNummerSupplier.get(); - assertThat(resultBuilder.substring(0, 1)).isEqualTo(lastYearNumber); - } + assertThat(result.substring(0, 1)).isEqualTo(lastYearNumber); + } - @Test - void shouldAddMonthValueSecond() { - var monthValue = "%02d".formatted(LocalDate.now().getMonthValue()); + @Test + void shouldAddMonthValueSecond() { + var monthHexValue = "%X".formatted(LocalDate.now().getMonthValue()); - var resultBuilder = vorgangNummerSupplier.initWithPrefix(); + var result = vorgangNummerSupplier.get(); - assertThat(resultBuilder.substring(1, 3)).isEqualTo(monthValue); - } + assertThat(result.substring(1, 2)).isEqualTo(monthHexValue); + } - @Test - void shouldAddDayValueThird() { - var dayValue = "%02d".formatted(LocalDate.now().getDayOfMonth()); + @Test + void shouldAddDayValueThird() { + var dayValue = "%02d".formatted(LocalDate.now().getDayOfMonth()); - var resultBuilder = vorgangNummerSupplier.initWithPrefix(); + var result = vorgangNummerSupplier.get(); - assertThat(resultBuilder.substring(3, 5)).isEqualTo(dayValue); - } + assertThat(result.substring(2, 4)).isEqualTo(dayValue); + } - @Test - void shouldAddHyphenAtEnd() { - var resultBuilder = vorgangNummerSupplier.initWithPrefix(); + @Test + void shouldAddHyphenAtEnd() { + var result = vorgangNummerSupplier.get(); - assertThat(resultBuilder.charAt(5)).isEqualTo('-'); - } + assertThat(result.charAt(4)).isEqualTo('-'); } } \ No newline at end of file diff --git a/enterprise-adapter/pom.xml b/enterprise-adapter/pom.xml index e1584e046641abc328a04c90d8853c9d1afee0e7..a58f9ddebd13ba6d5acec413bef00ae297961b1b 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> </parent> <artifactId>enterprise-adapter</artifactId> <name>EM - Enterprise Interface Adapter</name> diff --git a/formcycle-adapter/formcycle-adapter-impl/pom.xml b/formcycle-adapter/formcycle-adapter-impl/pom.xml index 124e8c4b23125aa7b8e53b4c830c390c51a6e202..385edb61741306639da6294e8395f8c4c7874fe1 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java index b79d3a951c53f0853ff0cdde4dbfef9c0966f56c..d860e7833dc3cb2c41fa2255247015d8a6798575 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java @@ -40,7 +40,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import de.ozgcloud.common.binaryfile.TempFileUtils; -import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; @@ -60,11 +60,13 @@ import lombok.extern.log4j.Log4j2; @RequiredArgsConstructor class FormDataController { + public static final String HTTP_TYPE_PROTOBUF = "application/x-protobuf"; + private final FormCycleFormDataMapper mapper; private final SemantikAdapter semantikAdapter; private final VorgangNummerSupplier vorgangNummerSupplier; - @PostMapping(consumes = "multipart/form-data", produces = "application/protobuf") + @PostMapping(consumes = "multipart/form-data", produces = HTTP_TYPE_PROTOBUF) public FormCycleConfirmationResponse receiveFormData(@RequestPart FormCycleFormData formData, @RequestPart(required = false) Optional<Collection<MultipartFile>> representations, @RequestPart(required = false) Optional<Collection<MultipartFile>> attachments) { diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java index 8f0e8a7768ac9384a3c348d35a9a57f468cc8f3d..dddbd8f53cba6ef112fe68bc79e5689ebb89100b 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java @@ -23,12 +23,18 @@ */ package de.ozgcloud.eingang.formcycle; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.TimeZone; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; +import de.ozgcloud.eingang.formcycle.common.errorhandling.FormcycleExceptionHandler; +import de.ozgcloud.eingang.formcycle.common.protobuf.CustomProtobufHttpMessageConverter; import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.enginebased.formcycle.FormCycleEngineBasedAdapter; @@ -44,4 +50,23 @@ public class FormcycleAdapterApplication { EngineBasedSemantikAdapter engineBasedAdapter() { return new FormCycleEngineBasedAdapter(); } + + @Bean + ProtobufHttpMessageConverter protobufMessageConverter() { + return addCustomProtobufMediaType(new CustomProtobufHttpMessageConverter()); + } + + @Deprecated(forRemoval = true, since = "2.1.0") + // FIXME: Remove this method after all customers have updated ozg-cloud plugin to version 1.4.0 or higher + private ProtobufHttpMessageConverter addCustomProtobufMediaType(ProtobufHttpMessageConverter protobufHttpMessageConverter) { + var supportetMediaTypes = new ArrayList<>(protobufHttpMessageConverter.getSupportedMediaTypes()); + supportetMediaTypes.add(new MediaType("application", "protobuf", StandardCharsets.UTF_8)); + protobufHttpMessageConverter.setSupportedMediaTypes(supportetMediaTypes); + return protobufHttpMessageConverter; + } + + @Bean + FormcycleExceptionHandler restResposeEntityExceptionHandler() { + return new FormcycleExceptionHandler(); + } } diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandler.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..d98bdc6aaf6a18ee25015f577945b356205ae3a2 --- /dev/null +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandler.java @@ -0,0 +1,74 @@ +package de.ozgcloud.eingang.formcycle.common.errorhandling; + +import java.util.UUID; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import de.ozgcloud.common.errorhandling.ExceptionUtil; +import de.ozgcloud.common.errorhandling.TechnicalException; +import io.grpc.StatusRuntimeException; +import lombok.extern.log4j.Log4j2; + +@ControllerAdvice +@Log4j2 +public class FormcycleExceptionHandler extends ResponseEntityExceptionHandler { + + static final String TECHNICAL_EXCEPTION_MESSAGE = "Cannot process request."; + static final String CREATE_VORGANG_EXCEPTION_MESSAGE = "Cannot create vorgang."; + static final String UNEXPECTED_EXCEPTION_MESSAGE = "An unexpected error occurred."; + + private static final String EXCEPTION_ID_TEMPLATE = "(ExceptionId:"; + + @ExceptionHandler({ TechnicalException.class }) + public ResponseEntity<InternalExceptionDto> handleTechnicalException(TechnicalException e, WebRequest request) { + LOG.error(TECHNICAL_EXCEPTION_MESSAGE, e); + return buildResponseEntity(TECHNICAL_EXCEPTION_MESSAGE, e.getExceptionId()); + } + + @ExceptionHandler({ StatusRuntimeException.class }) + public ResponseEntity<InternalExceptionDto> handleStatusRuntimeException(StatusRuntimeException e, WebRequest request) { + var logMessage = TECHNICAL_EXCEPTION_MESSAGE; + var exceptionId = getExceptionId(e.getMessage()); + if (!hasExceptionId(e.getMessage())) { + logMessage = ExceptionUtil.formatMessageWithExceptionId(CREATE_VORGANG_EXCEPTION_MESSAGE, exceptionId); + } + LOG.error(logMessage, e); + return buildResponseEntity(CREATE_VORGANG_EXCEPTION_MESSAGE, exceptionId); + } + + boolean hasExceptionId(String message) { + return message.contains(EXCEPTION_ID_TEMPLATE); + } + + String getExceptionId(String message) { + try { + return message.substring(message.indexOf(EXCEPTION_ID_TEMPLATE) + 14, message.indexOf(")")); + } catch (IndexOutOfBoundsException e) { + return createExceptionId(); + } + } + + @ExceptionHandler({ RuntimeException.class }) + public ResponseEntity<InternalExceptionDto> handleUnexpectedException(RuntimeException e, WebRequest request) { + var exceptionId = createExceptionId(); + var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(UNEXPECTED_EXCEPTION_MESSAGE, exceptionId); + LOG.error(messageWithExceptionId, e); + return buildResponseEntity(UNEXPECTED_EXCEPTION_MESSAGE, exceptionId); + } + + String createExceptionId() { + return UUID.randomUUID().toString(); + } + + ResponseEntity<InternalExceptionDto> buildResponseEntity(String message, String exceptionId) { + return ResponseEntity.internalServerError().body(buildInternalExceptionDto(message, exceptionId)); + } + + InternalExceptionDto buildInternalExceptionDto(String message, String exceptionId) { + return InternalExceptionDto.builder().message(message).exceptionId(exceptionId).build(); + } +} diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDto.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDto.java new file mode 100644 index 0000000000000000000000000000000000000000..9e72ccd3baee345ffa744753b3bf01c189caa247 --- /dev/null +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDto.java @@ -0,0 +1,12 @@ +package de.ozgcloud.eingang.formcycle.common.errorhandling; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class InternalExceptionDto { + + private String exceptionId; + private String message; +} diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/CustomProtobufHttpMessageConverter.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/CustomProtobufHttpMessageConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..6a6ab8e0fca7eb2ac7111aef84ec2d2c6039bcc4 --- /dev/null +++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/CustomProtobufHttpMessageConverter.java @@ -0,0 +1,19 @@ +package de.ozgcloud.eingang.formcycle.common.protobuf; + +import java.io.IOException; + +import org.springframework.http.HttpInputMessage; +import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; + +import com.google.protobuf.Message; + +@Deprecated(forRemoval = true, since = "2.1.0") +// FIXME: Remove this class after all customers have updated ozg-cloud plugin to version 1.4.0 or higher +public class CustomProtobufHttpMessageConverter extends ProtobufHttpMessageConverter { + + @Override + protected Message readInternal(Class<? extends Message> clazz, HttpInputMessage inputMessage) throws IOException { + inputMessage.getHeaders().setContentType(ProtobufHttpMessageConverter.PROTOBUF); + return super.readInternal(clazz, inputMessage); + } +} diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverter.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverter.java deleted file mode 100644 index b26262f97fa6f805b875ea187021b24d5f6d636e..0000000000000000000000000000000000000000 --- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverter.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.formcycle.common.protobuf; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Type; - -import org.springframework.http.HttpInputMessage; -import org.springframework.http.HttpOutputMessage; -import org.springframework.http.MediaType; -import org.springframework.http.converter.AbstractGenericHttpMessageConverter; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.http.converter.HttpMessageNotWritableException; -import org.springframework.stereotype.Component; - -import com.google.protobuf.CodedOutputStream; - -import de.ozgcloud.common.errorhandling.TechnicalException; -import lombok.extern.log4j.Log4j2; - -@Component -@Log4j2 -public class ProtobufMessageConverter extends AbstractGenericHttpMessageConverter<Object> { - - public ProtobufMessageConverter() { - super(new MediaType(com.google.common.net.MediaType.PROTOBUF.type(), com.google.common.net.MediaType.PROTOBUF.subtype())); - } - - @Override - protected void writeInternal(Object t, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { - try { - var writeMethod = Class.forName(type.getTypeName()).getMethod("writeTo", CodedOutputStream.class); - CodedOutputStream out = CodedOutputStream.newInstance(outputMessage.getBody()); - writeMethod.invoke(t, out); - out.flush(); - } catch (NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException - | InvocationTargetException e) { - LOG.error("Error writing response", e); - throw new TechnicalException("Error writing response.", e); - } - - } - - @Override - public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { - try { - return readInternal(Class.forName(type.getTypeName()), inputMessage); - } catch (HttpMessageNotReadableException | ClassNotFoundException | IOException e) { - LOG.error("Error getting target class", e); - throw new TechnicalException("Error getting target class", e); - } - } - - @Override - protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { - try { - var parserMethod = clazz.getMethod("parseFrom", InputStream.class); - return parserMethod.invoke(null, inputMessage.getBody()); - } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - LOG.error("Error on reading protobuf data.", e); - throw new TechnicalException("Error on reading protobuf data.", e); - } - } -} diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java index e25ac53a1168a14b152d7ec4bab8bc4694ff11ac..e3e878598707b5d02b85d7ef618ebd3b1f3b8cec 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java @@ -73,7 +73,7 @@ class FormDataControllerITCase { private ResultActions doPostRequest() { return mockMvc.perform( multipart("/formData") - .file(new MockMultipartFile("formData", null, "application/protobuf", buildTestFormData())) + .file(new MockMultipartFile("formData", null, FormDataController.HTTP_TYPE_PROTOBUF, buildTestFormData())) .file(IncomingFileTestFactory.asMultipartFile("representations")) .file(asMultipartFile("attachments", createBuilder().name(IncomingFileGroupTestFactory.VENDOR_ID_XXX + "__" + NAME).build()))); diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java index 1e9430b99f44ee7befc31568c96d3fe940622868..4ff5e49568537a304f76b9f1c568701b1e87240d 100644 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java @@ -42,6 +42,7 @@ import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; +import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @@ -55,7 +56,6 @@ import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; -import de.ozgcloud.eingang.formcycle.common.protobuf.ProtobufMessageConverter; import de.ozgcloud.eingang.semantik.SemantikAdapter; import lombok.SneakyThrows; @@ -77,7 +77,7 @@ class FormDataControllerTest { @BeforeEach void init() { mockMvc = MockMvcBuilders.standaloneSetup(controller) - .setMessageConverters(new ProtobufMessageConverter()) + .setMessageConverters(new ProtobufHttpMessageConverter()) .build(); } @@ -186,7 +186,7 @@ class FormDataControllerTest { void shouldBeFineWithoutRepresentations() { mockMvc.perform( multipart("/formData") - .file(new MockMultipartFile("formData", null, "application/protobuf", buildTestFormData()))) + .file(new MockMultipartFile("formData", null, FormDataController.HTTP_TYPE_PROTOBUF, buildTestFormData()))) .andExpect(status().isOk()); } } @@ -221,7 +221,7 @@ class FormDataControllerTest { private ResultActions doPostRequest() { return mockMvc.perform( multipart("/formData") - .file(new MockMultipartFile("formData", null, "application/protobuf", buildTestFormData())) + .file(new MockMultipartFile("formData", null, FormDataController.HTTP_TYPE_PROTOBUF, buildTestFormData())) .file(IncomingFileTestFactory.asMultipartFile("representations")) .file(asMultipartFile("attachments", createBuilder().name(IncomingFileGroupTestFactory.VENDOR_ID_XXX).build()))); diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandlerTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f5e8ffaf282d688e800ab64cd87d57a478c0fd81 --- /dev/null +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandlerTest.java @@ -0,0 +1,126 @@ +package de.ozgcloud.eingang.formcycle.common.errorhandling; + +import static de.ozgcloud.eingang.formcycle.common.errorhandling.InternalExceptionDtoTestFactory.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +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.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import de.ozgcloud.common.errorhandling.ExceptionUtil; +import de.ozgcloud.common.errorhandling.TechnicalException; +import io.grpc.StatusRuntimeException; + +class FormcycleExceptionHandlerTest { + + @Spy + @InjectMocks + private FormcycleExceptionHandler exceptionHandler; + + @Nested + class TestHandleTechnicalException { + + @Mock + private TechnicalException technicalException; + + @Test + void shouldCallBuildResponseEntity() { + when(technicalException.getExceptionId()).thenReturn(EXCEPTION_ID); + + exceptionHandler.handleTechnicalException(technicalException, null); + + verify(exceptionHandler).buildResponseEntity(FormcycleExceptionHandler.TECHNICAL_EXCEPTION_MESSAGE, EXCEPTION_ID); + } + + } + + @Nested + class TestHandleStatusRuntimeException { + + @Mock + private StatusRuntimeException statusRuntimeException; + + @Test + void shouldCallBuildResponseEntity() { + when(statusRuntimeException.getStackTrace()).thenReturn(new StackTraceElement[0]); + when(statusRuntimeException.getMessage()).thenReturn(ExceptionUtil.formatMessageWithExceptionId(MESSAGE, EXCEPTION_ID)); + + exceptionHandler.handleStatusRuntimeException(statusRuntimeException, null); + + verify(exceptionHandler).buildResponseEntity(FormcycleExceptionHandler.CREATE_VORGANG_EXCEPTION_MESSAGE, EXCEPTION_ID); + } + + @Nested + class TestGetExceptionId { + + @Test + void shouldReturnExceptionIdFromMessage() { + var exceptionId = exceptionHandler.getExceptionId(messageWithExceptionId()); + + assertThat(exceptionId).isEqualTo(EXCEPTION_ID); + } + + @Test + void shouldCreateNewExceptionId() { + var exceptionId = exceptionHandler.getExceptionId(MESSAGE); + + assertThat(exceptionId).isNotEqualTo(EXCEPTION_ID); + } + + } + + } + + @Nested + class TestBuildResponseEntity { + + @Test + void shouldReturnInternaServerError() { + var response = buildResponseEntity(); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + } + + @Test + void shouldCallBuildInternalExceptionDto() { + buildResponseEntity(); + + verify(exceptionHandler).buildInternalExceptionDto(InternalExceptionDtoTestFactory.MESSAGE, EXCEPTION_ID); + } + + private ResponseEntity<InternalExceptionDto> buildResponseEntity() { + return exceptionHandler.buildResponseEntity(InternalExceptionDtoTestFactory.MESSAGE, EXCEPTION_ID); + } + + } + + @Nested + class TestBuildInternalExceptionDto { + + @Test + void shouldSetExceptionId() { + var response = buildInternalExceptionDto(); + + assertThat(response.getExceptionId()).isEqualTo(EXCEPTION_ID); + } + + @Test + void shouldSetMessage() { + var response = buildInternalExceptionDto(); + + assertThat(response.getMessage()).isEqualTo(InternalExceptionDtoTestFactory.MESSAGE); + } + + private InternalExceptionDto buildInternalExceptionDto() { + return exceptionHandler.buildInternalExceptionDto(InternalExceptionDtoTestFactory.MESSAGE, EXCEPTION_ID); + } + + } +} \ No newline at end of file diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDtoTestFactory.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDtoTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..98a8e5f27c53fd8676f1233ae24e3bf7c42306eb --- /dev/null +++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDtoTestFactory.java @@ -0,0 +1,22 @@ +package de.ozgcloud.eingang.formcycle.common.errorhandling; + +import de.ozgcloud.common.errorhandling.ExceptionUtil; +import de.ozgcloud.eingang.formcycle.common.errorhandling.InternalExceptionDto.InternalExceptionDtoBuilder; + +public class InternalExceptionDtoTestFactory { + + public static final String EXCEPTION_ID = "exception-id"; + public static final String MESSAGE = "exception message"; + + public static InternalExceptionDto create() { + return createBuilder().build(); + } + + private static InternalExceptionDtoBuilder createBuilder() { + return InternalExceptionDto.builder().exceptionId(EXCEPTION_ID).message(MESSAGE); + } + + public static String messageWithExceptionId() { + return ExceptionUtil.formatMessageWithExceptionId(MESSAGE, EXCEPTION_ID); + } +} diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverterTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverterTest.java deleted file mode 100644 index aa8b6462bfc72c3d2c872cf9f48883b9621fddee..0000000000000000000000000000000000000000 --- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverterTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.eingang.formcycle.common.protobuf; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.lang.reflect.Type; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Spy; -import org.springframework.http.HttpInputMessage; -import org.springframework.http.HttpOutputMessage; - -import de.ozgcloud.common.errorhandling.TechnicalException; -import de.ozgcloud.eingang.formcycle.common.protobuf.ProtobufMessageConverter; -import lombok.SneakyThrows; - -class ProtobufMessageConverterTest { - - @Spy - @InjectMocks - private ProtobufMessageConverter converter; - - @Nested - class TestRead { - - private HttpInputMessage inputMessage = mock(HttpInputMessage.class); - - @Test - @SneakyThrows - void shouldCallReadInternal() { - doReturn(null).when(converter).readInternal(any(), any()); - - converter.read(String.class, Object.class, inputMessage); - - verify(converter).readInternal(eq(String.class), same(inputMessage)); - } - - @Test - @SneakyThrows - void shouldThrowTechnicalException() { - var mockType = buildMockType(); - - assertThatThrownBy(() -> converter.read(mockType, Object.class, inputMessage)).isInstanceOf(TechnicalException.class); - } - } - - @Nested - class TestReadInternal { - @Test - void shouldThrowTechnicalException() { - assertThatThrownBy(() -> converter.readInternal(Object.class, mock(HttpInputMessage.class))) - .isInstanceOf(TechnicalException.class); - } - } - - @Nested - class TestWriteInternal { - @Test - void shouldThrowTechnicalException() { - var mockType = buildMockType(); - - assertThatThrownBy(() -> converter.writeInternal("test", mockType, mock(HttpOutputMessage.class))) - .isInstanceOf(TechnicalException.class); - } - } - - private Type buildMockType() { - var mockType = mock(Type.class); - when(mockType.getTypeName()).thenReturn("quatsch"); - - return mockType; - } -} diff --git a/formcycle-adapter/formcycle-adapter-interface/pom.xml b/formcycle-adapter/formcycle-adapter-interface/pom.xml index fb109c303b608c75e2c55e32fc90ac7d1154cfa9..28a72c95a2b5c17a1dcf768d0bb51e9e1a8ece6e 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <properties> <vorgang-manager.version>2.0.0</vorgang-manager.version> @@ -55,7 +55,7 @@ <groupId>de.ozgcloud.vorgang</groupId> <artifactId>vorgang-manager-interface</artifactId> <classifier>sources</classifier> - <scope>compile</scope> + <scope>provided</scope> <version>${vorgang-manager.version}</version> </dependency> diff --git a/formcycle-adapter/pom.xml b/formcycle-adapter/pom.xml index 5fa3e03ced9736321e54b7b03bff3529e45a6ad7..5b924798ec67e523e2959b1c66714d51407f2910 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> </parent> <artifactId>formcycle-adapter</artifactId> diff --git a/formsolutions-adapter/pom.xml b/formsolutions-adapter/pom.xml index e0674d8347f1a8e2c653b4a38ac7998fed4be4be..ec9d07b8a3593bb83dbf0f90f6e19e0d87c8b145 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/forwarder/pom.xml b/forwarder/pom.xml index caaed6c22bf36f0376b54b0f9723dfc8d0b41344..e3768f99fd8e246ad283db90e5c80db77080781a 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/intelliform-adapter/pom.xml b/intelliform-adapter/pom.xml index bf183fcf79d177b783ee5b81caaad3a06fc9ae60..20c90b990ce1e73337ac1de6706576d4cf9b6c05 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java new file mode 100644 index 0000000000000000000000000000000000000000..dad25e9f009aa064cc79e5837ccf4687d0dcdc89 --- /dev/null +++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.eingang.intelliform; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +import org.springframework.stereotype.Component; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; + +@Component +public class CustomHeaderReader { + + public static final String HEADER_POSTFACH_ID = "u:saml_legacypostkorbhandle"; + public static final String HEADER_VORNAME = "u:saml_givenname"; + public static final String HEADER_NACHNAME = "u:saml_surname"; + public static final String HEADER_GEBURTSORT = "u:saml_placeofbirth"; + public static final String HEADER_GEBURTSNAME = "u:saml_birthname"; + public static final String HEADER_EMAIL = "u:saml_mail"; + public static final String HEADER_TELEFON = "u:saml_telephonenumber"; + public static final String HEADER_STRASSE = "u:saml_postaladdress"; + public static final String HEADER_PLZ = "u:saml_postalcode"; + public static final String HEADER_ORT = "u:saml_localityname"; + + public Map<String, Object> getHeader(Document document) { + var map = new HashMap<String, Object>(); + Consumer<Attr> addHeader = attr -> map.put(attr.getName(), attr.getValue()); + getAttribute(document, HEADER_POSTFACH_ID).ifPresent(addHeader); + getAttribute(document, HEADER_VORNAME).ifPresent(addHeader); + getAttribute(document, HEADER_NACHNAME).ifPresent(addHeader); + getAttribute(document, HEADER_GEBURTSNAME).ifPresent(addHeader); + getAttribute(document, HEADER_GEBURTSORT).ifPresent(addHeader); + getAttribute(document, HEADER_EMAIL).ifPresent(addHeader); + getAttribute(document, HEADER_TELEFON).ifPresent(addHeader); + getAttribute(document, HEADER_STRASSE).ifPresent(addHeader); + getAttribute(document, HEADER_PLZ).ifPresent(addHeader); + getAttribute(document, HEADER_ORT).ifPresent(addHeader); + return map; + } + + Optional<Attr> getAttribute(Document document, String name) { + return Optional.ofNullable(document.getDocumentElement().getAttributeNode(name)); + } +} \ No newline at end of file diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java index 5d9faa593aa0a61b19dee676ab2a233106e010f3..f4796328f0f9469c17291a9f4dfda6655c1213cf 100644 --- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java +++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java @@ -86,6 +86,9 @@ class SemantikFormDataMapper { @Autowired private final AttachmentsContentAdder attachmentsContentAdder; + @Autowired + private final CustomHeaderReader customHeaderReader; + public FormData mapToFormData(Deposit depositData) { var xmlFormDataStream = getXmlFormData(depositData.getData()); @@ -156,6 +159,7 @@ class SemantikFormDataMapper { map.put(HEADER_CUSTOMER_ID, document.getDocumentElement().getAttribute(HEADER_CUSTOMER_ID)); map.put(HEADER_CLIENT, document.getDocumentElement().getAttribute(HEADER_CLIENT)); map.put(HEADER_CLIENT_ID, document.getDocumentElement().getAttribute(HEADER_CLIENT_ID)); + map.putAll(customHeaderReader.getHeader(document)); return map; } } \ No newline at end of file diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eb435c85ecd0d0dc5214f7a595abc7bd9632f396 --- /dev/null +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.eingang.intelliform; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +class CustomHeaderReaderTest { + + @InjectMocks + private CustomHeaderReader reader; + + @Mock + private Document document; + @Mock + private Element element; + @Mock + private Attr attribute; + + @BeforeEach + void setup() { + when(document.getDocumentElement()).thenReturn(element); + } + + @Test + void shouldNotAddIfNotPresent() { + var formData = reader.getHeader(document); + + assertThat(formData).isEmpty(); + } + + @Nested + class TestHeaderAdded { + + @BeforeEach + void setup() { + when(element.getAttributeNode(any())).thenReturn(attribute); + } + + @Test + void shouldAddPostfachId() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_POSTFACH_ID); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.POSTFACH_ID); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID); + } + + @Test + void shouldAddVorname() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_VORNAME); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.VORNAME); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_VORNAME, CustomHeaderTestFactory.VORNAME); + } + + @Test + void shouldAddNachname() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_NACHNAME); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.NACHNAME); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_NACHNAME, CustomHeaderTestFactory.NACHNAME); + } + + @Test + void shouldAddGeburtsname() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_GEBURTSNAME); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.GEBURTSNAME); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_GEBURTSNAME, CustomHeaderTestFactory.GEBURTSNAME); + } + + @Test + void shouldAddGeburtsort() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_GEBURTSORT); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.GEBURTSORT); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_GEBURTSORT, CustomHeaderTestFactory.GEBURTSORT); + } + + @Test + void shouldAddEmail() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_EMAIL); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.EMAIL); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_EMAIL, CustomHeaderTestFactory.EMAIL); + } + + @Test + void shouldAddTelefon() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_TELEFON); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.TELEFON); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_TELEFON, CustomHeaderTestFactory.TELEFON); + } + + @Test + void shouldAddStrasse() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_STRASSE); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.STRASSE); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_STRASSE, CustomHeaderTestFactory.STRASSE); + } + + @Test + void shouldAddPlz() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_PLZ); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.PLZ); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_PLZ, CustomHeaderTestFactory.PLZ); + } + + @Test + void shouldAddOrt() { + when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_ORT); + when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.ORT); + + var formData = reader.getHeader(document); + + assertThat(formData).containsEntry(CustomHeaderReader.HEADER_ORT, CustomHeaderTestFactory.ORT); + } + } + +} \ No newline at end of file diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..acb9fede61f17309e4417fac7149f5d03177c588 --- /dev/null +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.eingang.intelliform; + + +import java.util.HashMap; +import java.util.Map; + +public class CustomHeaderTestFactory { + + public static final String POSTFACH_ID = "postfach_id"; + public static final String VORNAME = "vorname"; + public static final String NACHNAME = "nachname"; + public static final String GEBURTSNAME = "geburtsname"; + public static final String GEBURTSORT = "geburtsort"; + public static final String EMAIL = "email"; + public static final String TELEFON = "telefon"; + public static final String STRASSE = "strasse"; + public static final String PLZ = "plz"; + public static final String ORT = "ort"; + + public static Map<String, Object> create() { + var map = new HashMap<String, Object>(); + map.put(CustomHeaderReader.HEADER_POSTFACH_ID, POSTFACH_ID); + map.put(CustomHeaderReader.HEADER_VORNAME, VORNAME); + map.put(CustomHeaderReader.HEADER_NACHNAME, NACHNAME); + map.put(CustomHeaderReader.HEADER_GEBURTSNAME, GEBURTSNAME); + map.put(CustomHeaderReader.HEADER_GEBURTSORT, GEBURTSORT); + map.put(CustomHeaderReader.HEADER_EMAIL, EMAIL); + map.put(CustomHeaderReader.HEADER_TELEFON, TELEFON); + map.put(CustomHeaderReader.HEADER_STRASSE, STRASSE); + map.put(CustomHeaderReader.HEADER_PLZ, PLZ); + map.put(CustomHeaderReader.HEADER_ORT, ORT); + return map; + } + +} diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java index 36f64310aaf25183df3acdb36f93567032e43576..3bf90315f3d0be4e23ea2de093908455ad32b18e 100644 --- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java +++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java @@ -25,6 +25,8 @@ package de.ozgcloud.eingang.intelliform; import static de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory.*; import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import java.io.IOException; import java.util.HashMap; @@ -33,8 +35,10 @@ import java.util.Map; import javax.xml.parsers.ParserConfigurationException; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Mock; import org.xml.sax.SAXException; import de.ozgcloud.eingang.common.formdata.FormData; @@ -43,8 +47,16 @@ import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper; class SemantikFormDataMapperTest { - private SemantikFormDataMapper mapper = new SemantikFormDataMapper(new XmlToJavaMapsMapper(), new FormDataIncomingFileMapper(), - new RepresentationsCalculator(), new DepositRequestIncomingFileMapper(), new AttachmentsContentAdder()); + private SemantikFormDataMapper mapper; + + @Mock + private CustomHeaderReader customHeaderReader; + + @BeforeEach + void setup() { + mapper = new SemantikFormDataMapper(new XmlToJavaMapsMapper(), new FormDataIncomingFileMapper(), + new RepresentationsCalculator(), new DepositRequestIncomingFileMapper(), new AttachmentsContentAdder(), customHeaderReader); + } @Nested class TestMapFormData { @@ -136,6 +148,17 @@ class SemantikFormDataMapperTest { .containsEntry(SemantikFormDataMapper.HEADER_CLIENT_ID, "land"); } + @Test + void shouldAddBayernHeader() { + Map<String, Object> bayernHeader = Map.of(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID); + when(customHeaderReader.getHeader(any())).thenReturn(bayernHeader); + + var formData = mapToFormData(deposit); + + verify(customHeaderReader).getHeader(any()); + assertThat(getHeader(formData)).containsEntry(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID); + } + @SuppressWarnings("unchecked") private Map<String, Object> getHeader(FormData formData) { return (Map<String, Object>) formData.getFormData().get(SemantikFormDataMapper.HEADER_FIELD); diff --git a/pom.xml b/pom.xml index c15af03eb29fbfe728961eb1147e8d055afedb1c..61e2d1200e8926055bcf9a0a9910f4ce50ff7965 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.1.1</version> + <version>2.2.0-SNAPSHOT</version> <packaging>pom</packaging> <name>OZG-Cloud Eingang Manager</name> diff --git a/router/pom.xml b/router/pom.xml index a4f1c2631f994fd5c82c85463813175df13123ab..3b7fb7515d8a5afdbd11f3a4f0107f38a03a0fea 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> diff --git a/run_helm_test.sh b/run_helm_test.sh index 5c2ac8a359d9b3be43e39c05eddf49e36d5f2a2d..76ae9ac809e2a17d7c58020c0cff75be781f1e48 100755 --- a/run_helm_test.sh +++ b/run_helm_test.sh @@ -4,4 +4,4 @@ set -e helm template ./src/main/helm/ -f src/test/helm-linter-values.yaml helm lint -f src/test/helm-linter-values.yaml ./src/main/helm/ -cd src/main/helm && helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/unit-values.yaml' . \ No newline at end of file +cd src/main/helm && helm unittest -f '../../test/helm/*.yaml' -v '../../test/unit-values.yaml' . \ No newline at end of file diff --git a/semantik-adapter/pom.xml b/semantik-adapter/pom.xml index 8c63a7642f99176f6de8246b8c2feda90e506188..7cf306d372be87c17859498ffbcff6b72891a32b 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> </parent> <artifactId>semantik-adapter</artifactId> diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelper.java index ee1bdab680bbf3e85b7708af5f766bb11fbf3584..1ec87a0e456865b00b7edbddf0834dad0f8e9948 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelper.java @@ -18,18 +18,19 @@ import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; public class ServiceKontoBuildHelper { public static final int POSTFACH_ADDRESS_DEFAULT = 1; - public static final String POSTFACH_TYPE = "OSI"; + public static final String POSTFACH_TYPE_OSI = "OSI"; + public static final String POSTFACH_TYPE_BAYERN_ID = "BayernID"; public static final String POSTFACH_VERSION = "1.0"; public static final String REST_RESPONSE_NAME = "rest_response_name"; public static final String REST_RESPONSE_NAME_MEMBER_SCOPE = "memberscope"; public static final String REST_RESPONSE_NAME_MEMBER_SCOPE_MAILBOX_TYPE = "mailboxtype"; - public ServiceKonto buildServiceKonto(String postfachId) { + public ServiceKonto buildOsiServiceKonto(String postfachId) { return buildDefault(postfachId); } - public ServiceKonto buildServiceKonto(String postfachId, FormData formData) { + public ServiceKonto buildOsiServiceKonto(String postfachId, FormData formData) { return Optional.ofNullable(getRestResponseNames(formData)) .filter(names -> !names.isEmpty()) .map(restResponseNames -> buildWithRestResponseNames(postfachId, restResponseNames)) @@ -37,7 +38,7 @@ public class ServiceKontoBuildHelper { } ServiceKonto buildDefault(String postfachId) { - return ServiceKonto.builder().type(POSTFACH_TYPE).postfachAddress(buildPostfachAddress(postfachId)).build(); + return ServiceKonto.builder().type(POSTFACH_TYPE_OSI).postfachAddress(buildPostfachAddress(postfachId)).build(); } @SuppressWarnings("unchecked") @@ -50,31 +51,27 @@ public class ServiceKontoBuildHelper { ServiceKonto buildWithRestResponseNames(String postfachId, List<Map<String, Object>> restResponseNames) { return ServiceKonto.builder() - .type(POSTFACH_TYPE) + .type(POSTFACH_TYPE_OSI) .postfachAddresses(buildPostfachAddresses(buildIdentifier(postfachId), restResponseNames)) .build(); } - private PostfachAddressIdentifier buildIdentifier(String postfachId) { - return StringBasedIdentifier.builder().postfachId(postfachId).build(); - } - List<PostfachAddress> buildPostfachAddresses(PostfachAddressIdentifier identifier, List<Map<String, Object>> restResponseNames) { return restResponseNames.stream().map(entry -> buildOsiPostfachV1Address(identifier, entry)).toList(); } - private PostfachAddress buildPostfachAddress(String postkorbHandle) { + PostfachAddress buildOsiPostfachV1Address(PostfachAddressIdentifier identifier, Map<String, Object> restResponseName) { + return buildOsiPostfachV1Address(identifier, getPostfachAddressType(restResponseName)); + } + + PostfachAddress buildOsiPostfachV1Address(PostfachAddressIdentifier identifier, int postfachAddressType) { return PostfachAddress.builder() - .type(POSTFACH_ADDRESS_DEFAULT) + .type(postfachAddressType) .version(POSTFACH_VERSION) - .identifier(buildIdentifier(postkorbHandle)) + .identifier(identifier) .build(); } - PostfachAddress buildOsiPostfachV1Address(PostfachAddressIdentifier identifier, Map<String, Object> restResponseName) { - return buildOsiPostfachV1Address(identifier, getPostfachAddressType(restResponseName)); - } - int getPostfachAddressType(Map<String, Object> restResponseName) { return getMailboxType(restResponseName); } @@ -88,11 +85,20 @@ public class ServiceKontoBuildHelper { return ((List<Map<String, Object>>) restResponseName.get(REST_RESPONSE_NAME_MEMBER_SCOPE)).get(0); } - PostfachAddress buildOsiPostfachV1Address(PostfachAddressIdentifier identifier, int postfachAddressType) { + public ServiceKonto buildBayernIdServiceKonto(String postfachId) { + return ServiceKonto.builder().type(POSTFACH_TYPE_BAYERN_ID).postfachAddress(buildPostfachAddress(postfachId)).build(); + } + + PostfachAddress buildPostfachAddress(String postkorbHandle) { return PostfachAddress.builder() - .type(postfachAddressType) + .type(POSTFACH_ADDRESS_DEFAULT) .version(POSTFACH_VERSION) - .identifier(identifier) + .identifier(buildIdentifier(postkorbHandle)) .build(); } + + private PostfachAddressIdentifier buildIdentifier(String postfachId) { + return StringBasedIdentifier.builder().postfachId(postfachId).build(); + } + } \ No newline at end of file diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..3171846b129f4f676a7392d2f857e0f72714705c --- /dev/null +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapper.java @@ -0,0 +1,67 @@ +package de.ozgcloud.eingang.semantik.enginebased.afm; + +import static java.util.Objects.*; +import static org.apache.commons.lang3.StringUtils.*; + +import java.util.Collections; +import java.util.Map; + +import org.springframework.stereotype.Component; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.common.formdata.Antragsteller; +import de.ozgcloud.eingang.common.formdata.FormData; + +@Component +public class AfmAntragstellerHeaderMapper { + + static final String KEY_POSTFACH_ID = "u:saml_legacypostkorbhandle"; + static final String KEY_VORNAME = "u:saml_givenname"; + static final String KEY_NACHNAME = "u:saml_surname"; + static final String KEY_GEBURTSORT = "u:saml_placeofbirth"; + public static final String KEY_GEBURTSNAME = "u:saml_birthname"; + static final String KEY_EMAIL = "u:saml_mail"; + static final String KEY_TELEFON = "u:saml_telephonenumber"; + static final String KEY_STRASSE = "u:saml_postaladdress"; + static final String KEY_PLZ = "u:saml_postalcode"; + static final String KEY_ORT = "u:saml_localityname"; + + public FormData parseAntragstellerData(FormData formData) { + return formData.toBuilder().antragsteller(buildAntragsteller(getHeaders(formData))).build(); + } + + Antragsteller buildAntragsteller(Map<String, Object> headers) { + return Antragsteller.builder() + .postfachId((String) headers.get(KEY_POSTFACH_ID)) + .vorname((String) headers.get(KEY_VORNAME)) + .nachname((String) headers.get(KEY_NACHNAME)) + .geburtsname((String) headers.get(KEY_GEBURTSNAME)) + .geburtsort((String) headers.get(KEY_GEBURTSORT)) + .email((String) headers.get(KEY_EMAIL)) + .telefon((String) headers.get(KEY_TELEFON)) + .strasse((String) headers.get(KEY_STRASSE)) + .plz((String) headers.get(KEY_PLZ)) + .ort((String) headers.get(KEY_ORT)) + .build(); + } + + public boolean isResponsible(FormData formData) { + var headers = getHeaders(formData); + return headers.containsKey(KEY_POSTFACH_ID) && isPostfachIdNotBlank(headers.get(KEY_POSTFACH_ID)); + } + + @SuppressWarnings("unchecked") + Map<String, Object> getHeaders(FormData formData) { + return (Map<String, Object>) formData.getFormData().getOrDefault(AfmHeaderMapper.HEADER_FIELD, Collections.emptyMap()); + } + + boolean isPostfachIdNotBlank(Object postfachId) { + if (isNull(postfachId)) { + return false; + } + if (postfachId instanceof String id) { + return isNotBlank(id); + } + throw new TechnicalException("Unexpected type of postfach id: " + postfachId.getClass().getName()); + } +} diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java index 68311943caa6e53772bfb97c3badb8994177d81e..4e5251da5812a678dd2234ab964de002cabd78e8 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import de.ozgcloud.eingang.common.formdata.Antragsteller; @@ -56,8 +57,14 @@ class AfmAntragstellerMapper implements AfmEngineBasedMapper { static final String PLZ = "sh_plz"; static final String ORT = "ort"; + @Autowired + private AfmAntragstellerHeaderMapper antragstellerHeaderMapper; + @Override public FormData parseFormData(FormData formData) { + if (antragstellerHeaderMapper.isResponsible(formData)) { + return antragstellerHeaderMapper.parseAntragstellerData(formData); + } var formDataMap = formData.getFormData(); var builder = Antragsteller.builder().postfachId(getPostfachId(formDataMap)); diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapper.java index a0ee78f8211d9514320c81f127db0b2eb60b02a3..2984f9a6d257eeae0e1c6e2d361383b37d6a2dbb 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapper.java @@ -34,6 +34,7 @@ import org.springframework.stereotype.Component; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataUtils; import de.ozgcloud.eingang.common.formdata.FormHeader; +import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.semantik.enginebased.ServiceKontoBuildHelper; @Component @@ -73,29 +74,40 @@ class AfmHeaderMapper implements AfmEngineBasedMapper { .formEngineName(AFM_FORMENGINE_NAME) .build(); - Optional.ofNullable(getNameId(formData)) - .map(nameId -> serviceKontoBuildHelper.buildServiceKonto(nameId, formData)) - .ifPresent(formHeaderBuilder::setServiceKonto); + createBayernIdServiceKonto(formData).or(() -> createOsiServiceKonto(formData)).ifPresent(formHeaderBuilder::setServiceKonto); return formHeaderBuilder; } + private ZonedDateTime getCreatedAt(Map<String, Object> headerDataMap) { + return ZonedDateTime.parse((String) headerDataMap.get(TIMESTAMP), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + Optional<ServiceKonto> createBayernIdServiceKonto(FormData formData) { + var postfachId1 = getPostfachId(formData); + return postfachId1.map(postfachId -> serviceKontoBuildHelper.buildBayernIdServiceKonto(postfachId)); + } + + Optional<String> getPostfachId(FormData formData) { + return Optional.ofNullable(getHeaderMap(formData)).map(headers -> headers.get(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID)) + .map(String.class::cast); + } + @SuppressWarnings("unchecked") - private Map<String, Object> getHeaderMap(FormData formData) { + Map<String, Object> getHeaderMap(FormData formData) { return (Map<String, Object>) formData.getFormData().get(HEADER_FIELD); } - private ZonedDateTime getCreatedAt(Map<String, Object> headerDataMap) { - return ZonedDateTime.parse((String) headerDataMap.get(TIMESTAMP), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + Optional<ServiceKonto> createOsiServiceKonto(FormData formData) { + return getNameId(formData).map(nameId -> serviceKontoBuildHelper.buildOsiServiceKonto(nameId, formData)); } - private String getNameId(FormData formData) { - return (String) formData.getFormData().get(POSTFACH_NAME_ID); + private Optional<String> getNameId(FormData formData) { + return Optional.of(formData.getFormData()).map(formDataMap -> formDataMap.get(POSTFACH_NAME_ID)).map(String.class::cast); } private FormData removeMappedData(FormData formData) { return FormDataUtils.from(formData) - .remove(HEADER_FIELD) .remove(ServiceKontoBuildHelper.REST_RESPONSE_NAME) .build(); } diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapper.java index 38d6a8853605d1713cb1faf97d1a8cd01e0c87d6..0c8bc2d63bcbf51bdfba7f6963cac424c773c7e8 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapper.java @@ -66,7 +66,7 @@ class FormSolutionsHeaderMapper implements FormSolutionsEngineBasedMapper { .requestId(getRequestId(formData)) .formEngineName(FORM_ENGINE_NAME); - Optional.ofNullable(getPostkorbhandle(formData)).map(serviceKontoBuildHelper::buildServiceKonto).ifPresent(formHeaderBuilder::serviceKonto); + Optional.ofNullable(getPostkorbhandle(formData)).map(serviceKontoBuildHelper::buildOsiServiceKonto).ifPresent(formHeaderBuilder::serviceKonto); return formHeaderBuilder.build(); } diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java index 1972f9b46f1834205a01c2b0b649c7e51c2b0418..6c2292d48b4b596feef5e0abdc3d087099a94d9d 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapper.java @@ -87,7 +87,7 @@ public class DFoerdermittelFormBasedMapper implements FormBasedMapper { } private ServiceKonto createServiceKonto(String postfachId) { - return serviceKontoHelper.buildServiceKonto(postfachId); + return serviceKontoHelper.buildOsiServiceKonto(postfachId); } FormData parseFachnachricht(FormData formData, IncomingFile fachnachrichtFile) { diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelperTest.java index e21842bd3ad9a201de98d85bf92515f4d606b2a4..8d49520d80e2d2ef27042b0dc2399202e44466c9 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/ServiceKontoBuildHelperTest.java @@ -10,6 +10,7 @@ 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.InjectMocks; import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; @@ -18,17 +19,17 @@ import de.ozgcloud.eingang.common.formdata.PostfachAddressTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier; import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress; -import de.ozgcloud.eingang.semantik.enginebased.ServiceKontoBuildHelper; import de.ozgcloud.eingang.semantik.enginebased.afm.AfmHeaderTestFactory; class ServiceKontoBuildHelperTest { @Spy - private ServiceKontoBuildHelper helper = new ServiceKontoBuildHelper(); + @InjectMocks + private ServiceKontoBuildHelper helper; - @DisplayName("service konto") + @DisplayName("OSI service konto") @Nested - class TestServiceKonto { + class TestOsiServiceKonto { private static final FormData FORM_DATA = FormData.builder().formData(AfmHeaderTestFactory.createFormDataMap()).build(); @@ -47,7 +48,7 @@ class ServiceKontoBuildHelperTest { void shouldContainsType() { var serviceKonto = getServiceKonto(FORM_DATA); - assertThat(serviceKonto.getType()).isEqualTo(ServiceKontoBuildHelper.POSTFACH_TYPE); + assertThat(serviceKonto.getType()).isEqualTo(ServiceKontoBuildHelper.POSTFACH_TYPE_OSI); } @Test @@ -67,7 +68,7 @@ class ServiceKontoBuildHelperTest { } private ServiceKonto getServiceKonto(FormData formData) { - return helper.buildServiceKonto(AfmHeaderTestFactory.POSTFACH_NAME_ID, formData); + return helper.buildOsiServiceKonto(AfmHeaderTestFactory.POSTFACH_NAME_ID, formData); } @DisplayName("postfach addresses") @@ -136,8 +137,35 @@ class ServiceKontoBuildHelperTest { } private ServiceKonto buildServiceKonto(FormData formData) { - return helper.buildServiceKonto(AfmHeaderTestFactory.POSTFACH_NAME_ID, formData); + return helper.buildOsiServiceKonto(AfmHeaderTestFactory.POSTFACH_NAME_ID, formData); } } } + + @Nested + class TestBayernIdServiceKonto { + + private static final String POSTFACH_ID = "postfach-id"; + private static final PostfachAddress POSTFACH_ADDRESS = PostfachAddressTestFactory.create(); + + @Test + void shouldSetType() { + var serviceKonto = buildBayernIdServiceKonto(); + + assertThat(serviceKonto.getType()).isEqualTo(ServiceKontoBuildHelper.POSTFACH_TYPE_BAYERN_ID); + } + + @Test + void shouldSetPostfachAddress() { + doReturn(POSTFACH_ADDRESS).when(helper).buildPostfachAddress(any()); + + var serviceKonto = buildBayernIdServiceKonto(); + + assertThat(serviceKonto.getPostfachAddresses()).containsOnly(POSTFACH_ADDRESS); + } + + ServiceKonto buildBayernIdServiceKonto() { + return helper.buildBayernIdServiceKonto(POSTFACH_ID); + } + } } \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..953ff17d4427885712c3d95f1b9524b0b1dc1bc1 --- /dev/null +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapperTest.java @@ -0,0 +1,241 @@ +package de.ozgcloud.eingang.semantik.enginebased.afm; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +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.AntragstellerTestFactory; +import de.ozgcloud.eingang.common.formdata.FormData; + +class AfmAntragstellerHeaderMapperTest { + + @Spy + @InjectMocks + private AfmAntragstellerHeaderMapper mapper; + + @Nested + class TestParseAntragstellerData { + + @Test + void shouldCallGetHeaders() { + var formData = FormData.builder().build(); + doReturn(Collections.emptyMap()).when(mapper).getHeaders(any()); + + mapper.parseAntragstellerData(formData); + + verify(mapper).getHeaders(formData); + } + + @Test + void shouldCallBuildAntragsteller() { + var headerMap = AfmHeaderTestFactory.createCustomHeaderMap(); + doReturn(headerMap).when(mapper).getHeaders(any()); + + mapper.parseAntragstellerData(FormData.builder().build()); + + verify(mapper).buildAntragsteller(headerMap); + } + + @Test + void shouldSetAntragsteller() { + var antragsteller = AntragstellerTestFactory.create(); + doReturn(antragsteller).when(mapper).buildAntragsteller(any()); + + var result = mapper.parseAntragstellerData(FormData.builder().build()); + + assertThat(result.getAntragsteller()).isEqualTo(antragsteller); + } + + @Nested + class TestBuildAntragsteller { + + private Map<String, Object> headers = AfmHeaderTestFactory.createCustomHeaderMap(); + @Test + void shouldSetPostfachId() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getPostfachId()).isEqualTo(AfmHeaderTestFactory.CUSTOM_POSTFACH_ID); + } + + @Test + void shouldSetVorname() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getVorname()).isEqualTo(AfmHeaderTestFactory.CUSTOM_VORNAME); + } + + @Test + void shouldSetNachname() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getNachname()).isEqualTo(AfmHeaderTestFactory.CUSTOM_NACHNAME); + } + + @Test + void shouldSetGeburtsname() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getGeburtsname()).isEqualTo(AfmHeaderTestFactory.CUSTOM_GEBURTSNAME); + } + + @Test + void shouldSetGeburtsort() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getGeburtsort()).isEqualTo(AfmHeaderTestFactory.CUSTOM_GEBURTSORT); + } + + @Test + void shoudlSetEmail() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getEmail()).isEqualTo(AfmHeaderTestFactory.CUSTOM_EMAIL); + } + + @Test + void shouldSetTelefon() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getTelefon()).isEqualTo(AfmHeaderTestFactory.CUSTOM_TELEFON); + } + + @Test + void shouldSetStrasse() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getStrasse()).isEqualTo(AfmHeaderTestFactory.CUSTOM_STRASSE); + } + + @Test + void shouldSetPlz() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getPlz()).isEqualTo(AfmHeaderTestFactory.CUSTOM_PLZ); + } + + @Test + void shouldSetOrt() { + var result = mapper.buildAntragsteller(headers); + + assertThat(result.getOrt()).isEqualTo(AfmHeaderTestFactory.CUSTOM_ORT); + } + } + } + + @Nested + class TestIsResponsible { + + @Mock + private FormData formData; + + @Test + void shouldApproveResponsibility() { + doReturn(true).when(mapper).isPostfachIdNotBlank(any()); + doReturn(createHeaders(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, "123")).when(mapper).getHeaders(any()); + + var isResponsible = mapper.isResponsible(formData); + + assertTrue(isResponsible); + } + + @Nested + class TestDenyResponsibility { + + @Test + void shouldDenyWhenNoHeader() { + doReturn(Collections.emptyMap()).when(mapper).getHeaders(any()); + + var isResponsible = mapper.isResponsible(FormData.builder().build()); + + assertFalse(isResponsible); + } + + @Test + void shouldDenyWhenNoPostfachId() { + doReturn(createHeaders(AfmAntragstellerHeaderMapper.KEY_VORNAME, "name")).when(mapper).getHeaders(any()); + + var isResponsible = mapper.isResponsible(formData); + + assertFalse(isResponsible); + } + + void shouldDenyWhenPostfachIdIsBlank() { + doReturn(createHeaders(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, null)).when(mapper).getHeaders(any()); + doReturn(false).when(mapper).isPostfachIdNotBlank(any()); + + var isResponsible = mapper.isResponsible(formData); + + assertFalse(isResponsible); + } + + @Nested + class TestIsPostfachIdNotBlank { + + @ParameterizedTest + @NullAndEmptySource + void shouldReturnFalseWhenPostfachIdIsBlank(String postfachId) { + var isNotBlank = mapper.isPostfachIdNotBlank(postfachId); + + assertFalse(isNotBlank); + } + + @Test + void shouldApprove() { + var isNotBlank = mapper.isPostfachIdNotBlank("123"); + + assertTrue(isNotBlank); + } + + @Test + void shouldFailOnUnexpectedType() { + var postfachId = new Object(); + + assertThrows(TechnicalException.class, () -> mapper.isPostfachIdNotBlank(postfachId)); + } + } + } + } + + @Nested + class TestGetHeaders { + + @Test + void shouldReturnHeaders() { + var headers = createHeaders(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, "123"); + var formData = FormData.builder().formData(createHeaders(AfmHeaderMapper.HEADER_FIELD, headers)).build(); + + var result = mapper.getHeaders(formData); + + assertThat(result).isEqualTo(headers); + } + + @Test + void shouldReturnEmptyMapWhenNoHeaders() { + var formData = FormData.builder().build(); + + var result = mapper.getHeaders(formData); + + assertThat(result).isEmpty(); + } + } + + private Map<String, Object> createHeaders(String key, Object value) { + var map = new HashMap<String, Object>(); + map.put(key, value); + return map; + } +} \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java index 47e58c47132daae7675ac23a34c1134764a08cc9..e40b13db45356729cd68b0fec172931b999c4c17 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java @@ -24,6 +24,8 @@ package de.ozgcloud.eingang.semantik.enginebased.afm; import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import java.util.HashMap; import java.util.UUID; @@ -33,6 +35,9 @@ 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.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; import de.ozgcloud.eingang.common.formdata.Antragsteller; import de.ozgcloud.eingang.common.formdata.FormData; @@ -40,7 +45,11 @@ import de.ozgcloud.eingang.semantik.enginebased.afm.AfmAntragstellerMapper; class AfmAntragstellerMapperTest { - private AfmAntragstellerMapper mapper = new AfmAntragstellerMapper(); + @InjectMocks + private AfmAntragstellerMapper mapper; + + @Mock + private AfmAntragstellerHeaderMapper antragstellerHeaderMapper; private FormData formData = FormData.builder().formData(AfmAntragstellerTestFactory.createFormDataMap()).build(); @@ -48,6 +57,17 @@ class AfmAntragstellerMapperTest { @Nested class TestParseFormData { + @Test + void shouldCallHeaderMapper() { + FormData expectedFormData = mock(FormData.class); + when(antragstellerHeaderMapper.isResponsible(any())).thenReturn(true); + when(antragstellerHeaderMapper.parseAntragstellerData(any())).thenReturn(expectedFormData); + + var processedFormData = parseFormData(formData); + + assertThat(processedFormData).isEqualTo(expectedFormData); + } + @Test void shouldDoNothingOnNullAntragstaller() { var formData = FormData.builder().formData(new HashMap<>()).build(); diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapperTest.java index ed5eee1e2c41a092b4f5e67869fe0d208bcc7c28..93ddc2f4f3e24d4dd2b4c045e6a4d8e39a23086c 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderMapperTest.java @@ -27,6 +27,9 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Map; +import java.util.Optional; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -36,14 +39,14 @@ import org.mockito.Spy; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataUtils; +import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.semantik.enginebased.ServiceKontoBuildHelper; -import de.ozgcloud.eingang.semantik.enginebased.afm.AfmHeaderMapper; class AfmHeaderMapperTest { @Spy @InjectMocks - private final AfmHeaderMapper mapper = new AfmHeaderMapper(); + private AfmHeaderMapper mapper; @Mock private ServiceKontoBuildHelper serviceKontoBuildHelper; @@ -57,6 +60,13 @@ class AfmHeaderMapperTest { private static final FormData FORM_DATA = FormData.builder().formData(AfmHeaderTestFactory.createFormDataMap()).build(); + @Test + void shouldKeepHeader() { + var parsedFormData = parseFormData(); + + assertThat(parsedFormData.getFormData().get(AfmHeaderMapper.HEADER_FIELD)).isNotNull(); + } + @DisplayName("fields") @Nested class TestFields { @@ -107,24 +117,66 @@ class AfmHeaderMapperTest { @Nested class TestServiceKonto { - @Test - void shouldCallBuildServiceKontoIfPresent() { - parseFormData(); + @DisplayName("OSI") + @Nested + class TestOsiServiceKonto { + @Test + void shouldCallBuildServiceKontoIfPresent() { + parseFormData(); + + verify(serviceKontoBuildHelper).buildOsiServiceKonto(any(), eq(FORM_DATA)); + } + + @Test + void shouldNotCallBuildServiceKontoIfNotExists() { + mapper.parseFormData(FormDataUtils.from(FORM_DATA).remove(AfmHeaderMapper.POSTFACH_NAME_ID).build()); - verify(serviceKontoBuildHelper).buildServiceKonto(any(), eq(FORM_DATA)); + verify(serviceKontoBuildHelper, never()).buildOsiServiceKonto(any(), any()); + } } - @Test - void shouldNotCallBuildServiceKontoIfNotExists() { - mapper.parseFormData(FormDataUtils.from(FORM_DATA).remove(AfmHeaderMapper.POSTFACH_NAME_ID).build()); + @DisplayName("BayernID") + @Nested + class TestBayernId { + + @Mock + private FormData formData; + @Mock + private ServiceKonto serviceKonto; + + @Test + void shouldCallCreateBayernIdServiceKonto() { + var formData = FormData.builder().formData(AfmHeaderTestFactory.createFormDataMapWithExtendedHeaders()).build(); - verify(serviceKontoBuildHelper, never()).buildServiceKonto(any(), any()); + mapper.parseFormData(formData); + + verify(mapper).createBayernIdServiceKonto(formData); + } + + @Test + void shouldReturnServiceKonto() { + doReturn(Optional.of("id")).when(mapper).getPostfachId(any()); + when(serviceKontoBuildHelper.buildBayernIdServiceKonto(any())).thenReturn(serviceKonto); + + var parsedFormData = mapper.createBayernIdServiceKonto(formData); + + assertThat(parsedFormData).isPresent().get().isEqualTo(serviceKonto); + } + + @Test + void shouldNotCallServiceKontoBuildHelper() { + doReturn(Optional.empty()).when(mapper).getPostfachId(any()); + + mapper.createBayernIdServiceKonto(formData); + + verify(serviceKontoBuildHelper, never()).buildBayernIdServiceKonto(any()); + } } } + } - private FormData parseFormData() { - return mapper.parseFormData(FORM_DATA); - } + private FormData parseFormData() { + return mapper.parseFormData(FORM_DATA); } } @@ -135,14 +187,7 @@ class AfmHeaderMapperTest { private final FormData formData = FormData.builder().formData(AfmHeaderTestFactory.createFormDataMap()).build(); @Test - void shouldRemoveHeader() { - var parsedFormData = parseFormData(); - - assertThat(parsedFormData.getFormData().get(AfmHeaderMapper.HEADER_FIELD)).isNull(); - } - - @Test - void shouldRemoveRestResponsName() { + void shouldRemoveRestResponseName() { var parsedFormData = parseFormData(); assertThat(parsedFormData.getFormData().get(ServiceKontoBuildHelper.REST_RESPONSE_NAME)).isNull(); @@ -153,4 +198,29 @@ class AfmHeaderMapperTest { } } } + + @Nested + class TestGetPostfachId { + + @Mock + private FormData formData; + + @Test + void shouldReturnPostfachId() { + doReturn(Map.of(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, AfmAntragstellerTestFactory.POSTFACH_ID)).when(mapper).getHeaderMap(any()); + + var postfachId = mapper.getPostfachId(formData); + + assertThat(postfachId).isPresent().get().isEqualTo(AfmAntragstellerTestFactory.POSTFACH_ID); + } + + @Test + void shouldReturnEmpty() { + doReturn(null).when(mapper).getHeaderMap(any()); + + var postfachId = mapper.getPostfachId(formData); + + assertThat(postfachId).isEmpty(); + } + } } \ No newline at end of file diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java index d3705fa4277593df269478566b7f1f221848d59b..4cdd6b5f7ed887dbd9841e0d844b5389b25bb366 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java @@ -38,6 +38,17 @@ public class AfmHeaderTestFactory { public static final String FORM = "Kleiner Waffenschein gem. § 10 Abs. 4 Satz 4 Waffengesetz (WaffG)"; public static final String SENDER = "afm.schleswig-holstein.de"; + public static final String CUSTOM_POSTFACH_ID = "postfach_id"; + public static final String CUSTOM_VORNAME = "vorname"; + public static final String CUSTOM_NACHNAME = "nachname"; + public static final String CUSTOM_GEBURTSNAME = "Geburtsname"; + public static final String CUSTOM_GEBURTSORT = "geburtsort"; + public static final String CUSTOM_EMAIL = "email"; + public static final String CUSTOM_TELEFON = "telefon"; + public static final String CUSTOM_STRASSE = "strasse"; + public static final String CUSTOM_PLZ = "plz"; + public static final String CUSTOM_ORT = "ort"; + public static final String POSTFACH_NAME_ID = "name-id-value"; public static final int REST_RESPONSE_NAME_MEMBER_SCOPE_MAILBOX_TYPE_VALUE = 1; @@ -51,6 +62,13 @@ public class AfmHeaderTestFactory { return map; } + @SuppressWarnings("unchecked") + public static Map<String, Object> createFormDataMapWithExtendedHeaders() { + var map = new HashMap<>(createFormDataMap()); + ((Map<String, Object>) map.get(AfmHeaderMapper.HEADER_FIELD)).putAll(createCustomHeaderMap()); + return map; + } + public static Map<String, Object> createHeaderMap() { var map = new HashMap<String, Object>(); map.put(AfmHeaderMapper.ID, ID); @@ -61,6 +79,21 @@ public class AfmHeaderTestFactory { return map; } + public static Map<String, Object> createCustomHeaderMap() { + var map = new HashMap<String, Object>(); + map.put(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, CUSTOM_POSTFACH_ID); + map.put(AfmAntragstellerHeaderMapper.KEY_VORNAME, CUSTOM_VORNAME); + map.put(AfmAntragstellerHeaderMapper.KEY_NACHNAME, CUSTOM_NACHNAME); + map.put(AfmAntragstellerHeaderMapper.KEY_GEBURTSNAME, CUSTOM_GEBURTSNAME); + map.put(AfmAntragstellerHeaderMapper.KEY_GEBURTSORT, CUSTOM_GEBURTSORT); + map.put(AfmAntragstellerHeaderMapper.KEY_EMAIL, CUSTOM_EMAIL); + map.put(AfmAntragstellerHeaderMapper.KEY_TELEFON, CUSTOM_TELEFON); + map.put(AfmAntragstellerHeaderMapper.KEY_STRASSE, CUSTOM_STRASSE); + map.put(AfmAntragstellerHeaderMapper.KEY_PLZ, CUSTOM_PLZ); + map.put(AfmAntragstellerHeaderMapper.KEY_ORT, CUSTOM_ORT); + return map; + } + public static Map<String, Object> createRestResponseNameMap() { return Map.of(ServiceKontoBuildHelper.REST_RESPONSE_NAME_MEMBER_SCOPE, List.of(createRestResponseNameMemberScopeMap())); } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapperTest.java index ce9964d6091dbb6f5d2fe89fb481c13e6a853464..89c782671e7e568ffebc70299df1fc8431499a71 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/formsolutions/FormSolutionsHeaderMapperTest.java @@ -39,7 +39,6 @@ import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataUtils; import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.semantik.enginebased.ServiceKontoBuildHelper; -import de.ozgcloud.eingang.semantik.enginebased.formsolutions.FormSolutionsHeaderMapper; class FormSolutionsHeaderMapperTest { @@ -120,7 +119,7 @@ class FormSolutionsHeaderMapperTest { void shouldCallServiceKontoBuildHelper() { buildFormHeader(); - verify(serviceKontoBuildHelper).buildServiceKonto(any()); + verify(serviceKontoBuildHelper).buildOsiServiceKonto(any()); } @Test @@ -129,7 +128,7 @@ class FormSolutionsHeaderMapperTest { mapper.buildFormHeader(formDataWithoutPostkorbHandle); - verify(serviceKontoBuildHelper, never()).buildServiceKonto(any()); + verify(serviceKontoBuildHelper, never()).buildOsiServiceKonto(any()); } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java index 2b5f2ddb6438a02872383a3cefb5936165f21a08..dc9d2d172dde4c1e84debbc0bb270e3e3437e8cb 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/formbased/DFoerdermittelFormBasedMapperTest.java @@ -166,7 +166,7 @@ class DFoerdermittelFormBasedMapperTest { @BeforeEach void init() { - when(serviceKontoHelper.buildServiceKonto(any())).thenReturn(ServiceKontoTestFactory.create()); + when(serviceKontoHelper.buildOsiServiceKonto(any())).thenReturn(ServiceKontoTestFactory.create()); } @Test @@ -183,7 +183,7 @@ class DFoerdermittelFormBasedMapperTest { void shouldRemovePrefix() { mapper.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); - verify(serviceKontoHelper).buildServiceKonto(DFoerdermittelFormDataTestFactory.POSTFACH_ID); + verify(serviceKontoHelper).buildOsiServiceKonto(DFoerdermittelFormDataTestFactory.POSTFACH_ID); } } diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl index 10c105666dc6ec19ce0a16e4334b2ff3ed1aa435..82a7d4757fd619634da2fe4d771717eac04fd1e4 100644 --- a/src/main/helm/templates/_helpers.tpl +++ b/src/main/helm/templates/_helpers.tpl @@ -83,5 +83,15 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }} {{- end -}} {{- define "app.serviceAccountName" -}} -{{ printf "%s" ( (.Values.serviceAccount).name | default "eingang-manager-service-account" ) }} +{{- if (.Values.serviceAccount).name }} +{{- printf "%s" .Values.serviceAccount.name }} +{{- else if eq (.Values.image).name "intelliform-adapter" }} +{{- printf "afm-adapter-service-account" }} +{{- else if eq (.Values.image).name "formsolutions-adapter" }} +{{- printf "fs-adapter-service-account" }} +{{- else if eq (.Values.image).name "formcycle-adapter" }} +{{- printf "formcycle-adapter-service-account" }} +{{- else if eq (.Values.image).name "enterprise-adapter" }} +{{- printf "enterprise-adapter-service-account" }} +{{- end }} {{- end -}} \ No newline at end of file diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml index c243a2b78267cbcbca542afa462cf40a2422f85d..929afd7c84be59aa8d39ca31148f72375a2c228b 100644 --- a/src/main/helm/templates/network_policy.yaml +++ b/src/main/helm/templates/network_policy.yaml @@ -55,4 +55,8 @@ spec: protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP {{- end }} \ No newline at end of file diff --git a/src/test/helm/deployment_defaults_labels_test.yaml b/src/test/helm/deployment_defaults_labels_test.yaml index 0b91b2423345ae8cb001fb2b602a55bd76703bf9..d6952edf6d1fb42b2ab2dcc11321b73d35c7e2d5 100644 --- a/src/test/helm/deployment_defaults_labels_test.yaml +++ b/src/test/helm/deployment_defaults_labels_test.yaml @@ -34,14 +34,14 @@ tests: - it: check default labels asserts: - equal: - path: metadata.labels.[app.kubernetes.io/instance] + path: metadata.labels["app.kubernetes.io/instance"] value: afm-adapter - equal: - path: metadata.labels.[app.kubernetes.io/name] + path: metadata.labels["app.kubernetes.io/name"] value: intelliform-adapter - equal: - path: metadata.labels.[app.kubernetes.io/part-of] + path: metadata.labels["app.kubernetes.io/part-of"] value: ozgcloud - equal: - path: metadata.labels.[app.kubernetes.io/namespace] + path: metadata.labels["app.kubernetes.io/namespace"] value: sh-helm-test diff --git a/src/test/helm/deployment_service_account_test.yaml b/src/test/helm/deployment_service_account_test.yaml index c3108cff4b6adf30955e3db6b8cf577bbba096cd..43aa6fcf59131f1fd9f4e0530a60b14551f89c9b 100644 --- a/src/test/helm/deployment_service_account_test.yaml +++ b/src/test/helm/deployment_service_account_test.yaml @@ -29,14 +29,42 @@ release: templates: - templates/deployment.yaml tests: - - it: should use service account with default name + - it: should use afm-adapter service account name set: + image.name: intelliform-adapter serviceAccount: create: true asserts: - equal: path: spec.template.spec.serviceAccountName - value: eingang-manager-service-account + value: afm-adapter-service-account + - it: should use fs-adapter service account name + set: + image.name: formsolutions-adapter + serviceAccount: + create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: fs-adapter-service-account + - it: should use formcycle-adapter service account name + set: + image.name: formcycle-adapter + serviceAccount: + create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: formcycle-adapter-service-account + - it: should use enterprise-adapter service account name + set: + image.name: enterprise-adapter + serviceAccount: + create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: enterprise-adapter-service-account - it: should use service account with name set: serviceAccount: diff --git a/src/test/helm/image-pull-secret-test.yaml b/src/test/helm/image-pull-secret-test.yaml index c95545170d0e4dd01fce0aab3a1c8953e3e20b5f..71e2149189f71dab73ffe321033ae29dc4bb4f65 100644 --- a/src/test/helm/image-pull-secret-test.yaml +++ b/src/test/helm/image-pull-secret-test.yaml @@ -47,7 +47,7 @@ tests: path: metadata.namespace value: helm-test - isNotEmpty: - path: data.[.dockerconfigjson] + path: data[".dockerconfigjson"] - it: should not create image pull secret set: diff --git a/src/test/helm/ingress_test.yaml b/src/test/helm/ingress_test.yaml index 7561bb305275f8ca3e90dc3a317c762bae8dd995..e5086079b97d4b11763d648d70352412d4e8d7ac 100644 --- a/src/test/helm/ingress_test.yaml +++ b/src/test/helm/ingress_test.yaml @@ -52,8 +52,9 @@ tests: value: intelliform-adapter - it: should match service path asserts: - - isEmpty: + - equal: path: spec.rules[0].http.paths[0].path + value: '' - it: should match service pathType asserts: - equal: @@ -106,7 +107,7 @@ tests: - it: should use letsencrypt-prod cluster-issuer as default asserts: - equal: - path: metadata.annotations.[cert-manager.io/cluster-issuer] + path: metadata.annotations["cert-manager.io/cluster-issuer"] value: letsencrypt-prod - it: should use letsencrypt-staging cluster-issuer if use_staging_cert is true @@ -114,7 +115,7 @@ tests: ingress.use_staging_cert: true asserts: - equal: - path: metadata.annotations.[cert-manager.io/cluster-issuer] + path: metadata.annotations["cert-manager.io/cluster-issuer"] value: letsencrypt-staging - it: should use letsencrypt-prod cluster-issuer if use_staging_cert is false @@ -122,10 +123,10 @@ tests: ingress.use_staging_cert: false asserts: - equal: - path: metadata.annotations.[cert-manager.io/cluster-issuer] + path: metadata.annotations["cert-manager.io/cluster-issuer"] value: letsencrypt-prod - it: should set proxy body size to 42m asserts: - equal: - path: metadata.annotations.[nginx.ingress.kubernetes.io/proxy-body-size] + path: metadata.annotations["nginx.ingress.kubernetes.io/proxy-body-size"] value: 42m \ No newline at end of file diff --git a/src/test/helm/network_policy_test.yaml b/src/test/helm/network_policy_test.yaml index 15c3a1ad88d74d6f694f27a7698a81237f91fa1c..1abf7b15ee0077fc1c4811d6b323e709ad83e5a1 100644 --- a/src/test/helm/network_policy_test.yaml +++ b/src/test/helm/network_policy_test.yaml @@ -87,6 +87,10 @@ tests: protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - it: test network policy disabled set: diff --git a/src/test/helm/service_account_test.yaml b/src/test/helm/service_account_test.yaml index 4f8f2fe84b5b1e57dbbfb5844673bac980630f93..52561bed188a291f689b81480f02126cd8aed6bc 100644 --- a/src/test/helm/service_account_test.yaml +++ b/src/test/helm/service_account_test.yaml @@ -29,8 +29,9 @@ release: templates: - templates/service_account.yaml tests: - - it: should create service account with default name + - it: should create default afm adapter service account name set: + image.name: intelliform-adapter serviceAccount: create: true asserts: @@ -38,7 +39,49 @@ tests: of: ServiceAccount - equal: path: metadata.name - value: eingang-manager-service-account + value: afm-adapter-service-account + - equal: + path: metadata.namespace + value: sh-helm-test + - it: should create default fs adapter service account name + set: + image.name: formsolutions-adapter + serviceAccount: + create: true + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: fs-adapter-service-account + - equal: + path: metadata.namespace + value: sh-helm-test + - it: should create default formcycle adapter service account name + set: + image.name: formcycle-adapter + serviceAccount: + create: true + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: formcycle-adapter-service-account + - equal: + path: metadata.namespace + value: sh-helm-test + - it: should create default enterprise adapter service account name + set: + image.name: enterprise-adapter + serviceAccount: + create: true + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: enterprise-adapter-service-account - equal: path: metadata.namespace value: sh-helm-test diff --git a/src/test/helm/service_monitor_test.yaml b/src/test/helm/service_monitor_test.yaml index e20b931986f88f3d9c21a322109738238ef31b5f..55ebac3068844aafb2c632b1ab528b7cefe9cefe 100644 --- a/src/test/helm/service_monitor_test.yaml +++ b/src/test/helm/service_monitor_test.yaml @@ -34,7 +34,7 @@ tests: - isKind: of: ServiceMonitor - equal: - path: metadata.labels.[component] + path: metadata.labels["component"] value: afm-adapter-service-monitor - it: should have the metrics endpoint configured by default set: @@ -64,13 +64,13 @@ tests: - it: selector should contain the component label with the value afm-adapter-service asserts: - equal: - path: spec.selector.matchLabels.[component] + path: spec.selector.matchLabels["component"] value: afm-adapter-service - it: selector should contain helm recommended labels name and namespace asserts: - equal: - path: spec.selector.matchLabels.[app.kubernetes.io/name] + path: spec.selector.matchLabels["app.kubernetes.io/name"] value: afm-adapter - equal: - path: spec.selector.matchLabels.[app.kubernetes.io/namespace] + path: spec.selector.matchLabels["app.kubernetes.io/namespace"] value: sh-helm-test diff --git a/src/test/helm/service_test.yaml b/src/test/helm/service_test.yaml index f9680d60e2a5a8b75f9f2ab35274f58d2e0808ca..9004018482d301c6e942d4cc0112de534105a38e 100644 --- a/src/test/helm/service_test.yaml +++ b/src/test/helm/service_test.yaml @@ -34,7 +34,7 @@ tests: - isKind: of: Service - equal: - path: metadata.labels.[component] + path: metadata.labels["component"] value: afm-adapter-service - it: should be of type ClusterIP asserts: @@ -50,8 +50,8 @@ tests: port: 8080 protocol: TCP targetPort: 8080 - count: 1 - any: true + count: 1 + any: true - it: ports should contain the metrics port asserts: - contains: @@ -60,19 +60,19 @@ tests: name: metrics port: 8081 protocol: TCP - count: 1 - any: true + count: 1 + any: true - it: selector should contain the component label with the value afm-adapter asserts: - equal: - path: spec.selector.[component] + path: spec.selector["component"] value: afm-adapter - it: selector should contain helm recommended labels name and namespace asserts: - equal: - path: spec.selector.[app.kubernetes.io/name] + path: spec.selector["app.kubernetes.io/name"] value: afm-adapter - equal: - path: spec.selector.[app.kubernetes.io/namespace] + path: spec.selector["app.kubernetes.io/namespace"] value: sh-helm-test \ No newline at end of file diff --git a/xta-adapter/pom.xml b/xta-adapter/pom.xml index d303c7a0721ca4accc36f88b5c036f82ee259239..78b24fe76d101255ca182d1f83a649c8ef1bb09d 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.1.1</version> + <version>2.2.0-SNAPSHOT</version> </parent> <artifactId>xta-adapter</artifactId> <name>Eingangs Adapter - XTA</name> diff --git a/xta-adapter/run_helm_test.sh b/xta-adapter/run_helm_test.sh index 9e10b8f0eafbab2eac176bd51e453caedabec7fa..8cfc42013cc858b0d2f5afc2c43b12eb56b68bab 100755 --- a/xta-adapter/run_helm_test.sh +++ b/xta-adapter/run_helm_test.sh @@ -4,4 +4,4 @@ set -e helm template ./src/main/helm/ -f src/main/helm/test-values.yaml helm lint -f src/test/helm/values/unit-values.yaml ./src/main/helm/ -cd src/main/helm && helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/helm/values/unit-values.yaml' . \ No newline at end of file +cd src/main/helm && helm unittest -f '../../test/helm/*.yaml' -v '../../test/helm/values/unit-values.yaml' . \ No newline at end of file diff --git a/xta-adapter/src/main/helm/templates/_helpers.tpl b/xta-adapter/src/main/helm/templates/_helpers.tpl index 62e0d295881ee2e179cb8d66eb006d33a050488d..203aab813c0e2dbb6505eb2af8acc5ca1631b146 100644 --- a/xta-adapter/src/main/helm/templates/_helpers.tpl +++ b/xta-adapter/src/main/helm/templates/_helpers.tpl @@ -61,4 +61,8 @@ helm.sh/chart: {{ include "app.chart" . }} {{- else if eq (include "app.kopEnvironment" . ) "dev" -}} {{ "*/15 * * * *" | quote }} {{- end -}} +{{- end -}} + +{{- define "app.serviceAccountName" -}} +{{ printf "%s" ( (.Values.serviceAccount).name | default "xta-adapter-service-account" ) }} {{- end -}} \ No newline at end of file diff --git a/xta-adapter/src/main/helm/templates/network_policy.yaml b/xta-adapter/src/main/helm/templates/network_policy.yaml index 7f4528b855e504f713b0c92a8e43c21bb94afada..af39de580127094d2e02f139e14a73917db1b38e 100644 --- a/xta-adapter/src/main/helm/templates/network_policy.yaml +++ b/xta-adapter/src/main/helm/templates/network_policy.yaml @@ -45,24 +45,27 @@ spec: - to: - namespaceSelector: matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns + kubernetes.io/metadata.name: {{ required "networkPolicy.dnsServerNamespace must be set" (.Values.networkPolicy).dnsServerNamespace }} ports: - port: 53 protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: ssh-port-forward - ports: - - port: 9000 + ports: + - port: 443 protocol: TCP - {{- with (.Values.networkPolicy).additionalEgressConfig }} - - to: -{{ toYaml . | indent 8 }} - {{- end }} + - port: 80 + protocol: TCP +{{- with (.Values.networkPolicy).additionalEgressConfig }} +{{ toYaml . | indent 2 }} +{{- end }} + {{- end }} \ No newline at end of file diff --git a/xta-adapter/src/main/helm/templates/service_account.yaml b/xta-adapter/src/main/helm/templates/service_account.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0e13e6bcabf1933117c29487473453b63265922a --- /dev/null +++ b/xta-adapter/src/main/helm/templates/service_account.yaml @@ -0,0 +1,31 @@ +# +# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +{{- if (.Values.serviceAccount).create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + namespace: {{ include "app.namespace" . }} +{{- end }} \ No newline at end of file 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 c3bca9d7feb890b449f04fe8ff8d974d6d287b8b..dc0be81abbdbb5a3dbf65a27f7abb32746c86c2c 100644 --- a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml +++ b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml @@ -44,6 +44,9 @@ spec: workload: xta-adapter-cronjob ozg-component: xta-adapter spec: + {{- if (.Values.serviceAccount).create }} + serviceAccountName: {{ include "app.serviceAccountName" . }} + {{- end }} restartPolicy: Never containers: - name: xta-adapter diff --git a/xta-adapter/src/main/helm/test-values.yaml b/xta-adapter/src/main/helm/test-values.yaml index 7b0b2d9b7f9c738856a2780a4cd8921c7cbba530..61f9442209016b78e715a783e0e1f7aa14691a2d 100644 --- a/xta-adapter/src/main/helm/test-values.yaml +++ b/xta-adapter/src/main/helm/test-values.yaml @@ -26,3 +26,7 @@ ozgcloud: environment: test bezeichner: helm bundesland: by + + +networkPolicy: + dnsServerNamespace: test-dns-server-namespace \ No newline at end of file diff --git a/xta-adapter/src/test/helm/cronjob_service_account_test.yaml b/xta-adapter/src/test/helm/cronjob_service_account_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..933e2c64f494bff262c48c680a46df70239662bd --- /dev/null +++ b/xta-adapter/src/test/helm/cronjob_service_account_test.yaml @@ -0,0 +1,52 @@ +# +# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +suite: test cronjob service account +templates: + - templates/xta_adapter_cronjob.yaml +release: + name: xta-adapter + namespace: helm-test +tests: + - it: should use service account with default name + set: + serviceAccount: + create: true + asserts: + - equal: + path: spec.jobTemplate.spec.template.spec.serviceAccountName + value: xta-adapter-service-account + - it: should use service account with name + set: + serviceAccount: + create: true + name: helm-service-account + asserts: + - equal: + path: spec.jobTemplate.spec.template.spec.serviceAccountName + value: helm-service-account + - it: should use default service account + asserts: + - isNull: + path: spec.jobTemplate.spec.template.spec.serviceAccountName diff --git a/xta-adapter/src/test/helm/image_pull_secret_test.yaml b/xta-adapter/src/test/helm/image_pull_secret_test.yaml index 80bffcc068842596343a15aeaa1eff0d52930584..1db60649f5340ec1071f476f0cefb7e8c9344f07 100644 --- a/xta-adapter/src/test/helm/image_pull_secret_test.yaml +++ b/xta-adapter/src/test/helm/image_pull_secret_test.yaml @@ -49,7 +49,7 @@ tests: path: metadata.namespace value: helm-test - isNotEmpty: - path: data.[.dockerconfigjson] + path: data[".dockerconfigjson"] - it: should not create image pull secret set: diff --git a/xta-adapter/src/test/helm/network_policy_test.yaml b/xta-adapter/src/test/helm/network_policy_test.yaml index 92a40e9ea58220536df7b6dc3c7623a2f936c03e..9ef79112e624f12d91d03075677c62a51454b8a9 100644 --- a/xta-adapter/src/test/helm/network_policy_test.yaml +++ b/xta-adapter/src/test/helm/network_policy_test.yaml @@ -27,6 +27,9 @@ release: namespace: by-helm-test templates: - templates/network_policy.yaml +set: + networkPolicy: + dnsServerNamespace: test-dns-namespace tests: - it: should match apiVersion asserts: @@ -64,64 +67,43 @@ tests: - to: - namespaceSelector: matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns + kubernetes.io/metadata.name: test-dns-namespace ports: - port: 53 protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: ssh-port-forward - ports: - - port: 9000 + ports: + - port: 443 + protocol: TCP + - port: 80 protocol: TCP - - it: add ingress rule by values + - it: add egress rules by values set: networkPolicy: + ssoPublicIp: 51.89.117.53/32 + dnsServerNamespace: test-dns-namespace additionalEgressConfig: - - podSelector: - matchLabels: - component: client2 + - to: + - ipBlock: + cidr: 1.2.3.4/32 asserts: - - equal: - path: spec.egress - value: - - to: - - podSelector: - matchLabels: - component: vorgang-manager - ports: - - port: 9090 - protocol: TCP - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns - ports: - - port: 53 - protocol: UDP - - port: 53 - protocol: TCP - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: ssh-port-forward - ports: - - port: 9000 - protocol: TCP - - to: - - podSelector: - matchLabels: - component: client2 + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 1.2.3.4/32 + - it: test network policy disabled set: @@ -135,6 +117,7 @@ tests: set: networkPolicy: disabled: false + dnsServerNamespace: test-dns-namespace asserts: - hasDocuments: count: 1 \ No newline at end of file diff --git a/xta-adapter/src/test/helm/service_account_test.yaml b/xta-adapter/src/test/helm/service_account_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e69fb10ec60f838348d3ab287f6d8eba19db67fb --- /dev/null +++ b/xta-adapter/src/test/helm/service_account_test.yaml @@ -0,0 +1,62 @@ +# +# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +suite: test service account +release: + name: xta-adapter + namespace: sh-helm-test +templates: + - templates/service_account.yaml +tests: + - it: should create service account with default name + set: + serviceAccount: + create: true + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: xta-adapter-service-account + - equal: + path: metadata.namespace + value: sh-helm-test + - it: should create service account with name + set: + serviceAccount: + create: true + name: helm-service-account + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: helm-service-account + - equal: + path: metadata.namespace + value: sh-helm-test + - it: should not create service account + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/xta-adapter/src/test/helm/xta-root-ca-secret-test.yaml b/xta-adapter/src/test/helm/xta-root-ca-secret-test.yaml index 3ca7b4a14f4fc1572956d7ad5768c029b486903c..c3861ba54d4cdbf807cfb5780090080d1290371e 100644 --- a/xta-adapter/src/test/helm/xta-root-ca-secret-test.yaml +++ b/xta-adapter/src/test/helm/xta-root-ca-secret-test.yaml @@ -44,6 +44,6 @@ tests: path: metadata.namespace value: helm-test - equal: - path: data.[ca.crt] + path: data["ca.crt"] value: Z2VoZWltCg== diff --git a/xta-adapter/src/test/helm/xta_adapter_cronjob_dummy_probes_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_dummy_probes_test.yaml index e34455f65790222cf1b174fd0f21b92a4a62418e..0a3ef9a964538609c475ec585b624d12892fc984 100644 --- a/xta-adapter/src/test/helm/xta_adapter_cronjob_dummy_probes_test.yaml +++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_dummy_probes_test.yaml @@ -32,17 +32,17 @@ tests: - it: check dummy livenessProbe default disabled template: xta_adapter_cronjob.yaml asserts: - - isEmpty: + - notExists: path: spec.jobTemplate.spec.template.spec.containers[0].livenessProbe - it: check dummy startupProbe default disabled template: xta_adapter_cronjob.yaml asserts: - - isEmpty: + - notExists: path: spec.jobTemplate.spec.template.spec.containers[0].startupProbe - it: check dummy readynessProbe default disabled template: xta_adapter_cronjob.yaml asserts: - - isEmpty: + - notExists: path: spec.jobTemplate.spec.template.spec.containers[0].readinessProbe - it: check dummy livenessProbe disabled @@ -50,21 +50,21 @@ tests: set: dummyProbesEnabled: false asserts: - - isEmpty: + - notExists: path: spec.jobTemplate.spec.template.spec.containers[0].livenessProbe - it: check dummy startupProbe disabled template: xta_adapter_cronjob.yaml set: dummyProbesEnabled: false asserts: - - isEmpty: + - notExists: path: spec.jobTemplate.spec.template.spec.containers[0].startupProbe - it: check dummy readynessProbe disabled template: xta_adapter_cronjob.yaml set: dummyProbesEnabled: false asserts: - - isEmpty: + - notExists: path: spec.jobTemplate.spec.template.spec.containers[0].readinessProbe