diff --git a/Jenkinsfile b/Jenkinsfile index ec06a286b328e9db37cbb3560af803ce248dce2e..9bb110e4afb5ce6d635a114f7830aa44d82a9536 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -135,7 +135,7 @@ pipeline { HELM_CHART_VERSION = generateHelmChartVersion() dir('src/main/helm') { - sh "helm lint -f test-values.yaml" + sh "helm lint -f ../../test/helm-linter-values.yaml" sh "helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/unit-values.yaml' ." 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 700bdf13443af604fb839c2acd11e8e991ef945d..c473beedb33594307ca3b95fbdad4a1ec709c2c5 100644 --- a/enterprise-adapter/pom.xml +++ b/enterprise-adapter/pom.xml @@ -35,9 +35,7 @@ <name>EM - Enterprise Interface Adapter</name> <properties> - <spring-boot.build-image.imageName> - docker.ozg-sh.de/enterprise-adapter:build-latest - </spring-boot.build-image.imageName> + <spring-boot.build-image.imageName>docker.ozg-sh.de/enterprise-adapter:build-latest</spring-boot.build-image.imageName> </properties> <dependencies> 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 5320f70c635a027707217dfc427b2d5b6372d1ae..28a72c95a2b5c17a1dcf768d0bb51e9e1a8ece6e 100644 --- a/formcycle-adapter/formcycle-adapter-interface/pom.xml +++ b/formcycle-adapter/formcycle-adapter-interface/pom.xml @@ -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/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java b/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java index ce0ebc98e684dc3cac7c5a501ecd24bb16ff8fc5..8a2f3c291eb730fa9a0f93b6291bdd2e15dc9555 100644 --- a/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java +++ b/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java @@ -86,7 +86,7 @@ public class FormsolutionsITCase { } private GrpcCreateVorgangRequest getCreateVorgangRequest() { - verify(blockingStub, timeout(60000)).startCreation(createVorgangRequestCaptor.capture()); + verify(blockingStub, timeout(1000)).startCreation(createVorgangRequestCaptor.capture()); return createVorgangRequestCaptor.getValue(); } } 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 73b148393ff3c0d2ae2329717af68836f4072fb4..61e2d1200e8926055bcf9a0a9910f4ce50ff7965 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ <groupId>de.ozgcloud.eingang</groupId> <artifactId>eingang-manager</artifactId> - <version>2.1.0-</version> + <version>2.2.0-SNAPSHOT</version> <packaging>pom</packaging> <name>OZG-Cloud Eingang Manager</name> diff --git a/run_helm_test.sh b/run_helm_test.sh index 7324e7d118cdd0dd4d8815201c07089ea5122d12..5c2ac8a359d9b3be43e39c05eddf49e36d5f2a2d 100755 --- a/run_helm_test.sh +++ b/run_helm_test.sh @@ -2,6 +2,6 @@ set -e -helm template ./src/main/helm/ -f src/test/unit-values.yaml -helm lint -f src/test/unit-values.yaml ./src/main/helm/ +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 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/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/AfmHeaderTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java index d3705fa4277593df269478566b7f1f221848d59b..28e807688770910087b28d5ec2a228c4f90789dd 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; @@ -58,6 +69,22 @@ public class AfmHeaderTestFactory { map.put(AfmHeaderMapper.FORM_ID, FORM_ID); map.put(AfmHeaderMapper.FORM, FORM); map.put(AfmHeaderMapper.SENDER, SENDER); + map.putAll(createCustomHeaderMap()); + 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; } diff --git a/src/main/helm/README.md b/src/main/helm/README.md index a5f2ffa71abef0d610826b5f699d01e93a530d58..343f5028d591329a068cf876ba38de3dd9b642a5 100644 --- a/src/main/helm/README.md +++ b/src/main/helm/README.md @@ -1,35 +1,93 @@ -# Helm - -## Linter - -`helm lint -f test-values.yaml` - -## Unit-Tests - -Für Unit-Tests wird das helm [helm-unittest](https://github.com/quintush/helm-unittest) plugin benötigt. Die Unit-Tests liegen im Verzeichnis src/test/helm - -`helm unittest -f '../../test/helm/*.yaml' .` - -## SyntaxCheck - -`helm template --debug -f test-values.yaml .` - -## Package - -`helm package --version=[version] .` - -## Versionierung - -Jenkins verwendet die Version aus der pom.xml - -### Master Branch - -Im master Branch werden die ersten 7 Zeichen vom git commit hash an die Version gehangen. - -### Release Branch - -Ist nur die Version aus der pom.xml - -### Feature Branch - -In einem feature Branch wird der Branchname an die Version gehangen. \ No newline at end of file +# Intelliform Adapter + +Adapter zum empfangen von Formulardaten von einem IntellForm basierten Formularserver, zum Beispiel iAFM (integriertes Antrags- und Formularmanagement). + +## Routingkonfiguration + +### Vorgang-Manager Instanzen + +Für alle Vorgang-Manager-Instanzen, die von dem Adapter erreichbar sein sollen, muss in das _Environment_ ein Eintrag mit dem GRPC-Service ergänzt werden: + +```yaml +grpc.client.vorgang-manager-*vorgang-manager-name*.address:*url und port* +grpc.client.vorgang-manager-*vorgang-manager-name*.negotiationType: PLAINTEXT +``` + +### Fallback Strategy + +Die Fallback Stratey steuert wie mit Eingängen umgegangen werden soll, für die keine passende Vorgang-Manager-Instanze gefunden werden konnte. + +Folgende Optionen stehen zur Verfügung: + +- **DENY** der Antrag wird mit einer Fehlermeldung abgelehnt. Dies funktioniert nur, solange die Abarbeitung synchron erfolgt. + +- **FUNDSTELLE** der Antrag wird an eine zentrale Fundstelle weitergeleitet. Dafür muss der Name der Vorgang-Manager-Instanze, die als Fundstelle fungiert, eingetragen werden. + +### Routing Strategy + +Die Routing Strategy steuert wie das Routing konfiguriert wird und wieviele Vorgang-Manager-Instanzen berücksichtigt werden können. + +Folgende Optionen stehen zur Verfügung: + +- **MULTI** es kann an beliebig viele Vorgang-Manager-Instanzen geroutet werden. Dafür muss in der Environment ein Mapping der Organisationseinheit-Id auf den Namen einer Vorgang-Manager-Instanz konfiguriert werden. + +```yaml +ozgcloud.adapter.organisationseinheiten.*id*: *vorgang-manager-name* +``` + +- **SINGLE** es wird immer nur an eine Vorgang-Manager-Instanze geroutet, der Name der Instanz ist im Feld 'Vorgang-Manager Name' anzugeben. + +### Beispielkonfiguration + +```yaml +env: + springProfiles: "oc, dev" + grpc: + - name: grpc_client_vorgang-manager-test_address + value: "vorgang-manager.test:9090" + - name: grpc_client_vorgang-manager-test_negotiationType + value: PLAINTEXT + - name: ozgcloud.adapter.organisationseinheiten.1357913579 + value: test +image: + tag: snapshot-latest +imageCredentials: + email: webmaster@ozg-sh.de + password: + registry: docker.ozg-sh.de + username: ozgcloud +ingress: + host: kiel-afm.dev.by.ozg-cloud.de +replicaCount: 2 +resources: + limits: + cpu: 1 + memory: 1200Mi + requests: + cpu: 100m + memory: 250Mi +global: + cattle: + clusterId: c-8g78g + clusterName: ozg-dev + systemDefaultRegistry: "" + systemDefaultRegistry: "" +routing: + fallbackStrategy: FUNDSTELLE + fundstelleVorgangManagerName: kiel + routingStrategy: MULTI + targetVorgangManagerName: kiel +``` + +### Benutzung beliebiger environment Werte + +In jedem der Projekte kann man beliebige weitere environments setzen. Dazu muss man in der jeweiligen values.yaml unter env.customList ein name value Paar setzen: + +```yaml +env: + customList: + - name: Dinge + value: true + - name: ... + value: ... +``` diff --git a/src/main/helm/app-readme.md b/src/main/helm/app-readme.md deleted file mode 100644 index 343f5028d591329a068cf876ba38de3dd9b642a5..0000000000000000000000000000000000000000 --- a/src/main/helm/app-readme.md +++ /dev/null @@ -1,93 +0,0 @@ -# Intelliform Adapter - -Adapter zum empfangen von Formulardaten von einem IntellForm basierten Formularserver, zum Beispiel iAFM (integriertes Antrags- und Formularmanagement). - -## Routingkonfiguration - -### Vorgang-Manager Instanzen - -Für alle Vorgang-Manager-Instanzen, die von dem Adapter erreichbar sein sollen, muss in das _Environment_ ein Eintrag mit dem GRPC-Service ergänzt werden: - -```yaml -grpc.client.vorgang-manager-*vorgang-manager-name*.address:*url und port* -grpc.client.vorgang-manager-*vorgang-manager-name*.negotiationType: PLAINTEXT -``` - -### Fallback Strategy - -Die Fallback Stratey steuert wie mit Eingängen umgegangen werden soll, für die keine passende Vorgang-Manager-Instanze gefunden werden konnte. - -Folgende Optionen stehen zur Verfügung: - -- **DENY** der Antrag wird mit einer Fehlermeldung abgelehnt. Dies funktioniert nur, solange die Abarbeitung synchron erfolgt. - -- **FUNDSTELLE** der Antrag wird an eine zentrale Fundstelle weitergeleitet. Dafür muss der Name der Vorgang-Manager-Instanze, die als Fundstelle fungiert, eingetragen werden. - -### Routing Strategy - -Die Routing Strategy steuert wie das Routing konfiguriert wird und wieviele Vorgang-Manager-Instanzen berücksichtigt werden können. - -Folgende Optionen stehen zur Verfügung: - -- **MULTI** es kann an beliebig viele Vorgang-Manager-Instanzen geroutet werden. Dafür muss in der Environment ein Mapping der Organisationseinheit-Id auf den Namen einer Vorgang-Manager-Instanz konfiguriert werden. - -```yaml -ozgcloud.adapter.organisationseinheiten.*id*: *vorgang-manager-name* -``` - -- **SINGLE** es wird immer nur an eine Vorgang-Manager-Instanze geroutet, der Name der Instanz ist im Feld 'Vorgang-Manager Name' anzugeben. - -### Beispielkonfiguration - -```yaml -env: - springProfiles: "oc, dev" - grpc: - - name: grpc_client_vorgang-manager-test_address - value: "vorgang-manager.test:9090" - - name: grpc_client_vorgang-manager-test_negotiationType - value: PLAINTEXT - - name: ozgcloud.adapter.organisationseinheiten.1357913579 - value: test -image: - tag: snapshot-latest -imageCredentials: - email: webmaster@ozg-sh.de - password: - registry: docker.ozg-sh.de - username: ozgcloud -ingress: - host: kiel-afm.dev.by.ozg-cloud.de -replicaCount: 2 -resources: - limits: - cpu: 1 - memory: 1200Mi - requests: - cpu: 100m - memory: 250Mi -global: - cattle: - clusterId: c-8g78g - clusterName: ozg-dev - systemDefaultRegistry: "" - systemDefaultRegistry: "" -routing: - fallbackStrategy: FUNDSTELLE - fundstelleVorgangManagerName: kiel - routingStrategy: MULTI - targetVorgangManagerName: kiel -``` - -### Benutzung beliebiger environment Werte - -In jedem der Projekte kann man beliebige weitere environments setzen. Dazu muss man in der jeweiligen values.yaml unter env.customList ein name value Paar setzen: - -```yaml -env: - customList: - - name: Dinge - value: true - - name: ... - value: ... -``` diff --git a/src/main/helm/questions.yml b/src/main/helm/questions.yml deleted file mode 100644 index b8309442a20fed6e3e3db74661d36bc1204c3586..0000000000000000000000000000000000000000 --- a/src/main/helm/questions.yml +++ /dev/null @@ -1,106 +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. -# - -questions: - # --- Container --- - - variable: image.name - type: enum - default: intelliform-adapter - label: The deployed Image - group: Container - required: true - options: - - intelliform-adapter - - formsolutions-adapter - - variable: image.tag - default: latest - type: string - label: The deployed version tag - group: "Container" - - variable: replicaCount - group: "Container" - type: string - default: "2" - label: "Deployment Replica count" - - variable: env.overrideSpringProfiles - group: "Container" - type: string - label: "Override Spring boot profile" - - variable: ozgcloud.bezeichner - group: "OZGCLOUD" - label: "Bezeichner" - type: string - required: true - - variable: ozgcloud.environment - group: "OZGCLOUD" - label: "Environment" - type: string - required: true - - - variable: ingress.enabled - type: boolean - label: Enable ingress - default: true - group: "Ingress" - show_subquestion_if: true - subquestions: - - variable: ingress.overrideHost - type: string - label: Override generated deposit Webservice URL - group: "Ingress" - - - variable: routing.fallbackStrategy - label: Fallback Strategy - group: Routing - type: enum - default: DENY - required: true - options: - - FUNDSTELLE - - DENY - show_subquestion_if: FUNDSTELLE - subquestions: - - variable: routing.fundstelleVorgangManagerName - type: string - label: Fundstelle - required: true - - variable: routing.routingStrategy - label: Routing Strategy - type: enum - default: SINGLE - required: true - group: Routing - options: - - MULTI - - SINGLE - show_subquestion_if: SINGLE - subquestions: - - variable: routing.targetVorgangManagerName - type: string - label: Vorgang-Manager Name - required: true - - variable: routing.targetNamespace - type: string - label: Namespace - required: true diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl index c7dfcd79523309e42ab91563882a39f65e4ecb60..82a7d4757fd619634da2fe4d771717eac04fd1e4 100644 --- a/src/main/helm/templates/_helpers.tpl +++ b/src/main/helm/templates/_helpers.tpl @@ -80,4 +80,18 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }} {{- else }} {{- printf "%s-afm.%s" (include "app.ozgcloudBezeichner" .) .Values.baseUrl }} {{- end }} +{{- end -}} + +{{- define "app.serviceAccountName" -}} +{{- 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/deployment.yaml b/src/main/helm/templates/deployment.yaml index cefff9be956d634f21a76a00f01b9269f24f8d21..b6850b78412c4d2e1327f89f840cafca8b517b9d 100644 --- a/src/main/helm/templates/deployment.yaml +++ b/src/main/helm/templates/deployment.yaml @@ -47,6 +47,9 @@ spec: {{- include "app.defaultLabels" . | indent 8 }} component: afm-adapter spec: + {{- if (.Values.serviceAccount).create }} + serviceAccountName: {{ include "app.serviceAccountName" . }} + {{- end }} topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname @@ -118,7 +121,13 @@ spec: allowPrivilegeEscalation: false privileged: false readOnlyRootFilesystem: false - runAsNonRoot: false + runAsNonRoot: true + {{- with (.Values.securityContext).runAsUser }} + runAsUser: {{ . }} + {{- end }} + {{- with (.Values.securityContext).runAsGroup }} + runAsGroup: {{ . }} + {{- end }} stdin: true terminationMessagePath: /dev/termination-log terminationMessagePolicy: File @@ -126,8 +135,16 @@ spec: dnsConfig: {} dnsPolicy: ClusterFirst imagePullSecrets: + {{- if .Values.imagePullSecret }} + - name: {{ .Values.imagePullSecret }} + {{ else }} - name: {{ include "app.name" . }}-image-pull-secret + {{- end }} restartPolicy: Always + {{- with .Values.hostAliases }} + hostAliases: +{{ toYaml . | indent 8 }} + {{- end }} schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 \ No newline at end of file diff --git a/src/main/helm/templates/image-pull-secret.yaml b/src/main/helm/templates/image-pull-secret.yaml index 17d65b7b75e0ebe440ece0451e78269e94596901..9ac29e90a738d57e16307c8335a60c032134f1c8 100644 --- a/src/main/helm/templates/image-pull-secret.yaml +++ b/src/main/helm/templates/image-pull-secret.yaml @@ -22,6 +22,7 @@ # unter der Lizenz sind dem Lizenztext zu entnehmen. # +{{- if not (.Values.imagePullSecret) }} apiVersion: v1 kind: Secret metadata: @@ -29,4 +30,5 @@ metadata: namespace: {{ include "app.namespace" . }} type: kubernetes.io/dockerconfigjson data: - .dockerconfigjson: {{ include "app.imagePullSecret" . }} \ No newline at end of file + .dockerconfigjson: {{ include "app.imagePullSecret" . }} +{{- end }} \ No newline at end of file diff --git a/src/main/helm/templates/ingress.yaml b/src/main/helm/templates/ingress.yaml index e539e8e0d02d3fed66e97fded23f800b937bdc02..fe85cf3ea82a073c99575ed87a7e56bad6910bf8 100644 --- a/src/main/helm/templates/ingress.yaml +++ b/src/main/helm/templates/ingress.yaml @@ -27,7 +27,11 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: - {{- if (.Values.ingress).use_staging_cert }} + {{- if (.Values.ingress).certManagerAnnotations -}} + {{- range (.Values.ingress).certManagerAnnotations }} +{{ . | indent 4 }} + {{- end }} + {{- else if (.Values.ingress).use_staging_cert }} cert-manager.io/cluster-issuer: letsencrypt-staging {{- else }} cert-manager.io/cluster-issuer: letsencrypt-prod @@ -53,7 +57,9 @@ spec: tls: - hosts: - {{ include "app.ingress.host" . }} - {{- if ne (.Values).cluster_env "dataport" }} + {{- if (.Values.ingress).tlsSecretName }} + secretName: {{ (.Values.ingress).tlsSecretName }} + {{- else if ne (.Values).cluster_env "dataport" }} secretName: {{ .Values.ozgcloud.bezeichner }}-{{ include "app.name" . }}-tls {{- 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 18cf7b2ccffa80585d82fa23789554ff862f3600..929afd7c84be59aa8d39ca31148f72375a2c228b 100644 --- a/src/main/helm/templates/network_policy.yaml +++ b/src/main/helm/templates/network_policy.yaml @@ -49,13 +49,14 @@ 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 {{- end }} \ No newline at end of file diff --git a/src/main/helm/templates/service_account.yaml b/src/main/helm/templates/service_account.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0e13e6bcabf1933117c29487473453b63265922a --- /dev/null +++ b/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/src/main/helm/values.yaml b/src/main/helm/values.yaml index 4a2bd83c1c4eb04af79fbd4b6458eb4dc52a1c9c..240501d36a5cc48d18ae5bc3a324b985f47ca550 100644 --- a/src/main/helm/values.yaml +++ b/src/main/helm/values.yaml @@ -44,12 +44,6 @@ image: # cpu: 100m # [default: 100m] # memory: 250Mi # [default: 250Mi] -imageCredentials: - registry: docker.ozg-sh.de - username: ozgcloud - password: - email: webmaster@ozg-sh.de - ingress: enabled: true # overrideHost: kiel-afm.dev.by.ozg-cloud.de diff --git a/src/main/helm/test-values.yaml b/src/test/helm-linter-values.yaml similarity index 92% rename from src/main/helm/test-values.yaml rename to src/test/helm-linter-values.yaml index e72f46c87bf4c6b6ce3cf960e19effcd09fd53b8..dc7bf7d67561d23925b5ebd3cbac9a491af1ffc8 100644 --- a/src/main/helm/test-values.yaml +++ b/src/test/helm-linter-values.yaml @@ -25,4 +25,7 @@ ozgcloud: environment: test bezeichner: helm - bundesland: sh \ No newline at end of file + bundesland: sh + +networkPolicy: + dnsServerNamespace: test-dns-server-namespace \ No newline at end of file diff --git a/src/test/helm/deployment_container_security_context_test.yaml b/src/test/helm/deployment_container_security_context_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..18a7450337149faf441b8fd520fc4883388f1f6e --- /dev/null +++ b/src/test/helm/deployment_container_security_context_test.yaml @@ -0,0 +1,65 @@ +# +# 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 deployment +release: + name: eingang-manager + namespace: sh-helm-test +templates: + - templates/deployment.yaml +tests: + - it: check default values + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.privileged + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.runAsNonRoot + value: true + - isNull: + path: spec.template.spec.containers[0].securityContext.runAsUser + - isNull: + path: spec.template.spec.containers[0].securityContext.runAsGroup + - it: check runAsUser + set: + securityContext.runAsUser: 1000 + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - it: check runAsGroup + set: + securityContext.runAsGroup: 1000 + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.runAsGroup + value: 1000 \ No newline at end of file diff --git a/src/test/helm/deployment_host_aliases_test.yaml b/src/test/helm/deployment_host_aliases_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..689bf6fd2d5d9eabbb92a6f521397c665bde2f08 --- /dev/null +++ b/src/test/helm/deployment_host_aliases_test.yaml @@ -0,0 +1,50 @@ +# +# 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: deployment host aliases +release: + name: eingang-manager + namespace: sh-helm-test +templates: + - templates/deployment.yaml +tests: + - it: should not set hostAliases + asserts: + - isNull: + path: spec.template.spec.hostAliases + - it: should set hostAliases + set: + hostAliases: + - ip: "127.0.0.1" + hostname: + - "eins" + - "zwei" + asserts: + - contains: + path: spec.template.spec.hostAliases + content: + ip: "127.0.0.1" + hostname: + - "eins" + - "zwei" diff --git a/src/test/helm/deployment_imagepull_secret_test.yaml b/src/test/helm/deployment_imagepull_secret_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2c72debd4fe921192fd925b909f7e6b85c649685 --- /dev/null +++ b/src/test/helm/deployment_imagepull_secret_test.yaml @@ -0,0 +1,47 @@ +# +# 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 deployment +release: + name: afm-adapter + namespace: sh-helm-test +templates: + - templates/deployment.yaml +tests: + - it: should use default imagePull secret + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: afm-adapter-image-pull-secret + - it: should set the imagePull secret + set: + imagePullSecret: image-pull-secret + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: image-pull-secret \ No newline at end of file diff --git a/src/test/helm/deployment_service_account_test.yaml b/src/test/helm/deployment_service_account_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..43aa6fcf59131f1fd9f4e0530a60b14551f89c9b --- /dev/null +++ b/src/test/helm/deployment_service_account_test.yaml @@ -0,0 +1,80 @@ +# +# 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: deployment service account +release: + name: eingang-manager + namespace: sh-helm-test +templates: + - templates/deployment.yaml +tests: + - it: should use afm-adapter service account name + set: + image.name: intelliform-adapter + serviceAccount: + create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + 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: + create: true + name: helm-service-account + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: helm-service-account + - it: should use default service account + asserts: + - isNull: + path: spec.template.spec.serviceAccountName \ No newline at end of file diff --git a/src/test/helm/image-pull-secret-test.yaml b/src/test/helm/image-pull-secret-test.yaml index 423d6268f8fea790bd466277a96f93c9594600a7..c95545170d0e4dd01fce0aab3a1c8953e3e20b5f 100644 --- a/src/test/helm/image-pull-secret-test.yaml +++ b/src/test/helm/image-pull-secret-test.yaml @@ -30,6 +30,12 @@ release: namespace: helm-test tests: - it: should match basic data + set: + imageCredentials: + registry: docker.ozg-sh.de + username: test + password: test1234 + email: webmaster@ozg-sh.de asserts: - containsDocument: kind: Secret @@ -40,3 +46,12 @@ tests: - equal: path: metadata.namespace value: helm-test + - isNotEmpty: + path: data.[.dockerconfigjson] + + - it: should not create image pull secret + set: + imagePullSecret: "image-pull-secret" + asserts: + - hasDocuments: + count: 0 \ 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 96c857eb6260c8ed088cf1a5fb1d70f8fa39c318..1abf7b15ee0077fc1c4811d6b323e709ad83e5a1 100644 --- a/src/test/helm/network_policy_test.yaml +++ b/src/test/helm/network_policy_test.yaml @@ -30,14 +30,23 @@ templates: - templates/network_policy.yaml tests: - it: should match apiVersion + set: + networkPolicy: + dnsServerNamespace: test-dns-namespace asserts: - isAPIVersion: of: networking.k8s.io/v1 - it: should match kind + set: + networkPolicy: + dnsServerNamespace: test-dns-namespace asserts: - isKind: of: NetworkPolicy - it: validate metadata + set: + networkPolicy: + dnsServerNamespace: test-dns-namespace asserts: - equal: path: metadata @@ -45,6 +54,9 @@ tests: name: network-policy-afm-adapter namespace: by-helm-test - it: validate spec + set: + networkPolicy: + dnsServerNamespace: test-dns-namespace asserts: - equal: path: spec @@ -69,20 +81,22 @@ 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 - it: test network policy disabled set: networkPolicy: disabled: true + dnsServerNamespace: test-dns-namespace asserts: - hasDocuments: count: 0 @@ -91,6 +105,7 @@ tests: set: networkPolicy: disabled: false + dnsServerNamespace: test-dns-namespace asserts: - hasDocuments: count: 1 \ No newline at end of file diff --git a/src/test/helm/service_account_test.yaml b/src/test/helm/service_account_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..52561bed188a291f689b81480f02126cd8aed6bc --- /dev/null +++ b/src/test/helm/service_account_test.yaml @@ -0,0 +1,105 @@ +# +# 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: eingang-manager + namespace: sh-helm-test +templates: + - templates/service_account.yaml +tests: + - it: should create default afm adapter service account name + set: + image.name: intelliform-adapter + serviceAccount: + create: true + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + 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 + - 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/src/test/unit-values.yaml b/src/test/unit-values.yaml index fcf2eaf1056c00bb9462330e2229f294201302cf..4c10588096434157f0e0ce39098dfcb134dec497 100644 --- a/src/test/unit-values.yaml +++ b/src/test/unit-values.yaml @@ -36,9 +36,3 @@ image: repo: docker.ozg-sh.de name: intelliform-adapter tag: latest - -imageCredentials: - registry: docker.ozg-sh.de - username: ozgcloud - password: - email: webmaster@ozg-sh.de \ 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/image-pull-secret.yaml b/xta-adapter/src/main/helm/templates/image-pull-secret.yaml index 17d65b7b75e0ebe440ece0451e78269e94596901..9ac29e90a738d57e16307c8335a60c032134f1c8 100644 --- a/xta-adapter/src/main/helm/templates/image-pull-secret.yaml +++ b/xta-adapter/src/main/helm/templates/image-pull-secret.yaml @@ -22,6 +22,7 @@ # unter der Lizenz sind dem Lizenztext zu entnehmen. # +{{- if not (.Values.imagePullSecret) }} apiVersion: v1 kind: Secret metadata: @@ -29,4 +30,5 @@ metadata: namespace: {{ include "app.namespace" . }} type: kubernetes.io/dockerconfigjson data: - .dockerconfigjson: {{ include "app.imagePullSecret" . }} \ No newline at end of file + .dockerconfigjson: {{ include "app.imagePullSecret" . }} +{{- 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..4b42df74f377c19cf12fd6435b4451afb627bf0a 100644 --- a/xta-adapter/src/main/helm/templates/network_policy.yaml +++ b/xta-adapter/src/main/helm/templates/network_policy.yaml @@ -54,6 +54,10 @@ spec: protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - to: - namespaceSelector: matchLabels: 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 61cac8717883a47d52e3992b23de6beb98a18782..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 @@ -99,7 +102,13 @@ spec: allowPrivilegeEscalation: false privileged: false readOnlyRootFilesystem: false - runAsNonRoot: false + runAsNonRoot: true + {{- with (.Values.securityContext).runAsUser }} + runAsUser: {{ . }} + {{- end }} + {{- with (.Values.securityContext).runAsGroup }} + runAsGroup: {{ . }} + {{- end }} resources: {{- with .Values.resources }} {{ toYaml . | indent 16 }} @@ -146,4 +155,8 @@ spec: secret: secretName: xta-keystore imagePullSecrets: - - name: {{ include "app.name" . }}-image-pull-secret \ No newline at end of file + {{- if .Values.imagePullSecret }} + - name: {{ .Values.imagePullSecret }} + {{ else }} + - name: {{ include "app.name" . }}-image-pull-secret + {{- end }} \ No newline at end of file diff --git a/xta-adapter/src/main/helm/values.yaml b/xta-adapter/src/main/helm/values.yaml index 2b3d383c69e987fbfe7c73bb0eded6b2bd109405..b7fd23ad6dcbad154f52411df043403824f33d86 100644 --- a/xta-adapter/src/main/helm/values.yaml +++ b/xta-adapter/src/main/helm/values.yaml @@ -30,12 +30,6 @@ image: # env: # overrideSpringProfiles: "oc,prod" -imageCredentials: - registry: docker.ozg-sh.de - username: ozgcloud - password: - email: webmaster@ozg-sh.de - routing: targetVorgangManagerName: vorgang-manager fallbackStrategy: DENY 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 new file mode 100644 index 0000000000000000000000000000000000000000..80bffcc068842596343a15aeaa1eff0d52930584 --- /dev/null +++ b/xta-adapter/src/test/helm/image_pull_secret_test.yaml @@ -0,0 +1,59 @@ +# +# 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 image pull secret +templates: + - templates/image-pull-secret.yaml +release: + name: xta-adapter + namespace: helm-test +tests: + - it: should match basic data + set: + imageCredentials: + registry: docker.ozg-sh.de + username: test + password: test1234 + email: webmaster@ozg-sh.de + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: Secret + apiVersion: v1 + - equal: + path: metadata.name + value: xta-adapter-image-pull-secret + - equal: + path: metadata.namespace + value: helm-test + - isNotEmpty: + path: data.[.dockerconfigjson] + + - it: should not create image pull secret + set: + imagePullSecret: "image-pull-secret" + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/xta-adapter/src/test/helm/network_policy_test.yaml b/xta-adapter/src/test/helm/network_policy_test.yaml index 92a40e9ea58220536df7b6dc3c7623a2f936c03e..75530cbc1039b70ebef9f3cd20689b739972e430 100644 --- a/xta-adapter/src/test/helm/network_policy_test.yaml +++ b/xta-adapter/src/test/helm/network_policy_test.yaml @@ -73,6 +73,10 @@ tests: protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - to: - namespaceSelector: matchLabels: @@ -111,6 +115,10 @@ tests: protocol: UDP - port: 53 protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - to: - namespaceSelector: matchLabels: 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_adapter_cronjob_basic_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml index 677ce10dc7fb886a0d2484cba11e0517ef8d1639..4667b03c48c34279b76865a0913a69758f745bbf 100644 --- a/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml +++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml @@ -99,8 +99,25 @@ tests: value: false - equal: path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsNonRoot - value: false - + value: true + - isNull: + path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsUser + - isNull: + path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsGroup + - it: check runAsUser + set: + securityContext.runAsUser: 1000 + asserts: + - equal: + path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - it: check runAsGroup + set: + securityContext.runAsGroup: 1000 + asserts: + - equal: + path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsGroup + value: 1000 - it: check pod labels template: xta_adapter_cronjob.yaml asserts: diff --git a/xta-adapter/src/test/helm/xta_adapter_cronjob_image_pull_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_image_pull_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d74e945ac83c43e56c43f2065615719c412c9432 --- /dev/null +++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_image_pull_test.yaml @@ -0,0 +1,43 @@ +# +# 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 xta adapter imagePull secret +release: + name: xta-adapter + namespace: sh-helm-test +templates: + - templates/xta_adapter_cronjob.yaml +tests: + - it: should use default imagePull secret + asserts: + - equal: + path: spec.jobTemplate.spec.template.spec.imagePullSecrets[0].name + value: xta-adapter-image-pull-secret + - it: should set the imagePull secret + set: + imagePullSecret: image-pull-secret + asserts: + - equal: + path: spec.jobTemplate.spec.template.spec.imagePullSecrets[0].name + value: image-pull-secret \ No newline at end of file