diff --git a/leia-common/src/main/java/com/grookage/leia/common/utils/SchemaValidationUtils.java b/leia-common/src/main/java/com/grookage/leia/common/utils/SchemaValidationUtils.java index 8a1fa4c..05d515c 100644 --- a/leia-common/src/main/java/com/grookage/leia/common/utils/SchemaValidationUtils.java +++ b/leia-common/src/main/java/com/grookage/leia/common/utils/SchemaValidationUtils.java @@ -19,11 +19,7 @@ import com.google.common.collect.Sets; import com.grookage.leia.common.violation.LeiaSchemaViolation; import com.grookage.leia.common.violation.ViolationContext; -import com.grookage.leia.models.attributes.ArrayAttribute; -import com.grookage.leia.models.attributes.MapAttribute; -import com.grookage.leia.models.attributes.ObjectAttribute; -import com.grookage.leia.models.attributes.SchemaAttribute; -import com.grookage.leia.models.attributes.SchemaAttributeHandler; +import com.grookage.leia.models.attributes.*; import com.grookage.leia.models.schema.SchemaDetails; import com.grookage.leia.models.schema.SchemaValidationType; import com.grookage.leia.models.schema.SchemaValidationVisitor; @@ -31,14 +27,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ClassUtils; -import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Set; +import java.lang.reflect.*; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -48,7 +38,7 @@ public class SchemaValidationUtils { static Function, Function> assignableCheckFunction = klass -> attribute -> ClassUtils.isAssignable(klass, attribute.getType().getAssignableClass()); - private static final String TYPE_VIOLATION = "Incompatible Type, expected: %s, provided: %s"; + private static final String TYPE_MISMATCH_MESSAGE = "Type mismatch, expected: %s, provided: %s"; public List valid(final SchemaDetails schemaDetails, final Class klass) { @@ -61,7 +51,7 @@ public List valid(final SchemaValidationType validationType final ViolationContext context) { context.pushClass(klass); final var fields = FieldUtils.getAllFields(klass); - validSchema(validationType, attributes, fields, klass, context); + validSchema(validationType, attributes, fields, context); attributes.forEach(each -> validAttribute(each, fields, validationType, context)); context.popClass(); return context.getViolations(); @@ -70,7 +60,6 @@ public List valid(final SchemaValidationType validationType private void validSchema(final SchemaValidationType validationType, final Set attributes, final List fields, - final Class klass, final ViolationContext context) { final var fieldNames = fields.stream() .map(Field::getName) @@ -136,7 +125,7 @@ private void valid(final SchemaValidationType validationType, final Class klass, final ViolationContext context) { if (!isMatchingType(klass, schemaAttribute)) { - context.addViolation(String.format(TYPE_VIOLATION, schemaAttribute.getType(), klass.getSimpleName()), + context.addViolation(String.format(TYPE_MISMATCH_MESSAGE, schemaAttribute.getType(), klass.getSimpleName()), schemaAttribute.getName()); return; } @@ -144,10 +133,12 @@ private void valid(final SchemaValidationType validationType, schemaAttribute.accept(new SchemaAttributeHandler(a -> null) { @Override public Void accept(ArrayAttribute attribute) { - if (klass.isArray()) { - valid(validationType, attribute.getElementAttribute(), klass.getComponentType(), context); - return null; - } else if (!Objects.isNull(attribute.getElementAttribute())) { + if (Objects.nonNull(attribute.getElementAttribute())) { + if (klass.isArray()) { + valid(validationType, attribute.getElementAttribute(), klass.getComponentType(), context); + return null; + } + // Provided List, Set expected List, Set context.addViolation(String.format("Missing Type arguments, expected ParameterizedType:%s", attribute.getElementAttribute().getType()), attribute.getName()); } @@ -156,7 +147,8 @@ public Void accept(ArrayAttribute attribute) { @Override public Void accept(MapAttribute attribute) { - if (!Objects.isNull(attribute.getKeyAttribute()) || !Objects.isNull(attribute.getValueAttribute())) { + if (Objects.nonNull(attribute.getKeyAttribute()) || Objects.nonNull(attribute.getValueAttribute())) { + // Provided Map, expected Map context.addViolation(String.format("Missing Type Arguments, expected parameterized Types key:%s value:%s", attribute.getKeyAttribute().getType(), attribute.getValueAttribute().getType()), attribute.getName()); } @@ -165,7 +157,9 @@ public Void accept(MapAttribute attribute) { @Override public Void accept(ObjectAttribute attribute) { - valid(validationType, attribute.getNestedAttributes(), klass, context); + if (Objects.nonNull(attribute.getNestedAttributes())) { + valid(validationType, attribute.getNestedAttributes(), klass, context); + } return null; } }); @@ -189,7 +183,7 @@ private void valid(final SchemaValidationType validationType, valid(validationType, mapAttribute.getKeyAttribute(), typeArguments[0], context); valid(validationType, mapAttribute.getValueAttribute(), typeArguments[1], context); } else { - context.addViolation(String.format(TYPE_VIOLATION, attribute.getType(), parameterizedType), attribute.getName()); + context.addViolation(String.format(TYPE_MISMATCH_MESSAGE, attribute.getType(), parameterizedType), attribute.getName()); } } @@ -201,7 +195,7 @@ private void valid(final SchemaValidationType validationType, valid(validationType, arrayAttribute.getElementAttribute(), arrayType.getGenericComponentType(), context); return; } - context.addViolation(String.format(TYPE_VIOLATION, attribute.getType(), arrayType), attribute.getName()); + context.addViolation(String.format(TYPE_MISMATCH_MESSAGE, attribute.getType(), arrayType), attribute.getName()); } private boolean isMatchingType(final Class klass, @@ -214,7 +208,7 @@ public Boolean accept(ArrayAttribute attribute) { @Override public Boolean accept(ObjectAttribute attribute) { - if (klass.equals(Object.class) && !Objects.isNull(attribute.getNestedAttributes())) { + if (klass.equals(Object.class) && Objects.nonNull(attribute.getNestedAttributes())) { return false; } return true; diff --git a/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolation.java b/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolation.java index 532bbd9..182ace2 100644 --- a/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolation.java +++ b/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolation.java @@ -1,9 +1,19 @@ package com.grookage.leia.common.violation; public interface LeiaSchemaViolation { + + /** + * @return Error message for the violation + */ String message(); + /** + * @return Relative path of the field being validated from the {@code rootKlass} + */ String fieldPath(); + /** + * @return Class of the field being validated + */ Class rootKlass(); } diff --git a/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolationImpl.java b/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolationImpl.java index e75f9de..f774ab6 100644 --- a/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolationImpl.java +++ b/leia-common/src/main/java/com/grookage/leia/common/violation/LeiaSchemaViolationImpl.java @@ -1,6 +1,7 @@ package com.grookage.leia.common.violation; import com.google.common.base.Joiner; +import com.google.common.base.Strings; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -31,8 +32,10 @@ public Class rootKlass() { } public String toString() { - return Joiner.on(":") - .skipNulls() - .join(rootKlass, fieldPath, message); + if (Strings.isNullOrEmpty(fieldPath)) { + return String.format("[LeiaSchemaViolation] %s, message = %s", rootKlass, message); + } + return String.format("[LeiaSchemaViolation] %s, fieldPath = %s, message = %s", rootKlass, + fieldPath, message); } } diff --git a/leia-common/src/test/java/com/grookage/leia/common/utils/SchemaValidationUtilsTest.java b/leia-common/src/test/java/com/grookage/leia/common/utils/SchemaValidationUtilsTest.java index 51d76d8..a1fdd40 100644 --- a/leia-common/src/test/java/com/grookage/leia/common/utils/SchemaValidationUtilsTest.java +++ b/leia-common/src/test/java/com/grookage/leia/common/utils/SchemaValidationUtilsTest.java @@ -1,6 +1,8 @@ package com.grookage.leia.common.utils; import com.grookage.leia.common.exception.ValidationErrorCode; +import com.grookage.leia.common.stubs.NestedStub; +import com.grookage.leia.common.stubs.PIIData; import com.grookage.leia.common.violation.ViolationContext; import com.grookage.leia.models.ResourceHelper; import com.grookage.leia.models.attributes.ArrayAttribute; @@ -108,14 +110,14 @@ void testParametrizedArray() { @Test void testRawArray() { final var arrayAttribute = new ArrayAttribute("arrayAttribute", true, null, null); -// Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, -// Set.of(arrayAttribute), RawSetTestClass.class, new ViolationContext()).isEmpty()); + Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, + Set.of(arrayAttribute), RawSetTestClass.class, new ViolationContext()).isEmpty()); Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(arrayAttribute), SetTestClass.class, new ViolationContext()).isEmpty()); -// Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, -// Set.of(arrayAttribute), ListTestClass.class, new ViolationContext()).isEmpty()); -// Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, -// Set.of(arrayAttribute), ArrayTestClass.class, new ViolationContext()).isEmpty()); + Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, + Set.of(arrayAttribute), ListTestClass.class, new ViolationContext()).isEmpty()); + Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, + Set.of(arrayAttribute), ArrayTestClass.class, new ViolationContext()).isEmpty()); } @Test @@ -161,6 +163,23 @@ void testGenericArrayType() { GenericArrayTestClass.class, new ViolationContext()).isEmpty()); } + @SneakyThrows + @Test + void testInvalidNestedStubSchema() { + final var schemaDetails = ResourceHelper.getResource("invalidNestedStubSchema.json", SchemaDetails.class); + final var violations = SchemaValidationUtils.valid(schemaDetails, NestedStub.class); + Assertions.assertFalse(violations.isEmpty()); + Assertions.assertEquals(4, violations.size()); + final var nestedStubViolations = violations.stream() + .filter(leiaSchemaViolation -> leiaSchemaViolation.rootKlass().equals(NestedStub.class)) + .toList(); + Assertions.assertEquals(3, nestedStubViolations.size()); + final var piiDataViolations = violations.stream() + .filter(leiaSchemaViolation -> leiaSchemaViolation.rootKlass().equals(PIIData.class)) + .toList(); + Assertions.assertEquals(1, piiDataViolations.size()); + } + enum TestEnum { TEST_ENUM } diff --git a/leia-common/src/test/resources/invalidNestedStubSchema.json b/leia-common/src/test/resources/invalidNestedStubSchema.json new file mode 100644 index 0000000..d6f5b5e --- /dev/null +++ b/leia-common/src/test/resources/invalidNestedStubSchema.json @@ -0,0 +1,92 @@ +{ + "namespace": "testNamespace", + "schemaName": "NestedStub", + "version": "V1234", + "schemaState": "CREATED", + "schemaType": "JSON", + "validationType": "STRICT", + "schemaMeta": { + "createdBy": "testUser" + }, + "attributes": [ + { + "type": "INTEGER", + "name": "phoneNumber", + "optional": false, + "qualifiers": [ + { + "type": "PII" + } + ] + }, + { + "type": "OBJECT", + "name": "piiData", + "optional": false, + "qualifiers": [ + { + "type": "ENCRYPTED" + }, + { + "type": "PII" + } + ], + "nestedAttributes": [ + { + "type": "STRING", + "name": "accountNumber", + "optional": false, + "qualifiers": [ + { + "type": "ENCRYPTED" + } + ] + } + ] + }, + { + "type": "LONG", + "name": "id", + "optional": false, + "qualifiers": [] + }, + { + "type": "ENUM", + "name": "enumClass", + "optional": false, + "qualifiers": [], + "values": [ + "ONE", + "TWO" + ] + }, + { + "type": "OBJECT", + "name": "recordStub", + "optional": false, + "qualifiers": [ + { + "type": "ENCRYPTED" + } + ], + "nestedAttributes": [ + { + "type": "INTEGER", + "name": "id", + "optional": true, + "qualifiers": [] + }, + { + "type": "STRING", + "name": "name", + "optional": false, + "qualifiers": [ + { + "type": "PII" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/leia-schema-validator/pom.xml b/leia-schema-validator/pom.xml index 6835674..98db477 100644 --- a/leia-schema-validator/pom.xml +++ b/leia-schema-validator/pom.xml @@ -56,6 +56,17 @@ commons-lang3 ${lang3.version} + + com.grookage.leia + leia-models + test-jar + + + * + * + + + diff --git a/leia-schema-validator/src/main/java/com/grookage/leia/validator/StaticSchemaValidator.java b/leia-schema-validator/src/main/java/com/grookage/leia/validator/StaticSchemaValidator.java index 92bdd16..040df77 100644 --- a/leia-schema-validator/src/main/java/com/grookage/leia/validator/StaticSchemaValidator.java +++ b/leia-schema-validator/src/main/java/com/grookage/leia/validator/StaticSchemaValidator.java @@ -56,7 +56,8 @@ private List validate(final SchemaKey schemaKey, Class k final var details = supplier.get().stream() .filter(each -> each.match(schemaKey)).findFirst().orElse(null); if (null == details) { - throw SchemaValidationException.error(ValidationErrorCode.NO_SCHEMA_FOUND); + throw SchemaValidationException.error(ValidationErrorCode.NO_SCHEMA_FOUND, + String.format("No schema found with key: %s", schemaKey.getReferenceId())); } return SchemaValidationUtils.valid(details, klass); } @@ -85,7 +86,10 @@ public void start() { }); if (!violations.isEmpty()) { log.error("Found invalid schemas. Please fix the following schemas to start the bundle {}", violations); - throw SchemaValidationException.error(ValidationErrorCode.INVALID_SCHEMAS); + throw SchemaValidationException.builder() + .errorCode(ValidationErrorCode.INVALID_SCHEMAS) + .context(Map.of("schemaViolations", violations)) + .build(); } } diff --git a/leia-schema-validator/src/test/java/com/grookage/leia/validator/StaticSchemaValidatorTest.java b/leia-schema-validator/src/test/java/com/grookage/leia/validator/StaticSchemaValidatorTest.java new file mode 100644 index 0000000..7d29d83 --- /dev/null +++ b/leia-schema-validator/src/test/java/com/grookage/leia/validator/StaticSchemaValidatorTest.java @@ -0,0 +1,95 @@ +package com.grookage.leia.validator; + +import com.grookage.leia.common.builder.SchemaBuilder; +import com.grookage.leia.common.exception.SchemaValidationException; +import com.grookage.leia.common.exception.ValidationErrorCode; +import com.grookage.leia.models.ResourceHelper; +import com.grookage.leia.models.annotations.SchemaDefinition; +import com.grookage.leia.models.schema.SchemaDetails; +import com.grookage.leia.models.schema.SchemaKey; +import com.grookage.leia.models.schema.SchemaMeta; +import com.grookage.leia.models.schema.engine.SchemaState; +import com.grookage.leia.validator.stubs.TestNestedRecordStub; +import com.grookage.leia.validator.stubs.TestRecordStub; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Set; + +class StaticSchemaValidatorTest { + private static final String PACKAGE = "com.grookage.leia.validator.stubs"; + + @Test + void testSchemaValidator() { + final var recordStubDetails = toSchemaDetails(TestRecordStub.class); + final var nestedStubDetails = toSchemaDetails(TestNestedRecordStub.class); + final var schemaValidator = StaticSchemaValidator.builder() + .packageRoots(Set.of(PACKAGE)) + .supplier(() -> List.of(recordStubDetails, nestedStubDetails)) + .build(); + Assertions.assertDoesNotThrow(schemaValidator::start); + Assertions.assertTrue(schemaValidator.valid(schemaKey(TestRecordStub.class))); + Assertions.assertTrue(schemaValidator.valid(schemaKey(TestNestedRecordStub.class))); + } + + @Test + void testSchemaValidator_withMissingSchemaDetails() { + final var recordStubDetails = toSchemaDetails(TestRecordStub.class); + final var schemaValidator = StaticSchemaValidator.builder() + .packageRoots(Set.of(PACKAGE)) + .supplier(() -> List.of(recordStubDetails)) + .build(); + final var schemaValidationException = Assertions.assertThrows(SchemaValidationException.class, schemaValidator::start); + Assertions.assertEquals(ValidationErrorCode.NO_SCHEMA_FOUND.name(), schemaValidationException.getCode()); + } + + @SneakyThrows + @Test + void testSchemaValidator_withInvalidSchema() { + final var recordStubDetails = ResourceHelper.getResource("InvalidRecordStubSchema.json", SchemaDetails.class); + final var nestedStubDetails = ResourceHelper.getResource("InvalidNestedRecordStubSchema.json", SchemaDetails.class); + final var schemaValidator = StaticSchemaValidator.builder() + .packageRoots(Set.of(PACKAGE)) + .supplier(() -> List.of(recordStubDetails, nestedStubDetails)) + .build(); + final var schemaValidationException = Assertions.assertThrows(SchemaValidationException.class, schemaValidator::start); + Assertions.assertEquals(ValidationErrorCode.INVALID_SCHEMAS.name(), schemaValidationException.getCode()); + Assertions.assertFalse(schemaValidator.valid(schemaKey(TestRecordStub.class))); + Assertions.assertFalse(schemaValidator.valid(schemaKey(TestNestedRecordStub.class))); + } + + + private SchemaDetails toSchemaDetails(final Class schemaKlass) { + final var schemaDefinition = schemaKlass.getAnnotation(SchemaDefinition.class); + final var createSchemaRequest = SchemaBuilder.buildSchemaRequest(schemaKlass) + .orElse(null); + Assertions.assertNotNull(createSchemaRequest); + return SchemaDetails.builder() + .namespace(schemaDefinition.namespace()) + .schemaName(schemaDefinition.name()) + .version(schemaDefinition.version()) + .schemaState(SchemaState.CREATED) + .schemaType(createSchemaRequest.getSchemaType()) + .description(createSchemaRequest.getDescription()) + .attributes(createSchemaRequest.getAttributes()) + .schemaMeta(SchemaMeta.builder() + .createdBy("testUser") + .createdByEmail("testEmail") + .createdAt(System.currentTimeMillis()) + .build()) + .validationType(createSchemaRequest.getValidationType()) + .transformationTargets(createSchemaRequest.getTransformationTargets()) + .build(); + } + + private SchemaKey schemaKey(final Class schemaKlass) { + final var schemaDefinition = schemaKlass.getAnnotation(SchemaDefinition.class); + return SchemaKey.builder() + .schemaName(schemaDefinition.name()) + .namespace(schemaDefinition.namespace()) + .version(schemaDefinition.version()) + .build(); + } +} \ No newline at end of file diff --git a/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestData.java b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestData.java new file mode 100644 index 0000000..35c6197 --- /dev/null +++ b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestData.java @@ -0,0 +1,17 @@ +package com.grookage.leia.validator.stubs; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TestData { + int id; + String name; + Object object; + TestEnum testEnum; +} diff --git a/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestEnum.java b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestEnum.java new file mode 100644 index 0000000..99b66b0 --- /dev/null +++ b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestEnum.java @@ -0,0 +1,6 @@ +package com.grookage.leia.validator.stubs; + +public enum TestEnum { + ONE, + TWO; +} diff --git a/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestNestedRecordStub.java b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestNestedRecordStub.java new file mode 100644 index 0000000..9cfaf51 --- /dev/null +++ b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestNestedRecordStub.java @@ -0,0 +1,35 @@ +package com.grookage.leia.validator.stubs; + +import com.grookage.leia.models.annotations.SchemaDefinition; +import com.grookage.leia.models.annotations.attribute.Optional; +import com.grookage.leia.models.annotations.attribute.qualifiers.Encrypted; +import com.grookage.leia.models.annotations.attribute.qualifiers.PII; +import com.grookage.leia.models.schema.SchemaType; +import com.grookage.leia.models.schema.SchemaValidationType; + +import java.util.List; +import java.util.Map; + +@SchemaDefinition( + name = TestNestedRecordStub.NAME, + namespace = TestNestedRecordStub.NAMESPACE, + version = TestNestedRecordStub.VERSION, + description = TestNestedRecordStub.DESCRIPTION, + type = SchemaType.JSON, + validation = SchemaValidationType.STRICT +) +public class TestNestedRecordStub { + static final String NAME = "TEST_NESTED_RECORD"; + static final String NAMESPACE = "test"; + static final String VERSION = "v1"; + static final String DESCRIPTION = "Test Nested Record"; + + @PII + @Encrypted + String accountNumber; + @Optional + String accountId; + TestData testData; + Map enumTestDataMap; + List strings; +} diff --git a/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestRecordStub.java b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestRecordStub.java new file mode 100644 index 0000000..bf48ce8 --- /dev/null +++ b/leia-schema-validator/src/test/java/com/grookage/leia/validator/stubs/TestRecordStub.java @@ -0,0 +1,32 @@ +package com.grookage.leia.validator.stubs; + +import com.grookage.leia.models.annotations.SchemaDefinition; +import com.grookage.leia.models.annotations.attribute.Optional; +import com.grookage.leia.models.annotations.attribute.qualifiers.Encrypted; +import com.grookage.leia.models.annotations.attribute.qualifiers.PII; +import com.grookage.leia.models.schema.SchemaType; +import com.grookage.leia.models.schema.SchemaValidationType; + +@SchemaDefinition( + name = TestRecordStub.NAME, + namespace = TestRecordStub.NAMESPACE, + version = TestRecordStub.VERSION, + description = TestRecordStub.DESCRIPTION, + type = SchemaType.JSON, + validation = SchemaValidationType.STRICT +) +public class TestRecordStub { + static final String NAME = "TEST_RECORD"; + static final String NAMESPACE = "test"; + static final String VERSION = "v1"; + static final String DESCRIPTION = "Test Record"; + + int id; + String name; + @PII + @Encrypted + String accountNumber; + long ttl; + @Optional + String accountId; +} diff --git a/leia-schema-validator/src/test/resources/InvalidNestedRecordStubSchema.json b/leia-schema-validator/src/test/resources/InvalidNestedRecordStubSchema.json new file mode 100644 index 0000000..ab5e9cf --- /dev/null +++ b/leia-schema-validator/src/test/resources/InvalidNestedRecordStubSchema.json @@ -0,0 +1,113 @@ +{ + "namespace" : "test", + "schemaName" : "TEST_NESTED_RECORD", + "version" : "v1", + "description" : "Test Nested Record", + "schemaState" : "CREATED", + "schemaType" : "JSON", + "validationType" : "STRICT", + "schemaMeta" : { + "createdBy" : "testUser", + "createdByEmail" : "testEmail", + "createdAt" : 1733897687017, + "updatedBy" : null, + "updatedByEmail" : null, + "updatedAt" : 0 + }, + "attributes" : [ { + "type" : "OBJECT", + "name" : "testData", + "optional" : false, + "qualifiers" : [ ], + "nestedAttributes" : [ { + "type" : "OBJECT", + "name" : "object", + "optional" : false, + "qualifiers" : [ ], + "nestedAttributes" : null + }, { + "type" : "STRING", + "name" : "accountName", + "optional" : false, + "qualifiers" : [ ] + }, { + "type" : "LONG", + "name" : "id", + "optional" : false, + "qualifiers" : [ ] + }, { + "type" : "ENUM", + "name" : "testEnum", + "optional" : false, + "qualifiers" : [ ], + "values" : [ "ONE", "TWO" ] + } ] + }, { + "type" : "STRING", + "name" : "accountNumber", + "optional" : false, + "qualifiers" : [ { + "type" : "ENCRYPTED" + }, { + "type" : "PII" + } ] + }, { + "type" : "ARRAY", + "name" : "strings", + "optional" : false, + "qualifiers" : [ ], + "elementAttribute" : { + "type" : "STRING", + "name" : "element", + "optional" : false, + "qualifiers" : [ ] + } + }, { + "type" : "STRING", + "name" : "accountId", + "optional" : true, + "qualifiers" : [ ] + }, { + "type" : "MAP", + "name" : "enumTestDataMap", + "optional" : false, + "qualifiers" : [ ], + "keyAttribute" : { + "type" : "STRING", + "name" : "key", + "optional" : false, + "qualifiers" : [ ], + "values" : [ "ONE", "TWO" ] + }, + "valueAttribute" : { + "type" : "OBJECT", + "name" : "value", + "optional" : false, + "qualifiers" : [ ], + "nestedAttributes" : [ { + "type" : "OBJECT", + "name" : "object", + "optional" : false, + "qualifiers" : [ ], + "nestedAttributes" : null + }, { + "type" : "STRING", + "name" : "name", + "optional" : false, + "qualifiers" : [ ] + }, { + "type" : "LONG", + "name" : "id", + "optional" : false, + "qualifiers" : [ ] + }, { + "type" : "ENUM", + "name" : "testEnum", + "optional" : false, + "qualifiers" : [ ], + "values" : [ "ONE", "TWO" ] + } ] + } + } ], + "transformationTargets" : [ ] +} \ No newline at end of file diff --git a/leia-schema-validator/src/test/resources/InvalidRecordStubSchema.json b/leia-schema-validator/src/test/resources/InvalidRecordStubSchema.json new file mode 100644 index 0000000..23ec7c1 --- /dev/null +++ b/leia-schema-validator/src/test/resources/InvalidRecordStubSchema.json @@ -0,0 +1,43 @@ +{ + "namespace" : "test", + "schemaName" : "TEST_RECORD", + "version" : "v1", + "description" : "Test Record", + "schemaState" : "CREATED", + "schemaType" : "JSON", + "validationType" : "STRICT", + "schemaMeta" : { + "createdBy" : "testUser", + "createdByEmail" : "testEmail", + "createdAt" : 1733897544626, + "updatedBy" : null, + "updatedByEmail" : null, + "updatedAt" : 0 + }, + "attributes" : [ { + "type" : "INTEGER", + "name" : "ttl", + "optional" : false, + "qualifiers" : [ ] + }, { + "type" : "STRING", + "name" : "accountNumber", + "optional" : false, + "qualifiers" : [ { + "type" : "ENCRYPTED" + }, { + "type" : "PII" + } ] + }, { + "type" : "STRING", + "name" : "accountId", + "optional" : true, + "qualifiers" : [ ] + }, { + "type" : "LONG", + "name" : "id", + "optional" : false, + "qualifiers" : [ ] + } ], + "transformationTargets" : [ ] +} \ No newline at end of file