diff --git a/lombok.config b/lombok.config index a06fa130e8af26b659f2d3a0cb1114cd966a9b0e..f881e23c3720b1ad363aac0f5c1fe615a66a5d90 100644 --- a/lombok.config +++ b/lombok.config @@ -28,4 +28,5 @@ lombok.log.log4j.flagUsage = ERROR lombok.data.flagUsage = ERROR lombok.nonNull.exceptionType = IllegalArgumentException lombok.addLombokGeneratedAnnotation = true -lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier \ No newline at end of file +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.copyableAnnotations += net.devh.boot.grpc.client.inject.GrpcClient \ No newline at end of file diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml index 4b9faa2ee2b6334bb92d024bcbc0f248abd0ad0b..a5932236210a96e8b671969620f939ad14619ca6 100644 --- a/src/main/helm/templates/deployment.yaml +++ b/src/main/helm/templates/deployment.yaml @@ -163,6 +163,12 @@ spec: - name: grpc_client_zufi-manager_negotiationType value: {{ (.Values.zufiManager).grpcClientNegotiationType | default "PLAINTEXT" }} {{- end}} + {{- if (.Values.forwarding).enabled }} + - name: grpc_client_forwarder_address + value: {{ (.Values.forwarding).address }} + - name: grpc_client_forwarder_negotiationType + value: {{ (.Values.forwarding).grpcClientNegotiationType | default "TLS" }} + {{- end }} {{- if not (.Values.database).useExternal }} - name: spring_data_mongodb_uri valueFrom: diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml index b8750949572c54207885c21dc488aca7fb0b7b58..4e6fb3e0ac202c3f763aa5a23e040a5c53767f9c 100644 --- a/src/main/helm/templates/network_policy.yaml +++ b/src/main/helm/templates/network_policy.yaml @@ -22,7 +22,7 @@ # unter der Lizenz sind dem Lizenztext zu entnehmen. # -{{- if not (.Values.networkPolicy).disabled }} +{{- if not (.Values.networkPolicy).disabled }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -39,10 +39,10 @@ spec: - ports: - port: 9090 from: - - podSelector: + - podSelector: matchLabels: component: alfa - - podSelector: + - podSelector: matchLabels: ozg-component: eingangsadapter - podSelector: @@ -50,7 +50,7 @@ spec: ozg-component: xta-adapter {{- if ((.Values.ozgcloud).aggregationManager).enabled }} - from: - - podSelector: + - podSelector: matchLabels: component: aggregation-manager ports: @@ -69,7 +69,7 @@ spec: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: {{((.Values.ozgcloud).antragraum).antragraumProxyNamespace | default "antragraum-proxy"}} - podSelector: + podSelector: matchLabels: component: antragraum-proxy {{- end }} @@ -87,7 +87,7 @@ spec: - xta-adapter ports: - protocol: TCP - port: 9090 + port: 9090 {{- with (.Values.networkPolicy).additionalIngressConfigLocal }} {{ toYaml . | indent 2 }} @@ -114,7 +114,7 @@ spec: - port: 27017 protocol: TCP - to: - - podSelector: + - podSelector: matchLabels: component: user-manager ports: @@ -122,7 +122,7 @@ spec: protocol: TCP {{- if ((.Values.ozgcloud).bayernid).enabled }} - to: - - podSelector: + - podSelector: matchLabels: component: bayernid-proxy namespaceSelector: @@ -130,14 +130,14 @@ spec: kubernetes.io/metadata.name: {{ required "ozgcloud.bayernid.proxy.namespace must be set if bayernid is enabled" (((.Values.ozgcloud).bayernid).proxy).namespace }} ports: - port: 9090 - protocol: TCP + protocol: TCP {{- end }} {{- if ((.Values.ozgcloud).antragraum).enabled }} - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: {{((.Values.ozgcloud).infoManager).namespace | default "info-manager"}} - podSelector: + podSelector: matchLabels: component: info-manager {{- end }} @@ -146,13 +146,25 @@ spec: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: {{ required "zufiManager.namespace must be set if zufiManager server is enabled" (.Values.zufiManager).namespace }} - podSelector: + podSelector: matchLabels: component: zufi-server ports: - port: 9090 protocol: TCP {{- end }} +{{- if (.Values.forwarding).enabled }} + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ required "forwarding.namespace must be set if forwarding is enabled" (.Values.forwarding).namespace }} + podSelector: + matchLabels: + component: {{ required "forwarding.serviceName must be set if forwarding is enabled" (.Values.forwarding).serviceName }} + ports: + - port: 9090 + protocol: TCP +{{- end }} {{- if ((.Values.ozgcloud).muk).enabled }} - to: - podSelector: diff --git a/src/test/helm/deployment_forwarder_env_test.yaml b/src/test/helm/deployment_forwarder_env_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fd7a77f810286abfaef04c28e5aa0c6f35abbc0c --- /dev/null +++ b/src/test/helm/deployment_forwarder_env_test.yaml @@ -0,0 +1,81 @@ +# +# Copyright (C) 2024 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 forwarder environment +release: + name: vorgang-manager + namespace: by-helm-test +templates: + - templates/deployment.yaml +set: + baseUrl: test.sh.ozg-cloud.de + ozgcloud: + environment: dev + bezeichner: helm + imagePullSecret: test-image-pull-secret +tests: + - it: should be disabled by default + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_forwarder_address + any: true + - notContains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_forwarder_negotiationType + any: true + - it: should set the grpc forwarder client address + set: + forwarding: + enabled: true + address: https://forwarder.my-wonderful-domain.local:9000 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_forwarder_address + value: https://forwarder.my-wonderful-domain.local:9000 + - it: should set the default negotiation type + set: + forwarding: + enabled: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_forwarder_negotiationType + value: TLS + - it: should set the negotiation type + set: + forwarding: + enabled: true + grpcClientNegotiationType: PLAINTEXT + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: grpc_client_forwarder_negotiationType + value: PLAINTEXT \ 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 17c7a47611643bec68e2d54f90ccfbc74b4954be..fff3066c0175266c277e88c895455d1548f13f89 100644 --- a/src/test/helm/network_policy_test.yaml +++ b/src/test/helm/network_policy_test.yaml @@ -30,7 +30,7 @@ templates: tests: - it: should match apiVersion - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: @@ -38,7 +38,7 @@ tests: of: networking.k8s.io/v1 - it: should match kind - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: @@ -46,7 +46,7 @@ tests: of: NetworkPolicy - it: validate metadata - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: @@ -57,7 +57,7 @@ tests: namespace: by-helm-test - it: should set policy target matchLabel - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: @@ -67,9 +67,8 @@ tests: matchLabels: component: vorgang-manager - - it: should add policyType Egress - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: @@ -78,7 +77,7 @@ tests: content: Egress - it: should add policyType Ingress - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: @@ -87,44 +86,44 @@ tests: content: Ingress - it: should add ingress rule for eingangsmanager and alfa - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: - contains: path: spec.ingress content: - ports: + ports: - port: 9090 - from: - - podSelector: + from: + - podSelector: matchLabels: component: alfa - - podSelector: + - podSelector: matchLabels: ozg-component: eingangsadapter - podSelector: - matchLabels: - ozg-component: xta-adapter + matchLabels: + ozg-component: xta-adapter - it: should add ingress rule for monitoring scraper - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: - contains: path: spec.ingress content: - ports: + ports: - port: 8081 protocol: TCP - from: - - namespaceSelector: + from: + - namespaceSelector: matchLabels: name: openshift-user-workload-monitoring - it: should set monitoring namespace for monitoring scraper ingress rule - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace monitoringNamespace: test-monitoring @@ -132,11 +131,11 @@ tests: - contains: path: spec.ingress content: - ports: + ports: - port: 8081 protocol: TCP - from: - - namespaceSelector: + from: + - namespaceSelector: matchLabels: name: test-monitoring @@ -148,16 +147,16 @@ tests: antragraum: enabled: true asserts: - - contains: - path: spec.ingress - content: - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: antragraum-proxy - podSelector: - matchLabels: - component: antragraum-proxy + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: antragraum-proxy + podSelector: + matchLabels: + component: antragraum-proxy - it: should set ingress rule for antragraum-proxy if antragraum is enabled set: @@ -168,17 +167,16 @@ tests: enabled: true antragraumProxyNamespace: antragraum-proxy asserts: - - contains: - path: spec.ingress - content: - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: antragraum-proxy - podSelector: - matchLabels: - component: antragraum-proxy - + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: antragraum-proxy + podSelector: + matchLabels: + component: antragraum-proxy - it: should not add ingress rule for antragraum if antragraum is disabled set: @@ -188,16 +186,16 @@ tests: antragraum: enabled: false asserts: - - notContains: - path: spec.ingress - content: - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: antragraum - podSelector: - matchLabels: - component: antragraum-server + - notContains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: antragraum + podSelector: + matchLabels: + component: antragraum-server - it: should not add ingress rule for antragraum-proxy if antragraum is disabled set: @@ -207,40 +205,40 @@ tests: antragraum: enabled: false asserts: - - notContains: - path: spec.ingress - content: - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: antragraum-proxy - podSelector: - matchLabels: - component: antragraum-proxy - any: true + - notContains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: antragraum-proxy + podSelector: + matchLabels: + component: antragraum-proxy + any: true - it: should add default ingress rule for zentraler-eingang set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: - - contains: - path: spec.ingress - content: - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: zentraler-eingang - podSelector: - matchExpressions: - - key: ozg-component - operator: In - values: - - eingangsadapter - - xta-adapter - ports: - - protocol: TCP - port: 9090 + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: zentraler-eingang + podSelector: + matchExpressions: + - key: ozg-component + operator: In + values: + - eingangsadapter + - xta-adapter + ports: + - protocol: TCP + port: 9090 - it: should add ingress rule for zentraler-eingang set: @@ -248,24 +246,23 @@ tests: dnsServerNamespace: test-dns-namespace zentralerEingangNamespace: custom-namespace asserts: - - contains: - path: spec.ingress - content: - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: custom-namespace - podSelector: - matchExpressions: - - key: ozg-component - operator: In - values: - - eingangsadapter - - xta-adapter - ports: - - protocol: TCP - port: 9090 - + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: custom-namespace + podSelector: + matchExpressions: + - key: ozg-component + operator: In + values: + - eingangsadapter + - xta-adapter + ports: + - protocol: TCP + port: 9090 - it: should add egress rule to elasticsearch set: @@ -275,16 +272,16 @@ tests: - contains: path: spec.egress content: - to: + to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: elastic-system podSelector: matchLabels: - elasticsearch.k8s.elastic.co/cluster-name : ozg-search-cluster - ports: - - port: 9200 - protocol: TCP + elasticsearch.k8s.elastic.co/cluster-name: ozg-search-cluster + ports: + - port: 9200 + protocol: TCP - it: should add egress rule to mongodb set: @@ -294,13 +291,13 @@ tests: - contains: path: spec.egress content: - to: + to: - podSelector: matchLabels: component: ozgcloud-mongodb - ports: - - port: 27017 - protocol: TCP + ports: + - port: 27017 + protocol: TCP - it: should add egress rule to user-manager set: @@ -310,13 +307,13 @@ tests: - contains: path: spec.egress content: - to: - - podSelector: + to: + - podSelector: matchLabels: component: user-manager - ports: - - port: 9000 - protocol: TCP + ports: + - port: 9000 + protocol: TCP - it: should add egress rule to nachrichten-bayernid-proxy if bayernid is enabled set: @@ -332,15 +329,15 @@ tests: path: spec.egress content: to: - - podSelector: - matchLabels: - component: bayernid-proxy - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: bayernidProxyNamespace + - podSelector: + matchLabels: + component: bayernid-proxy + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: bayernidProxyNamespace ports: - - port: 9090 - protocol: TCP + - port: 9090 + protocol: TCP - it: should not add egress rule to bayernid-proxy if bayernid is disabled set: @@ -354,16 +351,16 @@ tests: path: spec.egress content: to: - - podSelector: - matchLabels: - component: bayernid-proxy - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: bayernidProxyNamespace + - podSelector: + matchLabels: + component: bayernid-proxy + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: bayernidProxyNamespace ports: - - port: 9090 - protocol: TCP - + - port: 9090 + protocol: TCP + - it: should throw error if bayernid-proxy is enabled but bayernid namespace is not set set: networkPolicy: @@ -390,7 +387,7 @@ tests: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: info-manager - podSelector: + podSelector: matchLabels: component: info-manager @@ -411,7 +408,7 @@ tests: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: info-manager2 - podSelector: + podSelector: matchLabels: component: info-manager @@ -430,7 +427,7 @@ tests: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: info-manager - podSelector: + podSelector: matchLabels: component: info-manager @@ -446,16 +443,15 @@ tests: path: spec.egress content: to: - - podSelector: - matchLabels: - component: zufi-server - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: zufi + - podSelector: + matchLabels: + component: zufi-server + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: zufi ports: - - port: 9090 - protocol: TCP - + - port: 9090 + protocol: TCP - it: should not add egress rule to zufi server if zufi is disabled set: @@ -469,14 +465,58 @@ tests: path: spec.egress content: to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: zufi - podSelector: - matchLabels: - component: zufi-server + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: zufi + podSelector: + matchLabels: + component: zufi-server + any: true + + - it: should add egress rule to forwarding service if forwarding is enabled + set: + networkPolicy: + dnsServerNamespace: test-dns-namespace + forwarding: + enabled: true + namespace: zentraler-eingang + serviceName: fs-adapter + asserts: + - contains: + path: spec.egress + content: + to: + - podSelector: + matchLabels: + component: fs-adapter + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: zentraler-eingang + ports: + - port: 9090 + protocol: TCP + + - it: should not add egress rule to forwarding service if forwarding is disabled + set: + networkPolicy: + dnsServerNamespace: test-dns-namespace + forwarding: + enabled: false + namespace: zentraler-eingang + serviceName: fs-adapter + asserts: + - notContains: + path: spec.egress + content: + to: + - podSelector: + matchLabels: + component: fs-adapter + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: zentraler-eingang any: true - + - it: should throw error if zufi is enabled but zufi namespace is not set set: networkPolicy: @@ -496,17 +536,16 @@ tests: asserts: - notContains: path: spec.egress - content: + content: to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: zufi - podSelector: - matchLabels: - component: zufi-server + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: zufi + podSelector: + matchLabels: + component: zufi-server any: true - - it: should add egress rule to dns service set: networkPolicy: @@ -515,19 +554,19 @@ tests: - contains: path: spec.egress content: - to: + to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: test-dns-namespace - ports: - - port: 53 - protocol: UDP - - port: 53 - protocol: TCP - - port: 5353 - protocol: UDP - - port: 5353 - protocol: TCP + ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP - it: add ingress rule local by values set: @@ -535,89 +574,89 @@ tests: dnsServerNamespace: test-dns-namespace ssoPublicIp: 51.89.117.53/32 additionalIngressConfigGlobal: - - from: - - podSelector: - matchLabels: - component: client2 + - from: + - podSelector: + matchLabels: + component: client2 asserts: - contains: path: spec.ingress content: from: - - podSelector: - matchLabels: - component: client2 + - podSelector: + matchLabels: + component: client2 - it: add ingress rule global by values set: networkPolicy: dnsServerNamespace: test-dns-namespace ssoPublicIp: 51.89.117.53/32 additionalIngressConfigLocal: - - from: - - podSelector: - matchLabels: - component: client2 + - from: + - podSelector: + matchLabels: + component: client2 asserts: - contains: path: spec.ingress content: from: - - podSelector: - matchLabels: - component: client2 + - podSelector: + matchLabels: + component: client2 - it: add egress rules local by values set: networkPolicy: dnsServerNamespace: test-dns-namespace additionalEgressConfigGlobal: - - to: - - ipBlock: - cidr: 1.2.3.4/32 - - to: - - podSelector: - matchLabels: - component: ozg-testservice - ports: - - port: 12345 - protocol: TCP - asserts: - - contains: - path: spec.egress - content: - to: - - ipBlock: - cidr: 1.2.3.4/32 - - contains: - path: spec.egress - content: - to: - - podSelector: - matchLabels: - component: ozg-testservice - ports: - - port: 12345 - protocol: TCP + - to: + - ipBlock: + cidr: 1.2.3.4/32 + - to: + - podSelector: + matchLabels: + component: ozg-testservice + ports: + - port: 12345 + protocol: TCP + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 1.2.3.4/32 + - contains: + path: spec.egress + content: + to: + - podSelector: + matchLabels: + component: ozg-testservice + ports: + - port: 12345 + protocol: TCP - it: add egress rules global by values set: networkPolicy: dnsServerNamespace: test-dns-namespace additionalEgressConfigLocal: - - to: - - ipBlock: - cidr: 1.2.3.4/32 - - to: - - podSelector: - matchLabels: - additionalEgressConfigLocal: yes - asserts: - - contains: - path: spec.egress - content: - to: - - podSelector: - matchLabels: - additionalEgressConfigLocal: yes + - to: + - ipBlock: + cidr: 1.2.3.4/32 + - to: + - podSelector: + matchLabels: + additionalEgressConfigLocal: yes + asserts: + - contains: + path: spec.egress + content: + to: + - podSelector: + matchLabels: + additionalEgressConfigLocal: yes - it: test network policy disabled set: @@ -676,15 +715,15 @@ tests: path: spec.egress content: to: - - podSelector: - matchLabels: - app.kubernetes.io/name: elster-transfer - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: elster-transfer + - podSelector: + matchLabels: + app.kubernetes.io/name: elster-transfer + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: elster-transfer ports: - - port: 8081 - protocol: TCP + - port: 8081 + protocol: TCP - it: should set elster transfer name set: @@ -701,15 +740,15 @@ tests: path: spec.egress content: to: - - podSelector: - matchLabels: - app.kubernetes.io/name: elster-transfer-test - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: elster-transfer + - podSelector: + matchLabels: + app.kubernetes.io/name: elster-transfer-test + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: elster-transfer ports: - - port: 8081 - protocol: TCP + - port: 8081 + protocol: TCP - it: should not add egress rule for elster-transfer if muk is disabled set: @@ -725,15 +764,15 @@ tests: path: spec.egress content: to: - - podSelector: - matchLabels: - app.kubernetes.io/name: elster-transfer - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: elster-transfer + - podSelector: + matchLabels: + app.kubernetes.io/name: elster-transfer + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: elster-transfer any: true - it: should add ingress rule for aggregation-manager - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace ozgcloud: @@ -743,26 +782,26 @@ tests: - contains: path: spec.ingress content: - ports: + ports: - port: 9090 protocol: TCP - from: - - podSelector: + from: + - podSelector: matchLabels: component: aggregation-manager - it: should not add ingress rule for aggregation-manager - set: + set: networkPolicy: dnsServerNamespace: test-dns-namespace asserts: - notContains: path: spec.ingress content: - ports: + ports: - port: 9090 protocol: TCP - from: - - podSelector: + from: + - podSelector: matchLabels: component: aggregation-manager diff --git a/vorgang-manager-server/pom.xml b/vorgang-manager-server/pom.xml index d265423e02a345b4608f2ede9fda8f9978aa95e0..a21b718ba3809dccf567d3bd9559f0abf7bd745e 100644 --- a/vorgang-manager-server/pom.xml +++ b/vorgang-manager-server/pom.xml @@ -32,7 +32,7 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.11.0</version> + <version>4.12.0-OZG-7573-GrpcUpload-utils-SNAPSHOT</version> <relativePath /> </parent> @@ -51,7 +51,7 @@ <spring-boot.build-image.imageName>docker.ozg-sh.de/vorgang-manager:build-latest</spring-boot.build-image.imageName> <zufi-manager-interface.version>1.6.0</zufi-manager-interface.version> - + <common-lib.version>4.12.0-SNAPSHOT</common-lib.version> <user-manager-interface.version>2.12.0</user-manager-interface.version> <processor-manager.version>0.5.0</processor-manager.version> <nachrichten-manager.version>2.19.0-SNAPSHOT</nachrichten-manager.version> @@ -60,6 +60,7 @@ <collaboration-manager.version>0.7.0</collaboration-manager.version> <archive-manager.version>0.3.0</archive-manager.version> <document-manager.version>1.2.0</document-manager.version> + <eingang-manager-interface.version>2.19.0-SNAPSHOT</eingang-manager-interface.version> <zip.version>2.11.5</zip.version> <jsoup.version>1.15.3</jsoup.version> @@ -81,6 +82,11 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>de.ozgcloud.common</groupId> + <artifactId>ozgcloud-common-lib</artifactId> + <version>${common-lib.version}</version> + </dependency> <dependency> <groupId>de.ozgcloud.nachrichten</groupId> <artifactId>nachrichten-manager-server</artifactId> @@ -171,6 +177,11 @@ <artifactId>api-lib-core</artifactId> <version>${api-lib.version}</version> </dependency> + <dependency> + <groupId>de.ozgcloud.eingang</groupId> + <artifactId>eingang-manager-interface</artifactId> + <version>${eingang-manager-interface.version}</version> + </dependency> <!-- Spring --> <dependency> @@ -396,7 +407,8 @@ <env> <BPE_DELIM_JAVA_TOOL_OPTIONS xml:space="preserve"> </BPE_DELIM_JAVA_TOOL_OPTIONS> <BPE_APPEND_JAVA_TOOL_OPTIONS>-Dfile.encoding=UTF-8</BPE_APPEND_JAVA_TOOL_OPTIONS> - <BPE_APPEND_JAVA_TOOL_OPTIONS>-Dio.grpc.netty.shaded.io.netty.maxDirectMemory=0</BPE_APPEND_JAVA_TOOL_OPTIONS> + <BPE_APPEND_JAVA_TOOL_OPTIONS> + -Dio.grpc.netty.shaded.io.netty.maxDirectMemory=0</BPE_APPEND_JAVA_TOOL_OPTIONS> <BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:MaxDirectMemorySize=512m</BPE_APPEND_JAVA_TOOL_OPTIONS> <BPE_APPEND_LC_ALL>en_US.UTF-8</BPE_APPEND_LC_ALL> </env> diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/EingangMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/EingangMapper.java index f072e0ec6d69a38eba82bad30737494c3c465095..0c5dcaafc4d2791f2855df3ee0611a9c7707f0da 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/EingangMapper.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/EingangMapper.java @@ -36,7 +36,7 @@ import de.ozgcloud.vorgang.common.grpc.GrpcFormDataMapper; nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, // nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, // collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -interface EingangMapper { +public interface EingangMapper { @Mapping(source = "attachmentsList", target = "attachments") @Mapping(source = "representationsList", target = "representations") diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapper.java index aefc6d34ed1a5bc24bb6e1c2e3f48062b61da4e1..1170b27d77f0e96d07a6c91447a5e971dbf4de3f 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapper.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapper.java @@ -24,9 +24,12 @@ package de.ozgcloud.vorgang.vorgang; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import com.google.protobuf.ByteString; +import de.ozgcloud.eingang.forwarding.GrpcAttachmentFile; +import de.ozgcloud.eingang.forwarding.GrpcRepresentationFile; import de.ozgcloud.vorgang.files.FileIdMapper; @Mapper(uses = FileIdMapper.class) @@ -37,4 +40,29 @@ public interface IncomingFileMapper { default byte[] map(ByteString value) { return value.toByteArray(); } + + @Mapping(target = "mergeFrom", ignore = true) + @Mapping(target = "clearField", ignore = true) + @Mapping(target = "clearOneof", ignore = true) + @Mapping(target = "mergeUnknownFields", ignore = true) + @Mapping(target = "contentTypeBytes", ignore = true) + @Mapping(target = "fileNameBytes", ignore = true) + @Mapping(target = "groupNameBytes", ignore = true) + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "vendorIdBytes", ignore = true) + @Mapping(target = "allFields", ignore = true) + @Mapping(target = "fileName", source = "file.name") + GrpcAttachmentFile toAttachmentFile(String groupName, IncomingFile file); + + @Mapping(target = "mergeFrom", ignore = true) + @Mapping(target = "clearField", ignore = true) + @Mapping(target = "clearOneof", ignore = true) + @Mapping(target = "mergeUnknownFields", ignore = true) + @Mapping(target = "contentTypeBytes", ignore = true) + @Mapping(target = "fileNameBytes", ignore = true) + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "vendorIdBytes", ignore = true) + @Mapping(target = "allFields", ignore = true) + @Mapping(target = "fileName", source = "name") + GrpcRepresentationFile toRepresentationFile(IncomingFile file); } \ No newline at end of file diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java new file mode 100644 index 0000000000000000000000000000000000000000..63323fb8ecb106b710574deed664efbc70c3be1f --- /dev/null +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import java.io.InputStream; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.springframework.stereotype.Service; + +import com.google.protobuf.ByteString; + +import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils; +import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender; +import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.eingang.forwarder.RouteForwardingServiceGrpc; +import de.ozgcloud.eingang.forwarding.GrpcAttachment; +import de.ozgcloud.eingang.forwarding.GrpcFileContent; +import de.ozgcloud.eingang.forwarding.GrpcRepresentation; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingResponse; +import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor; +import de.ozgcloud.vorgang.files.FileService; +import de.ozgcloud.vorgang.vorgang.Eingang; +import de.ozgcloud.vorgang.vorgang.IncomingFile; +import de.ozgcloud.vorgang.vorgang.IncomingFileGroup; +import de.ozgcloud.vorgang.vorgang.IncomingFileMapper; +import de.ozgcloud.vorgang.vorgang.VorgangService; +import io.grpc.stub.CallStreamObserver; +import io.grpc.stub.StreamObserver; +import lombok.RequiredArgsConstructor; +import net.devh.boot.grpc.client.inject.GrpcClient; + +@Service +@RequiredArgsConstructor +class ForwardingRemoteService { + + private static final int TIMEOUT_MINUTES = 2; + private final VorgangService vorgangService; + private final ForwardingRequestMapper forwardingRequestMapper; + @GrpcClient("forwarder") + private final RouteForwardingServiceGrpc.RouteForwardingServiceStub serviceStub; + private final FileService fileService; + private final IncomingFileMapper incomingFileMapper; + + public void forward(ForwardingRequest request) { + CompletableFuture<Void> responseFuture = new CompletableFuture<>(); + routeForwarding(request, new ForwardingResponseObserver(responseFuture)); + waitForCompletion(responseFuture); + } + + void routeForwarding(ForwardingRequest request, ForwardingResponseObserver responseObserver) { + var requestStreamObserver = serviceStub.withInterceptors(new VorgangManagerClientCallContextAttachingInterceptor()) + .routeForwarding(responseObserver); + try { + sendEingang(request, requestStreamObserver); + requestStreamObserver.onCompleted(); + } catch (Exception e) { + requestStreamObserver.onError(e); + throw e; + } + } + + void sendEingang(ForwardingRequest request, StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { + var eingang = vorgangService.getById(request.getVorgangId()).getEingangs().getFirst(); + requestStreamObserver.onNext(buildRouteForwardingRequest(request, eingang)); + sendAttachments(eingang.getAttachments(), requestStreamObserver); + sendRepresentations(eingang.getRepresentations(), requestStreamObserver); + } + + GrpcRouteForwardingRequest buildRouteForwardingRequest(ForwardingRequest request, Eingang eingang) { + var routeForwarding = forwardingRequestMapper.toGrpcRouteForwarding(request, eingang); + return GrpcRouteForwardingRequest.newBuilder().setRouteForwarding(routeForwarding).build(); + } + + void sendAttachments(List<IncomingFileGroup> attachments, StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { + for (var attachment : attachments) { + var groupName = attachment.getName(); + attachment.getFiles().forEach(file -> sendAttachmentFile(requestStreamObserver, groupName, file)); + } + } + + private void sendAttachmentFile(StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, String groupName, IncomingFile file) { + var fileContentStream = fileService.getUploadedFileStream(file.getId()); + createAttachmentFileSender(requestStreamObserver, groupName, file, fileContentStream).send(); + } + + FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createAttachmentFileSender( + StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, String groupName, IncomingFile file, InputStream fileContentStream) { + return createSenderWithoutMetadata(this::buildAttachmentChunk, requestStreamObserver, fileContentStream) + .withMetaData(buildGrpcAttachmentFile(groupName, file)); + } + + GrpcRouteForwardingRequest buildAttachmentChunk(byte[] chunk, int length) { + return GrpcRouteForwardingRequest.newBuilder() + .setAttachment(GrpcAttachment.newBuilder() + .setContent(buildGrpcFileContent(chunk, length)) + .build()) + .build(); + } + + GrpcRouteForwardingRequest buildGrpcAttachmentFile(String name, IncomingFile file) { + return GrpcRouteForwardingRequest.newBuilder() + .setAttachment(GrpcAttachment.newBuilder() + .setFile(incomingFileMapper.toAttachmentFile(name, file)) + .build()) + .build(); + } + + void sendRepresentations(List<IncomingFile> representations, StreamObserver<GrpcRouteForwardingRequest> requestObserver) { + representations.forEach(representation -> { + var fileContentStream = fileService.getUploadedFileStream(representation.getId()); + createRepresentationFileSender(requestObserver, representation, fileContentStream).send(); + }); + } + + FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createRepresentationFileSender( + StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, IncomingFile file, InputStream fileContentStream) { + return createSenderWithoutMetadata(this::buildRepresentationChunk, requestStreamObserver, fileContentStream) + .withMetaData(buildGrpcRepresentationFile(file)); + } + + FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createSenderWithoutMetadata( + BiFunction<byte[], Integer, GrpcRouteForwardingRequest> chunkBuilder, + StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, InputStream fileContentStream) { + return GrpcFileUploadUtils + .createSender(chunkBuilder, fileContentStream, requestCallStreamObserverProvider(requestStreamObserver), false); + } + + private Function<StreamObserver<GrpcRouteForwardingResponse>, CallStreamObserver<GrpcRouteForwardingRequest>> requestCallStreamObserverProvider( + StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { + return response -> (CallStreamObserver<GrpcRouteForwardingRequest>) requestStreamObserver; + } + + GrpcRouteForwardingRequest buildRepresentationChunk(byte[] chunk, int length) { + return GrpcRouteForwardingRequest.newBuilder() + .setRepresentation(GrpcRepresentation.newBuilder() + .setContent(buildGrpcFileContent(chunk, length)) + .build()) + .build(); + } + + GrpcFileContent buildGrpcFileContent(byte[] chunk, int length) { + var fileContentBuilder = GrpcFileContent.newBuilder(); + if (length <= 0) { + fileContentBuilder.setIsEndOfFile(true); + } else { + fileContentBuilder.setContent(ByteString.copyFrom(chunk)); + } + return fileContentBuilder.build(); + } + + GrpcRouteForwardingRequest buildGrpcRepresentationFile(IncomingFile file) { + return GrpcRouteForwardingRequest.newBuilder() + .setRepresentation(GrpcRepresentation.newBuilder() + .setFile(incomingFileMapper.toRepresentationFile(file)) + .build()) + .build(); + } + + void waitForCompletion(CompletableFuture<Void> responseFuture) { + try { + responseFuture.get(TIMEOUT_MINUTES, TimeUnit.MINUTES); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new TechnicalException("Waiting for finishing file upload was interrupted.", e); + } catch (ExecutionException e) { + throw new TechnicalException("Error on uploading file content.", e); + } catch (TimeoutException e) { + throw new TechnicalException("Timeout on uploading file content.", e); + } + } + + @RequiredArgsConstructor + static class ForwardingResponseObserver implements StreamObserver<GrpcRouteForwardingResponse> { + private final CompletableFuture<Void> future; + + @Override + public void onNext(GrpcRouteForwardingResponse value) { + // noop + } + + @Override + public void onError(Throwable t) { + future.completeExceptionally(t); + } + + @Override + public void onCompleted() { + future.complete(null); + } + } +} diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java index e47ae180e85e18dc7466278b994f02f1886ce28b..2e32110106d1b8b4a0a39e6fd3506768152fbf95 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java @@ -26,12 +26,24 @@ package de.ozgcloud.vorgang.vorgang.redirect; import java.util.Map; import org.apache.commons.collections4.MapUtils; +import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.NullValuePropertyMappingStrategy; import de.ozgcloud.command.Command; +import de.ozgcloud.eingang.forwarding.GrpcEingangStub; +import de.ozgcloud.eingang.forwarding.GrpcRouteCriteria; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwarding; +import de.ozgcloud.vorgang.vorgang.Eingang; +import de.ozgcloud.vorgang.vorgang.EingangMapper; +import de.ozgcloud.vorgang.vorgang.GrpcEingang; -@Mapper(imports = MapUtils.class) +@Mapper(imports = MapUtils.class, uses = EingangMapper.class, // + nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, // + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, // + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) interface ForwardingRequestMapper { interface CommandBodyFields { @@ -42,7 +54,7 @@ interface ForwardingRequestMapper { String PLZ = "plz"; String ORT = "ort"; } - + @Mapping(target = "version", source = "relationVersion") @Mapping(target = "organisationEinheit", source = "bodyObject") ForwardingRequest fromCommand(Command command); @@ -57,4 +69,17 @@ interface ForwardingRequestMapper { @Mapping(target = "zipCode", expression = "java(MapUtils.getString(body, CommandBodyFields.PLZ))") @Mapping(target = "city", expression = "java(MapUtils.getString(body, CommandBodyFields.ORT))") Address toAddress(Map<String, Object> body); + + @Mapping(target = "routeCriteria", source = "request") + @Mapping(target = "eingangStub", source = "eingang") + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "allFields", ignore = true) + GrpcRouteForwarding toGrpcRouteForwarding(ForwardingRequest request, Eingang eingang); + + @Mapping(target = "organisationEinheitId", source = "organisationEinheit.id") + GrpcRouteCriteria toGrpcRouteCriteria(ForwardingRequest request); + + @Mapping(target = "unknownFields", ignore = true) + @Mapping(target = "allFields", ignore = true) + GrpcEingangStub toGrpcEingangStub(GrpcEingang eingang); } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java index ed26c9e9850a1361531b70b36699b5ca92c08596..6af4a3cd03f5a786e9951d30683af55e3fd53962 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java @@ -35,7 +35,6 @@ import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -56,10 +55,12 @@ import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import jakarta.mail.util.ByteArrayDataSource; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Service @Log4j2 +@RequiredArgsConstructor public class ForwardingService { static final String MAIL_TEMPLATE = "/mail/redirect.txt.ftlh"; @@ -87,26 +88,15 @@ public class ForwardingService { static final String SUBJECT_BESTAETIGUNG_TEMPL = "Ihr Antrag auf %s - Az: %s"; static final String ZIP_FILENAME_TMPL = "%s.zip"; - @Autowired - private ForwardingRepository repository; - - @Autowired - private Configuration freemarkerCfg; - @Autowired - private ZipBuilderService zipService; - - @Autowired - private MailService emailService; - - @Autowired - private VorgangService vorgangService; - + private final ForwardingRepository repository; + private final Configuration freemarkerCfg; + private final ZipBuilderService zipService; + private final MailService emailService; + private final VorgangService vorgangService; // TODO abhängigkeit entfernen - @Autowired - private StatusService statusService; - - @Autowired - private ApplicationEventPublisher publisher; + private final StatusService statusService; + private final ForwardingRemoteService forwardingRemoteService; + private final ApplicationEventPublisher publisher; @Value("${ozgcloud.redirect.mail-from}") private String mailFrom; @@ -332,5 +322,6 @@ public class ForwardingService { public void forward(ForwardingRequest request) { statusService.setStatusToWeitergeleitet(request.getVorgangId(), request.getVersion()); + forwardingRemoteService.forward(request); } } \ No newline at end of file diff --git a/vorgang-manager-server/src/main/resources/application-local.yml b/vorgang-manager-server/src/main/resources/application-local.yml index 6dc2ce987e221a66e9c5f7e74a23b8a82fe86557..d320959ed403f3d876855a97c6cfe3f13fddb37d 100644 --- a/vorgang-manager-server/src/main/resources/application-local.yml +++ b/vorgang-manager-server/src/main/resources/application-local.yml @@ -38,6 +38,10 @@ grpc: negotiationType: PLAINTEXT vorgang-manager: negotiationType: PLAINTEXT + forwarder: + address: static://127.0.0.1:9292 + negotiationType: PLAINTEXT + server: security: enabled: false diff --git a/vorgang-manager-server/src/main/resources/application.yml b/vorgang-manager-server/src/main/resources/application.yml index 7bf48c56cfe7b1d089dd2dc367d1b6bcdd25d09c..db37a3d59597564120aae7e596c1202b417bc44e 100644 --- a/vorgang-manager-server/src/main/resources/application.yml +++ b/vorgang-manager-server/src/main/resources/application.yml @@ -44,6 +44,8 @@ grpc: negotiationType: PLAINTEXT zufi-manager: negotiationType: TLS + forwarder: + negotiationType: TLS server: security: diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/EingangTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/EingangTestFactory.java index 9fa8813dda465272e1279e1015337fe1c15efd45..458d34b190863132535d415c903e16c999591684 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/EingangTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/EingangTestFactory.java @@ -49,6 +49,9 @@ public class EingangTestFactory { public static final Map<String, Object> SUBFORM_FLAT = Map.of(SUBFORM_FIELD_NAME, SUBFORM_FIELD); public static final Map<String, Object> FORM_DATA = Map.of(SINGLE_FIELD_NAME, SINGLE_FIELD, SUBFORM_NAME, SUBFORM); + public static final IncomingFileGroup ATTACHMENT = IncomingFileGroupTestFactory.create(); + public static final IncomingFile REPRESENTATION = IncomingFileTestFactory.create(); + public static Eingang create() { return createBuilder().build(); } @@ -59,8 +62,8 @@ public class EingangTestFactory { .header(EingangHeaderTestFactory.create()) .antragsteller(AntragstellerTestFactory.create()) .formData(FORM_DATA) - .attachment(IncomingFileGroupTestFactory.create()) - .representation(IncomingFileTestFactory.create()) + .attachment(ATTACHMENT) + .representation(REPRESENTATION) .zustaendigeStelle(ZustaendigeStelleTestFactory.create()); } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcEingangTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcEingangTestFactory.java index 79acc665d6b1e91a113c120c9c4f3b4455499b6b..e149cbf5b3a682ae4628b2862a8d34c25fb6dd6f 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcEingangTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcEingangTestFactory.java @@ -25,12 +25,11 @@ package de.ozgcloud.vorgang.vorgang; import java.util.UUID; -import de.ozgcloud.vorgang.common.grpc.GrpcSubFormTestFactory; +import de.ozgcloud.vorgang.common.grpc.GrpcFormDataTestFactory; public class GrpcEingangTestFactory { public static final String ID = UUID.randomUUID().toString(); - public static final GrpcSubForm SUB_FORM = GrpcSubFormTestFactory.create(); public static GrpcEingang create() { return createBuilder().build(); @@ -42,7 +41,7 @@ public class GrpcEingangTestFactory { .setHeader(GrpcEingangHeaderTestFactory.create()) .setAntragsteller(GrpcAntragstellerTestFactory.create()) .setZustaendigeStelle(GrpcZustaendigeStelleTestFactory.create()) - .setFormData(GrpcFormData.newBuilder().addForm(GrpcSubFormTestFactory.create()).build()) + .setFormData(GrpcFormDataTestFactory.create()) .addAttachments(GrpcIncomingFileGroupTestFactory.create()) .setNumberOfAttachments(4) .addRepresentations(GrpcIncomingFileTestFactory.create()) diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapperTest.java index e59250ca0f7f5a57efec908af88708184b7f1d6e..771c11f67fc9cc2e3e3116bf7e208acc05a4bc49 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapperTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/IncomingFileMapperTest.java @@ -32,6 +32,8 @@ import org.mockito.InjectMocks; import org.mockito.Spy; import de.ozgcloud.vorgang.files.FileIdMapper; +import de.ozgcloud.vorgang.vorgang.redirect.GrpcAttachmentFileTestFactory; +import de.ozgcloud.vorgang.vorgang.redirect.GrpcRepresentationFileTestFactory; class IncomingFileMapperTest { @@ -50,4 +52,26 @@ class IncomingFileMapperTest { assertThat(result).isNotNull().usingRecursiveComparison().isEqualTo(IncomingFileTestFactory.create()); } } + + @Nested + class TestToAttachmentFile { + + @Test + void shouldMapToGrpcAttachmentFile() { + var result = mapper.toAttachmentFile(GrpcAttachmentFileTestFactory.GROUP_NAME, IncomingFileTestFactory.create()); + + assertThat(result).isEqualTo(GrpcAttachmentFileTestFactory.create()); + } + } + + @Nested + class TestToRepresentationFile { + + @Test + void shouldMapToGrpcRepresentationFile() { + var result = mapper.toRepresentationFile(IncomingFileTestFactory.create()); + + assertThat(result).isEqualTo(GrpcRepresentationFileTestFactory.create()); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangGrpcServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangGrpcServiceITCase.java index 24d8152f703322dd571094e5b4eefd73463fbc87..dbb11b274b6b7413244b976d5e6b23838ab8533a 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangGrpcServiceITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangGrpcServiceITCase.java @@ -223,7 +223,7 @@ class VorgangGrpcServiceITCase { } private static GrpcFormData expectedFormData() { - var grpcFormData = GrpcFormDataTestFactory.createBuilder().clearField().addAllField(formFields); + var grpcFormData = GrpcFormDataTestFactory.createBuilder().clearField().addAllField(formFields).clearForm(); for (String subFormName : List.of(TITLE_SUBFORM_1, TITLE_SUBFORM_2, TITLE_SUBFORM_3)) { grpcFormData.addForm(GrpcSubForm.newBuilder() .setTitle(subFormName) diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5e6e63b58402a779cb7716609f773772e50b2342 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java @@ -0,0 +1,796 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +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.io.InputStream; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.apache.commons.lang3.RandomUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Spy; + +import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils; +import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender; +import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.common.test.ReflectionTestUtils; +import de.ozgcloud.eingang.forwarder.RouteForwardingServiceGrpc; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwarding; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingResponse; +import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor; +import de.ozgcloud.vorgang.files.FileService; +import de.ozgcloud.vorgang.vorgang.Eingang; +import de.ozgcloud.vorgang.vorgang.EingangTestFactory; +import de.ozgcloud.vorgang.vorgang.IncomingFile; +import de.ozgcloud.vorgang.vorgang.IncomingFileGroup; +import de.ozgcloud.vorgang.vorgang.IncomingFileGroupTestFactory; +import de.ozgcloud.vorgang.vorgang.IncomingFileMapper; +import de.ozgcloud.vorgang.vorgang.IncomingFileTestFactory; +import de.ozgcloud.vorgang.vorgang.Vorgang; +import de.ozgcloud.vorgang.vorgang.VorgangService; +import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; +import de.ozgcloud.vorgang.vorgang.redirect.ForwardingRemoteService.ForwardingResponseObserver; +import io.grpc.stub.CallStreamObserver; +import io.grpc.stub.StreamObserver; +import lombok.SneakyThrows; + +class ForwardingRemoteServiceTest { + + @Spy + @InjectMocks + private ForwardingRemoteService service; + @Mock + private VorgangService vorgangService; + @Mock + private ForwardingRequestMapper forwardingRequestMapper; + @Mock + private RouteForwardingServiceGrpc.RouteForwardingServiceStub serviceStub; + @Mock + private FileService fileService; + @Mock + private IncomingFileMapper incomingFileMapper; + + @Mock + private StreamObserver<GrpcRouteForwardingRequest> requestObserver; + private final ForwardingRequest request = ForwardingRequestTestFactory.create(); + private final Eingang eingang = EingangTestFactory.create(); + private final Vorgang vorgang = VorgangTestFactory.createBuilder().clearEingangs().eingang(eingang).build(); + + @Nested + class TestForward { + + @Captor + private ArgumentCaptor<ForwardingResponseObserver> responseObserverCaptor; + @Captor + private ArgumentCaptor<CompletableFuture<Void>> futureCaptor; + + @BeforeEach + void init() { + doNothing().when(service).routeForwarding(any(), any()); + doNothing().when(service).waitForCompletion(any()); + } + + @Test + void shouldRouteForwarding() { + forward(); + + verify(service).routeForwarding(eq(request), any(ForwardingResponseObserver.class)); + } + + @Test + void shouldWaitForCompletion() { + forward(); + + verify(service).waitForCompletion(futureCaptor.capture()); + verify(service).routeForwarding(any(), responseObserverCaptor.capture()); + assertThat(futureCaptor.getValue()) + .isSameAs(ReflectionTestUtils.getField(responseObserverCaptor.getValue(), "future", CompletableFuture.class)); + } + + private void forward() { + service.forward(request); + } + } + + @Nested + class TestRouteForwarding { + + @Mock + private ForwardingResponseObserver responseObserver; + + @BeforeEach + void init() { + when(serviceStub.withInterceptors(any())).thenReturn(serviceStub); + } + + @Test + void shouldAttachClientCallContextToServiceStub() { + givenGrpcCallCompletedSuccessfully(); + doNothing().when(service).sendEingang(any(), any()); + + routeForwarding(); + + verify(serviceStub).withInterceptors(any(VorgangManagerClientCallContextAttachingInterceptor.class)); + } + + @Test + void shouldMakeGrpcCallToRouteForwarding() { + givenGrpcCallCompletedSuccessfully(); + doNothing().when(service).sendEingang(any(), any()); + + routeForwarding(); + + verify(serviceStub).routeForwarding(responseObserver); + } + + @Nested + class OnSuccess { + + @BeforeEach + void init() { + givenGrpcCallCompletedSuccessfully(); + doNothing().when(service).sendEingang(any(), any()); + } + + @Test + void shouldSendEingang() { + routeForwarding(); + + verify(service).sendEingang(request, requestObserver); + } + + @Test + void shouldCallOnCompleted() { + routeForwarding(); + + verify(requestObserver).onCompleted(); + } + } + + @Nested + class OnFailure { + + private final RuntimeException error = new RuntimeException(); + + @BeforeEach + void init() { + givenGrpcCallCompletedSuccessfully(); + doThrow(error).when(service).sendEingang(any(), any()); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + void shouldCallOnError() { + catchThrowableOfType(RuntimeException.class, TestRouteForwarding.this::routeForwarding); + + verify(requestObserver).onError(error); + } + + @Test + void shouldThrowError() { + assertThatThrownBy(TestRouteForwarding.this::routeForwarding).isSameAs(error); + } + } + + private void givenGrpcCallCompletedSuccessfully() { + when(serviceStub.routeForwarding(any())).thenAnswer(invocation -> { + ((ForwardingResponseObserver) invocation.getArgument(0)).onCompleted(); + return requestObserver; + }); + } + + private void routeForwarding() { + service.routeForwarding(request, responseObserver); + } + } + + @Nested + class TestSendEingang { + + private final GrpcRouteForwardingRequest routeForwardingRequest = GrpcRouteForwardingRequestTestFactory.create(); + + @BeforeEach + void init() { + when(vorgangService.getById(any())).thenReturn(vorgang); + doReturn(routeForwardingRequest).when(service).buildRouteForwardingRequest(any(), any()); + doNothing().when(service).sendAttachments(any(), any()); + doNothing().when(service).sendRepresentations(any(), any()); + } + + @Test + void shouldGetVorgangById() { + sendEingang(); + + verify(vorgangService).getById(VorgangTestFactory.ID); + } + + @Test + void shouldBuildRouteForwardingRequest() { + sendEingang(); + + verify(service).buildRouteForwardingRequest(request, eingang); + } + + @Test + void shouldSendForwardingRequest() { + sendEingang(); + + verify(requestObserver).onNext(routeForwardingRequest); + } + + @Test + void shouldCallSendAttachments() { + sendEingang(); + + verify(service).sendAttachments(List.of(EingangTestFactory.ATTACHMENT), requestObserver); + } + + @Test + void shouldCallSendRepresentations() { + sendEingang(); + + verify(service).sendRepresentations(List.of(EingangTestFactory.REPRESENTATION), requestObserver); + } + + private void sendEingang() { + service.sendEingang(request, requestObserver); + } + } + + @Nested + class TestBuildRouteForwardingRequest { + + private final GrpcRouteForwarding routeForwarding = GrpcRouteForwardingTestFactory.create(); + + @BeforeEach + void init() { + when(forwardingRequestMapper.toGrpcRouteForwarding(any(), any())).thenReturn(routeForwarding); + } + + @Test + void shouldMapToRouteForwarding() { + buildRouteForwardingRequest(); + + verify(forwardingRequestMapper).toGrpcRouteForwarding(request, eingang); + } + + @Test + void shouldReturnRouteForwardingRequest() { + var builtRequest = buildRouteForwardingRequest(); + + assertThat(builtRequest).isEqualTo(GrpcRouteForwardingRequestTestFactory.create()); + } + + private GrpcRouteForwardingRequest buildRouteForwardingRequest() { + return service.buildRouteForwardingRequest(request, eingang); + } + } + + @Nested + class TestSendAttachments { + + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; + @Mock + private InputStream inputStream; + + private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create(); + + @BeforeEach + void init() { + when(fileService.getUploadedFileStream(any())).thenReturn(inputStream); + doReturn(fileSender).when(service).createAttachmentFileSender(any(), any(), any(), any()); + when(fileSender.send()).thenReturn(fileSender); + } + + @Test + void shouldGetUploadedFileContent() { + sendAttachments(); + + verify(fileService).getUploadedFileStream(IncomingFileTestFactory.ID); + } + + @Test + void shouldCallCreateAttachmentFileSender() { + sendAttachments(); + + verify(service).createAttachmentFileSender(requestObserver, IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE, + inputStream); + } + + @Test + void shouldSend() { + sendAttachments(); + + verify(fileSender).send(); + } + + private void sendAttachments() { + service.sendAttachments(List.of(attachment), requestObserver); + } + } + + @Nested + class TestCreateAttachmentFileSender { + + @Mock + private InputStream inputStream; + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSenderWithMetadata; + @Captor + private ArgumentCaptor<BiFunction<byte[], Integer, GrpcRouteForwardingRequest>> chunkBuilderCaptor; + + private final byte[] chunk = RandomUtils.insecure().randomBytes(5); + private final GrpcRouteForwardingRequest metadataRequest = GrpcRouteForwardingRequestTestFactory.create(); + + @BeforeEach + void init() { + doReturn(fileSender).when(service).createSenderWithoutMetadata(any(), any(), any()); + doReturn(metadataRequest).when(service).buildGrpcAttachmentFile(any(), any()); + when(fileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata); + } + + @Test + void shouldCallCreateSenderWithoutMetadata() { + createAttachmentFileSender(); + + verify(service).createSenderWithoutMetadata(chunkBuilderCaptor.capture(), eq(requestObserver), eq(inputStream)); + chunkBuilderCaptor.getValue().apply(chunk, chunk.length); + verify(service).buildAttachmentChunk(chunk, chunk.length); + } + + @Test + void shouldCallBuildGrpcAttachmentFile() { + createAttachmentFileSender(); + + verify(service).buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE); + } + + @Test + void shouldSetMetaData() { + createAttachmentFileSender(); + + verify(fileSender).withMetaData(metadataRequest); + } + + @Test + void shouldReturnBuiltFileSender() { + var returnedFileSender = createAttachmentFileSender(); + + assertThat(returnedFileSender).isSameAs(fileSenderWithMetadata); + } + + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createAttachmentFileSender() { + return service.createAttachmentFileSender(requestObserver, IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE, + inputStream); + } + } + + @Nested + class TestBuildAttachmentChunk { + + private final byte[] chunk = RandomUtils.insecure().randomBytes(5); + + @BeforeEach + void mock() { + doReturn(GrpcAttachmentTestFactory.CONTENT).when(service).buildGrpcFileContent(any(), anyInt()); + } + + @Test + void shouldCallBuildGrpcFileContent() { + service.buildAttachmentChunk(chunk, chunk.length); + + verify(service).buildGrpcFileContent(chunk, chunk.length); + } + + @Test + void shouldReturnGrpcRouteForwardingRequest() { + var result = service.buildAttachmentChunk(chunk, chunk.length); + + assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithAttachmentContent()); + } + } + + @Nested + class TestBuildGrpcAttachmentFile { + + private final IncomingFile file = IncomingFileTestFactory.create(); + + @BeforeEach + void mock() { + when(incomingFileMapper.toAttachmentFile(any(), any())).thenReturn(GrpcAttachmentFileTestFactory.create()); + } + + @Test + void shouldCallIncomingFileMapper() { + service.buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, file); + + verify(incomingFileMapper).toAttachmentFile(IncomingFileGroupTestFactory.NAME, file); + } + + @Test + void shouldReturnAttachmentMetadataRequest() { + var result = service.buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, file); + + assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithAttachmentMetadata()); + } + } + + @Nested + class TestSendRepresentations { + + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; + @Mock + private InputStream inputStream; + + private final IncomingFile representation = IncomingFileTestFactory.create(); + + @BeforeEach + void init() { + when(fileService.getUploadedFileStream(any())).thenReturn(inputStream); + doReturn(fileSender).when(service).createRepresentationFileSender(any(), any(), any()); + when(fileSender.send()).thenReturn(fileSender); + } + + @Test + void shouldGetUploadedFileContent() { + sendRepresentations(); + + verify(fileService).getUploadedFileStream(IncomingFileTestFactory.ID); + } + + @Test + void shouldCallCreateRepresentationFileSender() { + sendRepresentations(); + + verify(service).createRepresentationFileSender(requestObserver, representation, inputStream); + } + + @Test + void shouldSend() { + sendRepresentations(); + + verify(fileSender).send(); + } + + private void sendRepresentations() { + service.sendRepresentations(List.of(representation), requestObserver); + } + } + + @Nested + class TestCreateRepresentationFileSender { + + @Mock + private InputStream inputStream; + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSenderWithMetadata; + @Captor + private ArgumentCaptor<BiFunction<byte[], Integer, GrpcRouteForwardingRequest>> chunkBuilderCaptor; + + private final byte[] chunk = RandomUtils.insecure().randomBytes(5); + private final GrpcRouteForwardingRequest metadataRequest = GrpcRouteForwardingRequestTestFactory.create(); + private final IncomingFile incomingFile = IncomingFileTestFactory.create(); + + @BeforeEach + void init() { + doReturn(fileSender).when(service).createSenderWithoutMetadata(any(), any(), any()); + doReturn(metadataRequest).when(service).buildGrpcRepresentationFile(any()); + when(fileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata); + } + + @Test + void shouldCallCreateSenderWithoutMetadata() { + createRepresentationFileSender(); + + verify(service).createSenderWithoutMetadata(chunkBuilderCaptor.capture(), eq(requestObserver), eq(inputStream)); + chunkBuilderCaptor.getValue().apply(chunk, chunk.length); + verify(service).buildRepresentationChunk(chunk, chunk.length); + } + + @Test + void shouldCallBuildGrpcRepresentationFile() { + createRepresentationFileSender(); + + verify(service).buildGrpcRepresentationFile(incomingFile); + } + + @Test + void shouldSetMetaData() { + createRepresentationFileSender(); + + verify(fileSender).withMetaData(metadataRequest); + } + + @Test + void shouldReturnBuiltFileSender() { + var returnedFileSender = createRepresentationFileSender(); + + assertThat(returnedFileSender).isSameAs(fileSenderWithMetadata); + } + + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createRepresentationFileSender() { + return service.createRepresentationFileSender(requestObserver, incomingFile, inputStream); + } + } + + @Nested + class TestCreateSenderWithoutMetadata { + + private MockedStatic<GrpcFileUploadUtils> grpcFileUploadUtilsMock; + @Mock + private BiFunction<byte[], Integer, GrpcRouteForwardingRequest> chunkBuilder; + @Mock + private CallStreamObserver<GrpcRouteForwardingRequest> requestCallStreamObserver; + @Mock + private InputStream inputStream; + @Mock + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; + @Mock + private StreamObserver<GrpcRouteForwardingResponse> responseObserver; + @Captor + private ArgumentCaptor<Function<StreamObserver<GrpcRouteForwardingResponse>, CallStreamObserver<GrpcRouteForwardingRequest>>> reqObserverBuilderCaptor; + + @BeforeEach + void init() { + grpcFileUploadUtilsMock = mockStatic(GrpcFileUploadUtils.class); + grpcFileUploadUtilsMock.when(() -> GrpcFileUploadUtils.createSender(any(), any(), any(), anyBoolean())).thenReturn(fileSender); + } + + @AfterEach + void tearDown() { + grpcFileUploadUtilsMock.close(); + } + + @Test + void shouldCreateFileSender() { + createSenderWithoutMetadata(); + + grpcFileUploadUtilsMock + .verify(() -> GrpcFileUploadUtils.createSender(eq(chunkBuilder), eq(inputStream), reqObserverBuilderCaptor.capture(), eq(false))); + assertThat(reqObserverBuilderCaptor.getValue().apply(responseObserver)).isSameAs(requestCallStreamObserver); + } + + @Test + void shouldReturnCreatedFileSender() { + var returnedFileSender = createSenderWithoutMetadata(); + + assertThat(returnedFileSender).isSameAs(fileSender); + } + + private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createSenderWithoutMetadata() { + return service.createSenderWithoutMetadata(chunkBuilder, requestCallStreamObserver, inputStream); + } + } + + @Nested + class TestBuildRepresentationChunk { + + private final byte[] chunk = RandomUtils.insecure().randomBytes(5); + + @BeforeEach + void mock() { + doReturn(GrpcRepresentationTestFactory.CONTENT).when(service).buildGrpcFileContent(any(), anyInt()); + } + + @Test + void shouldCallBuildGrpcFileContent() { + service.buildRepresentationChunk(chunk, chunk.length); + + verify(service).buildGrpcFileContent(chunk, chunk.length); + } + + @Test + void shouldReturnGrpcRouteForwardingRequest() { + var result = service.buildRepresentationChunk(chunk, chunk.length); + + assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithRepresentationContent()); + } + } + + @Nested + class TestBuildGrpcFileContent { + + @Nested + class TestOnEndOfFile { + + @Test + void shouldBuildEndOfFileChunk() { + var fileContent = service.buildGrpcFileContent(new byte[0], -1); + + assertThat(fileContent).isEqualTo(GrpcFileContentTestFactory.createEndOfFile()); + } + } + + @Nested + class TestOnContentProvided { + + @Test + void shouldBuildEndOfFileChunk() { + var fileContent = service.buildGrpcFileContent(GrpcFileContentTestFactory.CONTENT, GrpcFileContentTestFactory.CONTENT.length); + + assertThat(fileContent).isEqualTo(GrpcFileContentTestFactory.create()); + } + } + } + + @Nested + class TestBuildGrpcRepresentationFile { + + private final IncomingFile file = IncomingFileTestFactory.create(); + + @BeforeEach + void mock() { + when(incomingFileMapper.toRepresentationFile(any())).thenReturn(GrpcRepresentationFileTestFactory.create()); + } + + @Test + void shouldCallIncomingFileMapper() { + service.buildGrpcRepresentationFile(file); + + verify(incomingFileMapper).toRepresentationFile(file); + } + + @Test + void shouldReturnRepresentationMetadataRequest() { + var result = service.buildGrpcRepresentationFile(file); + + assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithRepresentationMetadata()); + } + } + + @Nested + class TestWaitForCompletion { + + @Mock + private CompletableFuture<Void> future; + + @SneakyThrows + @Test + void shouldGetFromFuture() { + waitForCompletion(); + + verify(future).get(2, TimeUnit.MINUTES); + } + + @Nested + class TestOnInterruptedException { + + private final InterruptedException exception = new InterruptedException(); + + @BeforeEach + @SneakyThrows + void mock() { + when(future.get(anyLong(), any())).thenThrow(exception); + } + + @Test + void shouldThrowTechnicalException() { + assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); + } + + @Test + void shouldInterruptThread() { + try { + waitForCompletion(); + } catch (TechnicalException e) { + // expected + } + + assertThat(Thread.currentThread().isInterrupted()).isTrue(); + } + } + + @Nested + class TestOnExecutionException { + + private final ExecutionException exception = new ExecutionException(new Exception()); + + @BeforeEach + @SneakyThrows + void mock() { + when(future.get(anyLong(), any())).thenThrow(exception); + } + + @Test + void shouldThrowTechnicalException() { + assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); + } + } + + @Nested + class TestOnTimeoutException { + + private final TimeoutException exception = new TimeoutException(); + + @BeforeEach + @SneakyThrows + void mock() { + when(future.get(anyLong(), any())).thenThrow(exception); + } + + @Test + void shouldThrowTechnicalException() { + assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); + } + } + + private void waitForCompletion() { + service.waitForCompletion(future); + } + } + + @Nested + class ForwardingResponseObserverTest { + + @Mock + private CompletableFuture<Void> future; + private ForwardingResponseObserver responseObserver; + + @BeforeEach + void init() { + responseObserver = new ForwardingResponseObserver(future); + } + + @Test + void shouldCompleteExceptionallyOnError() { + var error = new Throwable(); + + responseObserver.onError(error); + + verify(future).completeExceptionally(error); + } + + @Test + void shouldCompleteOnCompleted() { + responseObserver.onCompleted(); + + verify(future).complete(null); + } + } +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java index 715529e268ded4133f6e9962fada6f8ce2c8ca35..ffa5197108a4c22c78753140c2f2dd3da9d74be5 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java @@ -32,14 +32,26 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mapstruct.factory.Mappers; +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Spy; +import de.ozgcloud.eingang.forwarding.GrpcRouteCriteria; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwarding; import de.ozgcloud.vorgang.command.CommandTestFactory; +import de.ozgcloud.vorgang.vorgang.Eingang; +import de.ozgcloud.vorgang.vorgang.EingangMapper; +import de.ozgcloud.vorgang.vorgang.EingangTestFactory; +import de.ozgcloud.vorgang.vorgang.GrpcEingang; +import de.ozgcloud.vorgang.vorgang.GrpcEingangTestFactory; import de.ozgcloud.vorgang.vorgang.redirect.ForwardingRequestMapper.CommandBodyFields; class ForwardingRequestMapperTest { + @Mock + private EingangMapper eingangMapper; @Spy + @InjectMocks private ForwardingRequestMapper mapper = Mappers.getMapper(ForwardingRequestMapper.class); private final Map<String, Object> bodyObject = Map.of( CommandBodyFields.ORGANISATION_EINHEIT_ID, OrganisationEinheitTestFactory.ID, @@ -118,4 +130,65 @@ class ForwardingRequestMapperTest { return mapper.toAddress(bodyObject); } } + + @Nested + class TestToGrpcRouteForwarding { + + private final ForwardingRequest request = ForwardingRequestTestFactory.create(); + private final Eingang eingang = EingangTestFactory.create(); + private final GrpcEingang grpcEingang = GrpcEingangTestFactory.create(); + + @BeforeEach + void init() { + doReturn(GrpcRouteCriteriaTestFactory.create()).when(mapper).toGrpcRouteCriteria(any()); + when(eingangMapper.toGrpc(any())).thenReturn(grpcEingang); + } + + @Test + void shouldCallEingangMapper() { + map(); + + verify(eingangMapper).toGrpc(eingang); + } + + @Test + void shouldMapToGrpcRouteCriteria() { + map(); + + verify(mapper).toGrpcRouteCriteria(request); + } + + @Test + void shouldMapToGrpcEingangStub() { + map(); + + verify(mapper).toGrpcEingangStub(grpcEingang); + } + + @Test + void shouldMapToGrpcRouteForwarding() { + var mapped = map(); + + assertThat(mapped).isEqualTo(GrpcRouteForwardingTestFactory.create()); + } + + private GrpcRouteForwarding map() { + return mapper.toGrpcRouteForwarding(request, eingang); + } + } + + @Nested + class TestToGrpcRouteCriteria { + + @Test + void shouldMap() { + var mapped = map(); + + assertThat(mapped).isEqualTo(GrpcRouteCriteriaTestFactory.create()); + } + + private GrpcRouteCriteria map() { + return mapper.toGrpcRouteCriteria(ForwardingRequestTestFactory.create()); + } + } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java index 1b864c7a9ab50c247178efd8d1346e87aff1e4f5..326cf45ddf0f6ea612311f599880cdb81e231d43 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java @@ -64,19 +64,16 @@ class ForwardingServiceTest { private ForwardingService service; @Mock private ForwardingRepository repository; - @Mock private ZipBuilderService zipService; - @Mock private MailService mailService; - @Mock private VorgangService vorgangService; - @Mock private StatusService statusService; - + @Mock + private ForwardingRemoteService remoteService; @Mock private ApplicationEventPublisher publisher; @@ -626,11 +623,24 @@ class ForwardingServiceTest { @Nested class TestForward { + private final ForwardingRequest request = ForwardingRequestTestFactory.create(); + @Test void shouldSetStatusToWeitergeleitet() { - service.forward(ForwardingRequestTestFactory.create()); + forward(); verify(statusService).setStatusToWeitergeleitet(VorgangTestFactory.ID, VorgangTestFactory.VERSION); } + + @Test + void shouldCallRemoteService() { + forward(); + + verify(remoteService).forward(request); + } + + private void forward() { + service.forward(request); + } } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcAttachmentFileTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcAttachmentFileTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8c954a3e170cdf1bafb583cb5cc59933637f665a --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcAttachmentFileTestFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import de.ozgcloud.eingang.forwarding.GrpcAttachmentFile; +import de.ozgcloud.eingang.forwarding.GrpcAttachmentFile.Builder; +import de.ozgcloud.vorgang.vorgang.IncomingFileGroupTestFactory; +import de.ozgcloud.vorgang.vorgang.IncomingFileTestFactory; + +public class GrpcAttachmentFileTestFactory { + + public static final String GROUP_NAME = IncomingFileGroupTestFactory.NAME; + + public static GrpcAttachmentFile create() { + return createBuilder().build(); + } + + public static Builder createBuilder() { + return GrpcAttachmentFile.newBuilder() + .setGroupName(GROUP_NAME) + .setFileName(IncomingFileTestFactory.NAME) + .setContentType(IncomingFileTestFactory.CONTENT_TYPE_STR) + .setVendorId(IncomingFileTestFactory.VENDOR_ID) + .setSize(IncomingFileTestFactory.SIZE); + } + +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcAttachmentTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcAttachmentTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..4e0e278a9d017593627fa279c7837dfaa0d221c7 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcAttachmentTestFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import de.ozgcloud.eingang.forwarding.GrpcAttachment; +import de.ozgcloud.eingang.forwarding.GrpcAttachmentFile; +import de.ozgcloud.eingang.forwarding.GrpcFileContent; + +public class GrpcAttachmentTestFactory { + + public static final GrpcAttachmentFile FILE = GrpcAttachmentFileTestFactory.create(); + public static final GrpcFileContent CONTENT = GrpcFileContentTestFactory.create(); + + public static GrpcAttachment createWithFile() { + return GrpcAttachment.newBuilder() + .setFile(FILE) + .build(); + } + + public static GrpcAttachment createWithContent() { + return GrpcAttachment.newBuilder() + .setContent(CONTENT) + .build(); + } + +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcEingangStubTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcEingangStubTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..6cdd06a4a1b2ad6af5d26bd3265c76ce2890cba6 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcEingangStubTestFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import de.ozgcloud.eingang.forwarding.GrpcEingangStub; +import de.ozgcloud.vorgang.common.grpc.GrpcFormDataTestFactory; +import de.ozgcloud.vorgang.vorgang.GrpcAntragstellerTestFactory; +import de.ozgcloud.vorgang.vorgang.GrpcEingangHeaderTestFactory; + +class GrpcEingangStubTestFactory { + + public static GrpcEingangStub create() { + return createBuilder().build(); + } + + public static GrpcEingangStub.Builder createBuilder() { + return GrpcEingangStub.newBuilder() + .setHeader(GrpcEingangHeaderTestFactory.create()) + .setAntragsteller(GrpcAntragstellerTestFactory.create()) + .setFormData(GrpcFormDataTestFactory.create()); + } +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcFileContentTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcFileContentTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..c37286a4df81c814c805fd2a6c05ac84a9741e68 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcFileContentTestFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import org.apache.commons.lang3.RandomUtils; + +import com.google.protobuf.ByteString; + +import de.ozgcloud.eingang.forwarding.GrpcFileContent; +import de.ozgcloud.eingang.forwarding.GrpcFileContent.Builder; + +public class GrpcFileContentTestFactory { + + public static final boolean IS_END_OF_FILE = false; + public static final byte[] CONTENT = RandomUtils.insecure().randomBytes(10);; + + public static GrpcFileContent create() { + return createBuilder().build(); + } + + public static Builder createBuilder() { + return GrpcFileContent.newBuilder() + .setContent(ByteString.copyFrom(CONTENT)) + .setIsEndOfFile(IS_END_OF_FILE); + } + + public static GrpcFileContent createEndOfFile() { + return GrpcFileContent.newBuilder().setIsEndOfFile(true).build(); + } + +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRepresentationFileTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRepresentationFileTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..d832cbc58b40bb3a68f0ac65d28d557c563934d2 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRepresentationFileTestFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import de.ozgcloud.eingang.forwarding.GrpcRepresentationFile; +import de.ozgcloud.eingang.forwarding.GrpcRepresentationFile.Builder; +import de.ozgcloud.vorgang.vorgang.IncomingFileTestFactory; + +public class GrpcRepresentationFileTestFactory { + + public static GrpcRepresentationFile create() { + return createBuilder().build(); + } + + public static Builder createBuilder() { + return GrpcRepresentationFile.newBuilder() + .setFileName(IncomingFileTestFactory.NAME) + .setContentType(IncomingFileTestFactory.CONTENT_TYPE_STR) + .setVendorId(IncomingFileTestFactory.VENDOR_ID) + .setSize(IncomingFileTestFactory.SIZE); + } + +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRepresentationTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRepresentationTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..4dce5a27e1c366229b9ad697e79717ba73c09a81 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRepresentationTestFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import de.ozgcloud.eingang.forwarding.GrpcFileContent; +import de.ozgcloud.eingang.forwarding.GrpcRepresentation; +import de.ozgcloud.eingang.forwarding.GrpcRepresentationFile; + +public class GrpcRepresentationTestFactory { + + public static final GrpcRepresentationFile FILE = GrpcRepresentationFileTestFactory.create(); + public static final GrpcFileContent CONTENT = GrpcFileContentTestFactory.create(); + + public static GrpcRepresentation createWithFile() { + return GrpcRepresentation.newBuilder() + .setFile(FILE) + .build(); + } + + public static GrpcRepresentation createWithContent() { + return GrpcRepresentation.newBuilder() + .setContent(CONTENT) + .build(); + } +} diff --git a/vorgang-manager-interface/src/main/protobuf/route-forwarding.proto b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteCriteriaTestFactory.java similarity index 66% rename from vorgang-manager-interface/src/main/protobuf/route-forwarding.proto rename to vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteCriteriaTestFactory.java index aeb0eefd8c8dd8447e8e26f88bff45b4ea35f630..e28c74034003854c9467922062a80a86f24185f8 100644 --- a/vorgang-manager-interface/src/main/protobuf/route-forwarding.proto +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteCriteriaTestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den * Ministerpräsidenten des Landes Schleswig-Holstein * Staatskanzlei * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung @@ -21,19 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -syntax = "proto3"; +package de.ozgcloud.vorgang.vorgang.redirect; -package de.ozgcloud.eingang.forwarder; +import de.ozgcloud.eingang.forwarding.GrpcRouteCriteria; -import "route-forwarding.model.proto"; +class GrpcRouteCriteriaTestFactory { -option java_multiple_files = true; -option java_package = "de.ozgcloud.eingang.forwarder"; -option java_outer_classname = "RouteForwardingProto"; - -service RouteForwardingService { - - rpc RouteForwarding(GrpcRouteForwardingRequest) returns (GrpcRouteForwardingResponse) { + public static GrpcRouteCriteria create() { + return createBuilder().build(); } -} \ No newline at end of file + public static GrpcRouteCriteria.Builder createBuilder() { + return GrpcRouteCriteria.newBuilder() + .setOrganisationEinheitId(OrganisationEinheitTestFactory.ID); + } +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteForwardingRequestTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteForwardingRequestTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7d463347d23cf97551855d460b655ea3da710524 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteForwardingRequestTestFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2025 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.vorgang.vorgang.redirect; + +import de.ozgcloud.eingang.forwarding.GrpcAttachment; +import de.ozgcloud.eingang.forwarding.GrpcRepresentation; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; + +class GrpcRouteForwardingRequestTestFactory { + + public static final GrpcAttachment ATTACHMENT_METADATA = GrpcAttachmentTestFactory.createWithFile(); + public static final GrpcAttachment ATTACHMENT_CONTENT = GrpcAttachmentTestFactory.createWithContent(); + public static final GrpcRepresentation REPRESENTATION_METADATA = GrpcRepresentationTestFactory.createWithFile(); + public static final GrpcRepresentation REPRESENTATION_CONTENT = GrpcRepresentationTestFactory.createWithContent(); + + public static GrpcRouteForwardingRequest create() { + return createBuilder().build(); + } + + public static GrpcRouteForwardingRequest.Builder createBuilder() { + return GrpcRouteForwardingRequest.newBuilder() + .setRouteForwarding(GrpcRouteForwardingTestFactory.create()); + } + + public static GrpcRouteForwardingRequest createWithAttachmentMetadata() { + return GrpcRouteForwardingRequest.newBuilder() + .setAttachment(ATTACHMENT_METADATA) + .build(); + } + + public static GrpcRouteForwardingRequest createWithAttachmentContent() { + return GrpcRouteForwardingRequest.newBuilder() + .setAttachment(ATTACHMENT_CONTENT) + .build(); + } + + public static GrpcRouteForwardingRequest createWithRepresentationMetadata() { + return GrpcRouteForwardingRequest.newBuilder() + .setRepresentation(REPRESENTATION_METADATA) + .build(); + } + + public static GrpcRouteForwardingRequest createWithRepresentationContent() { + return GrpcRouteForwardingRequest.newBuilder() + .setRepresentation(REPRESENTATION_CONTENT) + .build(); + } +} diff --git a/vorgang-manager-interface/src/main/protobuf/route-forwarding.model.proto b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteForwardingTestFactory.java similarity index 60% rename from vorgang-manager-interface/src/main/protobuf/route-forwarding.model.proto rename to vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteForwardingTestFactory.java index 46961d480f78f8a30591492b272e7ecf1329a4af..badf9c7b5c9aa3536c559cf51d09540ab2696c45 100644 --- a/vorgang-manager-interface/src/main/protobuf/route-forwarding.model.proto +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/GrpcRouteForwardingTestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den * Ministerpräsidenten des Landes Schleswig-Holstein * Staatskanzlei * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung @@ -21,28 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -syntax = "proto3"; +package de.ozgcloud.vorgang.vorgang.redirect; -package de.ozgcloud.eingang.forwarder; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwarding; -import "vorgang.model.proto"; +class GrpcRouteForwardingTestFactory { -option java_multiple_files = true; -option java_package = "de.ozgcloud.eingang.forwarding"; -option java_outer_classname = "RouteForwardingModelProto"; + public static GrpcRouteForwarding create() { + return createBuilder().build(); + } - -message GrpcRouteForwardingRequest { - GrpcRouteCriteria routeCriteria = 1; - de.ozgcloud.vorgang.vorgang.GrpcEingang eingang = 5; -} - -message GrpcRouteForwardingResponse { - + public static GrpcRouteForwarding.Builder createBuilder() { + return GrpcRouteForwarding.newBuilder() + .setRouteCriteria(GrpcRouteCriteriaTestFactory.create()) + .setEingangStub(GrpcEingangStubTestFactory.create()); + } } - -message GrpcRouteCriteria { - string gemeindeSchluessel = 1; - string webserviceUrl = 2; - string organisationseinheitenId = 3; -} \ No newline at end of file diff --git a/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataTestFactory.java b/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataTestFactory.java index b715c9098e9cc4134bcd1281a403563c4641dce5..760f1e90310ba7a316c82824a0ca625bed204d43 100644 --- a/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataTestFactory.java +++ b/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataTestFactory.java @@ -34,6 +34,7 @@ public class GrpcFormDataTestFactory { public static Builder createBuilder() { return GrpcFormData.newBuilder() - .addField(GrpcFormFieldTestFactory.create()); + .addField(GrpcFormFieldTestFactory.create()) + .addForm(GrpcSubFormTestFactory.create()); } }