From 7d16ab1f5711a726f3aea90cd042e38b9fdd933b Mon Sep 17 00:00:00 2001 From: Henry Borasch <Henry.Borasch@sinc.de> Date: Thu, 2 Mar 2023 10:55:34 +0100 Subject: [PATCH] fixed validator configuration, adjusted and added tests --- .../fitconnect/api/config/SchemaConfig.java | 5 +- .../client/util/ValidDataGuardTest.java | 25 +- .../validation/DefaultValidationService.java | 3 +- .../s00000096_1.0.schema.json | 1263 +++++++++++++++++ .../DefaultValidationServiceTest.java | 59 +- .../resources/submission_data_schema.json | 22 + 6 files changed, 1354 insertions(+), 23 deletions(-) create mode 100644 core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json create mode 100644 core/src/test/resources/submission_data_schema.json diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java b/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java index e5dd7541f..3250d7024 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java @@ -15,7 +15,8 @@ public enum SchemaConfig { SET_V_1_0_1(SCHEMA_BASE_URL.schemaUri.resolve("set-payload/1.0.1/set-payload.schema.json"), "set_schema_1.0.1.json"), SET_V_1_0_0(SCHEMA_BASE_URL.schemaUri.resolve("set-payload/1.0.0/set-payload.schema.json"), "set_schema_1.0.0.json"), METADATA_V_1_0_0(SCHEMA_BASE_URL.schemaUri.resolve("metadata/1.0.0/metadata.schema.json"), "metadata_schema_1.0.0.json"), - XZUFI_DESTINATION_SCHEMA(SCHEMA_BASE_URL.schemaUri.resolve("xzufi/destination.schema.json"), "destination_schema.json"); + XZUFI_DESTINATION_SCHEMA(SCHEMA_BASE_URL.schemaUri.resolve("xzufi/destination.schema.json"), "destination_schema.json"), + SUBMISSION_DATA_SCHEMA(URI.create("https://schema.fitko.de/fim/s00000096_1.0.schema.json"), "s00000096_1.0.schema.json"); private final URI schemaUri; @@ -50,7 +51,7 @@ public enum SchemaConfig { } public static List<String> getSubmissionDataSchemaPaths(final String submissionDataSchemaBaseDir) { - return Stream.empty() + return Stream.of(SUBMISSION_DATA_SCHEMA.fileName) .map(fileName -> submissionDataSchemaBaseDir + "/" + fileName) .collect(Collectors.toList()); } diff --git a/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java b/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java index ef356cb03..ed2f31677 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -56,7 +57,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -107,7 +108,7 @@ class ValidDataGuardTest { void testMissingDestinationId() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{}", URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")) @@ -126,7 +127,7 @@ class ValidDataGuardTest { void testInvalidServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{\"test\" . \"data\"}", @@ -145,7 +146,7 @@ class ValidDataGuardTest { void testMissingServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{\"test\" . \"data\"}", @@ -171,7 +172,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -202,7 +203,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -234,7 +235,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -268,7 +269,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -321,7 +322,7 @@ class ValidDataGuardTest { void testMissingDestinationId() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -341,7 +342,7 @@ class ValidDataGuardTest { void testInvalidServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -361,7 +362,7 @@ class ValidDataGuardTest { void testMissingServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -387,7 +388,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") diff --git a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java index 31a70c213..0ffa40b74 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java @@ -155,11 +155,10 @@ public class DefaultValidationService implements ValidationService { String schema = schemaProvider.loadSubmissionDataSchema(schemaUri); try { - returnValidationResult(SCHEMA_FACTORY_DRAFT_2007.getSchema(schema).validate(MAPPER.readTree(json))); + return returnValidationResult(SCHEMA_FACTORY_DRAFT_2020.getSchema(schema).validate(MAPPER.readTree(json))); } catch (final JacksonException e) { return ValidationResult.error(e); } - return ValidationResult.ok(); } @Override diff --git a/core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json b/core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json new file mode 100644 index 000000000..9208f4cc7 --- /dev/null +++ b/core/src/main/resources/submission-data-schema/s00000096_1.0.schema.json @@ -0,0 +1,1263 @@ +{ + "type": "object", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schema.fitko.de/fim/s00000096_1.0.schema.json", + "title": "Mutterschutzliste Detailangaben", + "$defs": { + "G00000253": { + "title": "Arbeitgeber - juristische Person (Anzeige schwangere oder stillende Frau)", + "type": "object", + "properties": { + "F60000319": { + "$ref": "#/$defs/F60000319" + }, + "G60000088": { + "$ref": "#/$defs/G60000088" + }, + "G00001408": { + "$ref": "#/$defs/G00001408" + }, + "G00001914": { + "$ref": "#/$defs/G00001914" + } + }, + "required": [ + "F60000319", + "G60000088", + "G00001408", + "G00001914" + ] + }, + "F60000319": { + "title": "Eingetragener Name / Organisationsname", + "description": "Laut XGewerbeanzeige.Betrieb.eingetragenerName soll der eingetragene Name 1-1000 Zeichen betragen.", + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "G60000088": { + "title": "Anschrift Inland", + "type": "object", + "properties": { + "G60000086": { + "$ref": "#/$defs/G60000086" + }, + "G60000087": { + "$ref": "#/$defs/G60000087" + } + } + }, + "G60000086": { + "title": "Anschrift Inland Straßenanschrift", + "type": "object", + "properties": { + "F60000243": { + "$ref": "#/$defs/F60000243" + }, + "F60000244": { + "$ref": "#/$defs/F60000244" + }, + "F60000246": { + "$ref": "#/$defs/F60000246" + }, + "F60000247": { + "$ref": "#/$defs/F60000247" + }, + "F60000248": { + "$ref": "#/$defs/F60000248" + } + }, + "required": [ + "F60000243", + "F60000246", + "F60000247" + ] + }, + "F60000243": { + "title": "Straße", + "description": "Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 50. Bei XInneres 8 ist die Feldlänge <= 55 Zeichen.", + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "F60000244": { + "title": "Hausnummer", + "description": "Die Modellierung aus XInneres wurde nicht 1:1 übernommen, um die Komplexität für die Ausfüllenden nicht zu hoch zu setzen. Es wurde darauf verzichtet für das Ende von Hausnummernbereichen eigene Felder zu modellieren. Daher ist die Feldlänge hier heraufgesetzt und eine entsprechende Beschreibung wurde eingefügt. Die Feldlänge setzt sich aus der maximalen Feldlänge zweier Hausnummern (jeweils 4), zweier Buchstaben (jeweils 1) und eines Zeichen (-) zusammen.", + "type": "string", + "minLength": 1, + "maxLength": 11 + }, + "F60000246": { + "title": "Postleitzahl", + "type": "string", + "minLength": 5, + "maxLength": 5, + "pattern": "^([0]{1}[1-9]{1}|[1-9]{1}[0-9]{1})[0-9]{3}$" + }, + "F60000247": { + "title": "Ort", + "description": "Kompatibilität zu EPA in TR XhD v 1.4 sollte Feldlänge min. 44. Laut PAuswV 2*25 = 50 Zeichen. Laut Xinneres.Meldeanschrift.Wohnort Version 8 = 40 Zeichen.\r\nLaut BSI TR-03123 ≤ 105 Zeichen.", + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "F60000248": { + "title": "Anschrift Zusatzangaben", + "type": "string", + "minLength": 1, + "maxLength": 21 + }, + "G60000087": { + "title": "Anschrift Inland Postfachanschrift", + "type": "object", + "properties": { + "F60000249": { + "$ref": "#/$defs/F60000249" + }, + "F60000246": { + "$ref": "#/$defs/F60000246" + }, + "F60000247": { + "$ref": "#/$defs/F60000247" + } + }, + "required": [ + "F60000246", + "F60000247" + ] + }, + "F60000249": { + "title": "Postfach", + "description": "Die Zeichenlänge des Postfachs orientiert sich derzeit an der Länge einer Adresszeile auf einem Brief. Eine Schärfung/Überprüfung steht noch aus.", + "type": "string", + "minLength": 1, + "maxLength": 21 + }, + "G00001408": { + "title": "Kommunikation (Einverständnis E-Mail, Personalangelegenheit)", + "description": "In dieser Datenfeldgruppe wird per Regel gefordert, dass mindestens eine Kommunikationsmöglichkeit angegeben werden muss. Falls es gewünscht ist, dass keine Kommunikationsmöglichkeit angegeben werden braucht, muss die ganze Feldgruppe bei der Verwendung optional gesetzt werden.", + "type": "object", + "properties": { + "F60000240": { + "$ref": "#/$defs/F60000240" + }, + "F60000241": { + "$ref": "#/$defs/F60000241" + }, + "F00002483": { + "$ref": "#/$defs/F00002483" + }, + "F00002408": { + "$ref": "#/$defs/F00002408" + } + } + }, + "F60000240": { + "title": "Telefon", + "description": "Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.", + "type": "string", + "minLength": 1, + "maxLength": 23 + }, + "F60000241": { + "title": "Telefax", + "description": "Dieses Feld wurde angelehnt an ITU E.123. Eine Prüfung über ein Pattern erfolgt nicht, um den Eingebenden nicht zu überfordern.", + "type": "string", + "minLength": 1, + "maxLength": 23 + }, + "F00002483": { + "title": "E-Mail Personalangelegenheit", + "type": "string", + "minLength": 6, + "maxLength": 254, + "pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,63}$" + }, + "F00002408": { + "title": "Einverständnis E-Mail", + "type": "boolean" + }, + "G00001914": { + "title": "Ansprechpartner (ohne Funktion / Einverständnis E-Mail)", + "type": "object", + "properties": { + "F60000227": { + "$ref": "#/$defs/F60000227" + }, + "F60000228": { + "$ref": "#/$defs/F60000228" + }, + "F60000229": { + "$ref": "#/$defs/F60000229" + }, + "G00001399": { + "$ref": "#/$defs/G00001399" + } + }, + "required": [ + "F60000227" + ] + }, + "F60000227": { + "title": "Familienname", + "description": "Laut BSI TR-03123 soll die Gesamtlänge für Familienname, Titel und Geburtsname nicht mehr als 120 Zeichen betragen. Laut PAuswV soll Name (Familienname und Geburtsname) nicht mehr als 2*26 = 52 Zeichen bzw. 3*40 = 120 Zeichen betragen.", + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "F60000228": { + "title": "Vornamen", + "description": "Laut BSI TR-03123 soll Vorname ≤ 80 Zeichen betragen.\r\nLaut PAuswV soll Vorname nicht mehr als 26 Zeichen bzw. 2*40 = 80 Zeichen betragen.", + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "F60000229": { + "title": "Doktorgrade", + "description": "Die Feldlänge ist laut BSI TR-03123 (hier Titel genannt) maximal 120 (Familienname + Titel + Geburtsname). \r\nDurch die Vielzahl von Kombinationsmöglichkeiten, falls mehrere Doktortitel vorhanden sind, ist es nicht sinnvoll, eine Codeliste zu hinterlegen.", + "type": "string", + "minLength": 3, + "maxLength": 119 + }, + "G00001399": { + "title": "Kommunikation (Einverständnis E-Mail)", + "description": "In dieser Datenfeldgruppe wird per Regel gefordert, dass mindestens eine Kommunikationsmöglichkeit angegeben werden muss. Falls es gewünscht ist, dass keine Kommunikationsmöglichkeit angegeben werden braucht, muss die ganze Feldgruppe bei der Verwendung optional gesetzt werden.", + "type": "object", + "properties": { + "F60000240": { + "$ref": "#/$defs/F60000240" + }, + "F60000241": { + "$ref": "#/$defs/F60000241" + }, + "F60000242": { + "$ref": "#/$defs/F60000242" + }, + "F00002408": { + "$ref": "#/$defs/F00002408" + } + } + }, + "F60000242": { + "title": "E-Mail", + "type": "string", + "minLength": 6, + "maxLength": 254, + "pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,63}$" + }, + "G00000271": { + "title": "Informationen zu einer schwangeren oder stillenden Frau", + "type": "object", + "properties": { + "G00000259": { + "$ref": "#/$defs/G00000259" + }, + "G00000260": { + "$ref": "#/$defs/G00000260" + }, + "G00000262": { + "$ref": "#/$defs/G00000262" + }, + "G00000264": { + "$ref": "#/$defs/G00000264" + }, + "G00000263": { + "$ref": "#/$defs/G00000263" + } + }, + "required": [ + "G00000259", + "G00000260", + "G00000262", + "G00000264", + "G00000263" + ] + }, + "G00000259": { + "title": "Persönliche Informationen schwangere stillende Frau Details", + "type": "object", + "properties": { + "F60000227": { + "$ref": "#/$defs/F60000227" + }, + "F60000228": { + "$ref": "#/$defs/F60000228" + }, + "G60000083": { + "$ref": "#/$defs/G60000083" + }, + "G60000093": { + "$ref": "#/$defs/G60000093" + }, + "F00000462": { + "$ref": "#/$defs/F00000462" + }, + "F00000467": { + "$ref": "#/$defs/F00000467" + }, + "F00000468": { + "$ref": "#/$defs/F00000468" + }, + "F00000471": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000471" + }, + "minItems": 1 + }, + "F00000473": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000473" + }, + "minItems": 1 + } + }, + "required": [ + "F60000227", + "G60000083", + "G60000093", + "F00000462" + ] + }, + "G60000083": { + "title": "Geburtsdatum (teilbekannt)", + "type": "object", + "properties": { + "F60000231": { + "$ref": "#/$defs/F60000231" + }, + "F60000232": { + "$ref": "#/$defs/F60000232" + }, + "F60000233": { + "$ref": "#/$defs/F60000233" + } + }, + "required": [ + "F60000233" + ] + }, + "F60000231": { + "title": "Tag (ohne Monat und Jahr)", + "type": "integer", + "minimum": 1, + "maximum": 31 + }, + "F60000232": { + "title": "Monat", + "type": "integer", + "minimum": 1, + "maximum": 12 + }, + "F60000233": { + "title": "Jahr", + "type": "integer", + "minimum": 1850, + "maximum": 2080 + }, + "G60000093": { + "title": "Anschrift Inland oder Ausland mit Frage", + "description": "Zu beachten: wird die Anschrift im Kontext der Online-Ausweisfunktion des neuen Personalausweis verwendet, können nur Personen mit Anschriften in Deutschland authentisiert werden (siehe auch https://www.personalausweisportal.de/DE/Buergerinnen-und-Buerger/Online-Ausweisen/Wohnsitz_im_Ausland/wohnsitz_im_ausland_node.html). Bei der Umsetzung müssen somit ausländische Anschriften ausgeschlossen werden.", + "type": "object", + "properties": { + "F60000263": { + "$ref": "#/$defs/F60000263" + }, + "G60000088": { + "$ref": "#/$defs/G60000088" + }, + "G60000091": { + "$ref": "#/$defs/G60000091" + } + }, + "required": [ + "F60000263" + ] + }, + "F60000263": { + "title": "Abfrage Anschrift Inland oder Ausland", + "description": "Verwendete Codeliste: Anschrift Inland oder Ausland 2020-08-18", + "type": "string", + "enum": [ + "001", + "002" + ] + }, + "G60000091": { + "title": "Anschrift Ausland", + "type": "object", + "properties": { + "F60000261": { + "$ref": "#/$defs/F60000261" + }, + "G60000092": { + "$ref": "#/$defs/G60000092" + } + }, + "required": [ + "F60000261", + "G60000092" + ] + }, + "F60000261": { + "title": "Staat", + "description": "Verwendete Codeliste: Staat 2021-02-19", + "type": "string", + "enum": [ + "000", + "121", + "122", + "123", + "124", + "125", + "126", + "127", + "128", + "129", + "130", + "131", + "134", + "135", + "136", + "137", + "139", + "140", + "141", + "142", + "143", + "144", + "145", + "146", + "147", + "148", + "149", + "150", + "151", + "152", + "153", + "154", + "155", + "156", + "157", + "158", + "160", + "161", + "163", + "164", + "165", + "166", + "167", + "168", + "169", + "170", + "181", + "221", + "223", + "224", + "225", + "226", + "227", + "229", + "230", + "231", + "232", + "233", + "236", + "237", + "238", + "239", + "242", + "243", + "244", + "245", + "246", + "247", + "248", + "249", + "251", + "252", + "253", + "254", + "255", + "256", + "257", + "258", + "259", + "261", + "262", + "263", + "265", + "267", + "268", + "269", + "271", + "272", + "273", + "274", + "277", + "278", + "281", + "282", + "283", + "284", + "285", + "286", + "287", + "289", + "291", + "320", + "322", + "323", + "324", + "326", + "327", + "328", + "330", + "332", + "333", + "334", + "335", + "336", + "337", + "340", + "345", + "346", + "347", + "348", + "349", + "351", + "353", + "354", + "355", + "357", + "359", + "361", + "364", + "365", + "366", + "367", + "368", + "369", + "370", + "371", + "421", + "422", + "423", + "424", + "425", + "426", + "427", + "429", + "430", + "431", + "432", + "434", + "436", + "437", + "438", + "439", + "441", + "442", + "444", + "445", + "446", + "447", + "448", + "449", + "450", + "451", + "454", + "456", + "457", + "458", + "460", + "461", + "462", + "467", + "469", + "470", + "471", + "472", + "474", + "475", + "476", + "477", + "479", + "482", + "483", + "523", + "524", + "526", + "527", + "530", + "531", + "532", + "533", + "536", + "537", + "538", + "540", + "541", + "543", + "544", + "545" + ] + }, + "G60000092": { + "title": "Anschriftzone", + "type": "object", + "properties": { + "F60000262": { + "type": "array", + "items": { + "$ref": "#/$defs/F60000262" + }, + "minItems": 2, + "maxItems": 5 + } + }, + "required": [ + "F60000262" + ] + }, + "F60000262": { + "title": "ZeileAnschrift", + "type": "string", + "minLength": 1, + "maxLength": 35 + }, + "F00000462": { + "title": "Status Frau (schwanger, stillend)", + "type": "string", + "enum": [ + "001", + "002" + ] + }, + "F00000467": { + "title": "Voraussichtlicher Entbindungstermin", + "type": "string", + "format": "date" + }, + "F00000468": { + "title": "Entbindungstermin", + "type": "string", + "format": "date" + }, + "F00000471": { + "title": "Ergebnis Entbindung", + "description": "Eine Mehrlingsgeburt kann über Mehrfachauswahl abgefragt werden.", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004", + "005" + ] + }, + "F00000473": { + "title": "Nachweis Schutzfristverlängerung Behinderung", + "type": "string" + }, + "G00000260": { + "title": "Informationen Beschäftigung schwangere stillende Frau Details", + "type": "object", + "properties": { + "F00000463": { + "$ref": "#/$defs/F00000463" + }, + "F00000601": { + "$ref": "#/$defs/F00000601" + }, + "G00000261": { + "$ref": "#/$defs/G00000261" + }, + "G00000280": { + "type": "array", + "items": { + "$ref": "#/$defs/G00000280" + }, + "minItems": 1 + } + }, + "required": [ + "F00000463", + "G00000261" + ] + }, + "F00000463": { + "title": "Beschäftigungsverhältnis Frau", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004", + "005", + "006", + "007", + "008", + "999" + ] + }, + "F00000601": { + "title": "Beschäftigungsverhältnis Frau Sonstiges", + "type": "string" + }, + "G00000261": { + "title": "Informationen Vertragslaufzeit", + "type": "object", + "properties": { + "F00000488": { + "$ref": "#/$defs/F00000488" + }, + "F00000489": { + "$ref": "#/$defs/F00000489" + }, + "F00000490": { + "$ref": "#/$defs/F00000490" + }, + "F00000491": { + "$ref": "#/$defs/F00000491" + } + }, + "required": [ + "F00000488", + "F00000489" + ] + }, + "F00000488": { + "title": "Vertrag Befristung", + "type": "string", + "enum": [ + "001", + "002" + ] + }, + "F00000489": { + "title": "Beschäftigungsbeginn", + "type": "string", + "format": "date" + }, + "F00000490": { + "title": "Beschäftigungsende", + "type": "string", + "format": "date" + }, + "F00000491": { + "title": "Kündigungsdatum", + "type": "string", + "format": "date" + }, + "G00000280": { + "title": "Angaben zur Elternzeit", + "type": "object", + "properties": { + "F60000048": { + "$ref": "#/$defs/F60000048" + }, + "F60000049": { + "$ref": "#/$defs/F60000049" + } + }, + "required": [ + "F60000048", + "F60000049" + ] + }, + "F60000048": { + "title": "Anfang", + "type": "string", + "format": "date" + }, + "F60000049": { + "title": "Ende", + "type": "string", + "format": "date" + }, + "G00000262": { + "title": "Informationen zur beabsichtigten Beschäftigung der schwangeren oder stillenden Frau Details", + "type": "object", + "properties": { + "F00000464": { + "$ref": "#/$defs/F00000464" + }, + "G00001404": { + "$ref": "#/$defs/G00001404" + }, + "F00000465": { + "$ref": "#/$defs/F00000465" + }, + "G00001405": { + "$ref": "#/$defs/G00001405" + }, + "F00002420": { + "$ref": "#/$defs/F00002420" + }, + "G00001406": { + "$ref": "#/$defs/G00001406" + }, + "F00000466": { + "$ref": "#/$defs/F00000466" + }, + "F00002421": { + "$ref": "#/$defs/F00002421" + }, + "F00002422": { + "$ref": "#/$defs/F00002422" + }, + "F00002423": { + "$ref": "#/$defs/F00002423" + } + }, + "required": [ + "F00000464", + "F00000466", + "F00002421" + ] + }, + "F00000464": { + "title": "Sonn- und Feiertagsarbeit (Mutterschutz)", + "type": "boolean" + }, + "G00001404": { + "title": "Sonn- und Feiertagsarbeit (Mutterschutz)", + "type": "object", + "properties": { + "F00000482": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000482" + }, + "minItems": 1 + }, + "F00002416": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002416" + }, + "minItems": 1 + }, + "F00002415": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002415" + }, + "minItems": 1 + } + }, + "required": [ + "F00000482", + "F00002416", + "F00002415" + ] + }, + "F00000482": { + "title": "Bereiterklärung Sonn- und Feiertagsarbeit", + "type": "string" + }, + "F00002416": { + "title": "Nachweis: Ausnahme § 10 Arbeitszeitgesetz ", + "type": "string" + }, + "F00002415": { + "title": "Nachweis: Ersatzruhetag", + "type": "string" + }, + "F00000465": { + "title": "Nachtarbeit (Mutterschutz)", + "type": "boolean" + }, + "G00001405": { + "title": "Nachtarbeit (Mutterschutz)", + "type": "object", + "properties": { + "F00000483": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000483" + }, + "minItems": 1 + }, + "F00002035": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002035" + }, + "minItems": 1 + }, + "F00002414": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002414" + }, + "minItems": 1 + }, + "F00000485": { + "$ref": "#/$defs/F00000485" + }, + "F00000249": { + "$ref": "#/$defs/F00000249" + }, + "F00000487": { + "$ref": "#/$defs/F00000487" + }, + "F60000296": { + "type": "array", + "items": { + "$ref": "#/$defs/F60000296" + }, + "minItems": 1 + } + }, + "required": [ + "F00000483", + "F00002035", + "F00002414", + "F00000485" + ] + }, + "F00000483": { + "title": "Erklärung Nachtarbeit", + "type": "string" + }, + "F00002035": { + "title": "Ärztliches Zeugnis (Unbedenklichkeitsbescheinigung)", + "type": "string" + }, + "F00002414": { + "title": "Nachweis: Ausschluss Gefährdung durch Alleinarbeit", + "type": "string" + }, + "F00000485": { + "title": "Status Antrag Nachtarbeit", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004" + ] + }, + "F00000249": { + "title": "Datum der Antragstellung", + "type": "string", + "format": "date" + }, + "F00000487": { + "title": "Genehmigungsdatum", + "type": "string", + "format": "date" + }, + "F60000296": { + "title": "Nachweis", + "type": "string" + }, + "F00002420": { + "title": "Teilnahme an Ausbildungsveranstaltungen (Mutterschutz)", + "type": "boolean" + }, + "G00001406": { + "title": "Nachtarbeit (Studentin/Schülerin - Mutterschutz)", + "type": "object", + "properties": { + "F00002036": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002036" + }, + "minItems": 1 + }, + "F00000484": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000484" + }, + "minItems": 1 + }, + "F00002414": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002414" + }, + "minItems": 1 + } + }, + "required": [ + "F00002036", + "F00000484", + "F00002414" + ] + }, + "F00002036": { + "title": "Nachweis: Erforderlichkeit Teilnahme an Ausbildungsveranstaltungen", + "type": "string" + }, + "F00000484": { + "title": "Nachtarbeit Ausbildung (Bereiterklärung)", + "type": "string" + }, + "F00000466": { + "title": "Mutterschutz getaktete Arbeit", + "type": "boolean" + }, + "F00002421": { + "title": "Heimarbeit (Mutterschutz)", + "type": "string" + }, + "F00002422": { + "title": "Umfang Heimarbeit (schwanger - Mutterschutz)", + "type": "string" + }, + "F00002423": { + "title": "Umfang Heimarbeit (stillend - Mutterschutz)", + "type": "string" + }, + "G00000264": { + "title": "Informationen zur Art der Beschäftigung der schwangeren oder stillenden Frau", + "type": "object", + "properties": { + "G00000267": { + "$ref": "#/$defs/G00000267" + }, + "F00000501": { + "$ref": "#/$defs/F00000501" + }, + "F00000503": { + "type": "array", + "items": { + "$ref": "#/$defs/F00000503" + }, + "minItems": 1 + }, + "F00000502": { + "$ref": "#/$defs/F00000502" + }, + "F00002418": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002418" + }, + "minItems": 1 + }, + "G00000268": { + "$ref": "#/$defs/G00000268" + } + }, + "required": [ + "G00000267", + "F00000501", + "F00000503" + ] + }, + "G00000267": { + "title": "Informationen zur Beschäftigung vor Schwangerschaft", + "type": "object", + "properties": { + "F00000499": { + "$ref": "#/$defs/F00000499" + }, + "G00001597": { + "$ref": "#/$defs/G00001597" + }, + "F00000215": { + "$ref": "#/$defs/F00000215" + }, + "F00000500": { + "$ref": "#/$defs/F00000500" + } + }, + "required": [ + "F00000499", + "F00000215", + "F00000500" + ] + }, + "F00000499": { + "title": "Beschäftigungsort", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004" + ] + }, + "G00001597": { + "title": "Betriebsstätte (mit Organisationsname)", + "type": "object", + "properties": { + "F60000319": { + "$ref": "#/$defs/F60000319" + }, + "G60000086": { + "$ref": "#/$defs/G60000086" + }, + "G00001408": { + "$ref": "#/$defs/G00001408" + } + }, + "required": [ + "G60000086", + "G00001408" + ] + }, + "F00000215": { + "title": "Berufliche Tätigkeit - Art", + "type": "string" + }, + "F00000500": { + "title": "Name Arbeitsplatz Gefährdungsbeurteilung", + "description": "Über diesen Namen wird auf die externe Gefährdungsbeurteilung (§ 10 MuSchG; § 5 ArbSchG) verwiesen. In dieser Gefährungsbeurteilung sollten alle relevanten Aspekte aus § 9 (3) MuSchG, § 11 MuSchG, § 12 MuSchG aufgenommen werden.", + "type": "string" + }, + "F00000501": { + "title": "Ergebnis der Beurteilung der Arbeitsbedingungen", + "type": "string", + "enum": [ + "001", + "002", + "003", + "004", + "005", + "006", + "007" + ] + }, + "F00000503": { + "title": "Gefährdungsbeurteilung Mutterschutz", + "type": "string" + }, + "F00000502": { + "title": "Umgestaltung der Arbeitsbedingungen", + "type": "string" + }, + "F00002418": { + "title": "Nachweis: Umgestaltung der Arbeitsbedingungen durch Schutzmaßnahmen", + "type": "string" + }, + "G00000268": { + "title": "Informationen zur Beschäftigung während der Schutzzeiten vor und nach der Entbindung", + "type": "object", + "properties": { + "F00000499": { + "$ref": "#/$defs/F00000499" + }, + "G00001597": { + "$ref": "#/$defs/G00001597" + }, + "F00000215": { + "$ref": "#/$defs/F00000215" + }, + "F00000500": { + "$ref": "#/$defs/F00000500" + } + }, + "required": [ + "F00000499", + "F00000215", + "F00000500" + ] + }, + "G00000263": { + "title": "Informationen zum Umfang der Beschäftigung der schwangeren oder stillenden Frau", + "type": "object", + "properties": { + "F00000494": { + "$ref": "#/$defs/F00000494" + }, + "F00000495": { + "$ref": "#/$defs/F00000495" + }, + "F00000496": { + "$ref": "#/$defs/F00000496" + }, + "F00000497": { + "$ref": "#/$defs/F00000497" + }, + "F00000498": { + "$ref": "#/$defs/F00000498" + }, + "F00002413": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002413" + }, + "minItems": 1 + }, + "F00002417": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002417" + }, + "minItems": 1 + }, + "F00002419": { + "type": "array", + "items": { + "$ref": "#/$defs/F00002419" + }, + "minItems": 1 + } + }, + "required": [ + "F00000496", + "F00000497", + "F00000498", + "F00002413", + "F00002417", + "F00002419" + ] + }, + "F00000494": { + "title": "Tagesarbeitszeit", + "type": "number" + }, + "F00000495": { + "title": "Doppelwochenarbeitszeit", + "type": "number" + }, + "F00000496": { + "title": "Uhrzeit des frühest möglichen Arbeits- oder Ausbildungsbeginns", + "type": "string" + }, + "F00000497": { + "title": "Uhrzeit des spätest möglichen Arbeits- oder Ausbildungsendes", + "type": "string" + }, + "F00000498": { + "title": "Dauer aller Ruhepause in Minuten ", + "type": "string" + }, + "F00002413": { + "title": "Nachweis: Ausschluss Ruhezeiten unter 11 Stunden", + "type": "string" + }, + "F00002417": { + "title": "Nachweis: Freistellung Untersuchungen", + "type": "string" + }, + "F00002419": { + "title": "Nachweis: Vermeidung von Nachteilen ", + "type": "string" + } + }, + "properties": { + "G00000253": { + "$ref": "#/$defs/G00000253" + }, + "G00000271": { + "type": "array", + "items": { + "$ref": "#/$defs/G00000271" + }, + "minItems": 1 + } + }, + "required": [ + "G00000253", + "G00000271" + ] +} \ No newline at end of file diff --git a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java index ede11c83a..c61b72989 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java @@ -24,7 +24,6 @@ import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.exceptions.ValidationException; import dev.fitko.fitconnect.api.services.crypto.MessageDigestService; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; -import dev.fitko.fitconnect.api.services.validation.ValidationService; import dev.fitko.fitconnect.core.crypto.HashService; import dev.fitko.fitconnect.core.schema.SchemaResourceProvider; import dev.fitko.fitconnect.core.testutil.LogCaptor; @@ -44,13 +43,15 @@ import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.*; class DefaultValidationServiceTest { - private ValidationService underTest; + private DefaultValidationService underTest; private MessageDigestService hashService; private static final LogCaptor logs = new LogCaptor(); + private RestTemplate restTemplate = mock(RestTemplate.class); private SchemaProvider schemaProvider; @BeforeEach @@ -62,7 +63,7 @@ class DefaultValidationServiceTest { final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); final List<String> submissionDataSchemas = SchemaConfig.getSubmissionDataSchemaPaths("/submission-data-schema"); final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemas); - schemaProvider = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); + schemaProvider = new SchemaResourceProvider(restTemplate, schemaResources); underTest = new DefaultValidationService(config, hashService, schemaProvider); } @@ -372,7 +373,7 @@ class DefaultValidationServiceTest { void testValidDestinationPayload() { // Given - final Map<String,Object> claims = Map.of( + final Map<String, Object> claims = Map.of( "iss", "submission-service", "jti", UUID.randomUUID().toString(), "iat", new Date().getTime(), @@ -392,7 +393,7 @@ class DefaultValidationServiceTest { void testDestinationPayloadIsMissingMandatoryClaims() { // Given - final Map<String,Object> claims = Map.of("test", "claim"); + final Map<String, Object> claims = Map.of("test", "claim"); // When final ValidationResult validationResult = underTest.validateDestinationSchema(claims); @@ -411,10 +412,14 @@ class DefaultValidationServiceTest { void testValidJson() throws IOException { // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn("{}"); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + final var validJson = getResource("/valid_json_data.json"); // When - final ValidationResult validationResult = underTest.validateJsonFormat(validJson, URI.create("urn:something")); + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(validJson, URI.create("urn:something")); // Then assertTrue(validationResult.isValid()); @@ -424,16 +429,56 @@ class DefaultValidationServiceTest { void testInvalidJson() throws IOException { // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn("{}"); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + final var invalidJson = getResource("/invalid_json_data.json"); // When - final ValidationResult validationResult = underTest.validateJsonFormat(invalidJson, URI.create("urn:something")); + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(invalidJson, URI.create("urn:something")); // Then assertFalse(validationResult.isValid()); assertTrue(validationResult.hasError()); assertThat(validationResult.getError().getMessage(), containsString("was expecting double-quote to start field name")); + } + + @Test + void testValidSubmissionDataSchema() throws IOException { + + // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn(getResource("/submission_data_schema.json")); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + final var invalidJson = "{ \"someString\": \"someStringValue\", \"someArray\": [\"someArrayValue\"] }"; + + // When + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(invalidJson, URI.create("urn:something")); + + // Then + assertTrue(validationResult.isValid()); + assertFalse(validationResult.hasError()); + } + + @Test + void testInvalidSubmissionDataSchema() throws IOException { + + // Given + SchemaProvider schemaProvider = mock(SchemaProvider.class); + when(schemaProvider.loadSubmissionDataSchema(any())).thenReturn(getResource("/submission_data_schema.json")); + DefaultValidationService defaultValidationService = new DefaultValidationService(getApplicationConfig(true), new HashService(), schemaProvider); + + final var invalidJson = "{ \"wrongString\": \"someStringValue\", \"someArray\": [\"someArrayValue\"] }"; + + // When + final ValidationResult validationResult = defaultValidationService.validateJsonFormat(invalidJson, URI.create("urn:something")); + + // Then + assertFalse(validationResult.isValid()); + assertTrue(validationResult.hasError()); + assertThat(validationResult.getError().getMessage(), containsString("$.someString")); } @Test diff --git a/core/src/test/resources/submission_data_schema.json b/core/src/test/resources/submission_data_schema.json new file mode 100644 index 000000000..dfe7ac754 --- /dev/null +++ b/core/src/test/resources/submission_data_schema.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://test/submission_data_schema.json", + "title": "test service", + "properties": { + "someString": { + "type": "string" + }, + "someArray": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": [ + "someString", + "someArray" + ] +} \ No newline at end of file -- GitLab