Skip to content

Commit

Permalink
Merge pull request #14 from abhigun/schema_violations
Browse files Browse the repository at this point in the history
Schema Violations and Marshaller bug fix
  • Loading branch information
koushikr authored Dec 11, 2024
2 parents 616861f + 71734d2 commit dcbcefd
Show file tree
Hide file tree
Showing 31 changed files with 757 additions and 155 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All notable changes to this project will be documented in this file.


## [0.0.1-RC10]

- LeiaSchemaViolation
- Introduced SchemaViolation & ViolationContext for generating violations as part of schema validation
- SchemaValidationUtils: Returns list of LeiaSchemaViolations instead of boolean
- StaticSchemaValidator: Updated to return all schema validation violations instead of stopping at the first error occurrence
- LeiaClientMarshaller: Bug fix in serialization
- Adds tests for `leia-schema-validator` module

## [0.0.1-RC9]

- RollOverAndUpdate
Expand Down
2 changes: 1 addition & 1 deletion leia-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>com.grookage.leia</groupId>
<artifactId>leia</artifactId>
<version>0.0.1-RC9</version>
<version>0.0.1-RC10</version>
</parent>

<artifactId>leia-bom</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion leia-client-dropwizard/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>com.grookage.leia</groupId>
<artifactId>leia-parent</artifactId>
<version>0.0.1-RC9</version>
<version>0.0.1-RC10</version>
<relativePath>../leia-parent</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion leia-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>com.grookage.leia</groupId>
<artifactId>leia-parent</artifactId>
<version>0.0.1-RC9</version>
<version>0.0.1-RC10</version>
<relativePath>../leia-parent</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.grookage.leia.models.utils.MapperUtils;
import com.grookage.leia.provider.marshal.Marshaller;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;

import java.util.List;

Expand All @@ -30,9 +31,10 @@ public static LeiaClientMarshaller getInstance() {
return new LeiaClientMarshaller();
}

@SneakyThrows
@Override
public List<SchemaDetails> marshall(byte[] body) {
return MapperUtils.mapper().convertValue(body, new TypeReference<>() {
return MapperUtils.mapper().readValue(body, new TypeReference<>() {
});
}
}
2 changes: 1 addition & 1 deletion leia-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<parent>
<groupId>com.grookage.leia</groupId>
<artifactId>leia-parent</artifactId>
<version>0.0.1-RC9</version>
<version>0.0.1-RC10</version>
<relativePath>../leia-parent</relativePath>
</parent>

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private void validateMapAttribute(final JsonNode fieldNode,
final var keyNode = entry.getKey() != null
? MapperUtils.mapper().convertValue(entry.getKey(), JsonNode.class)
: null;
if (!Objects.isNull(keyNode)) {
if (Objects.nonNull(keyNode)) {
// validate Key
validateField(keyNode, mapAttribute.getKeyAttribute(), schemaValidationType, validationErrors);
// Validate value
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +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();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class LeiaSchemaViolationImpl implements LeiaSchemaViolation {
private String message;
private String fieldPath;
private Class<?> rootKlass;

@Override
public String message() {
return message;
}

@Override
public String fieldPath() {
return fieldPath;
}

@Override
public Class<?> rootKlass() {
return rootKlass;
}

public String toString() {
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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.grookage.leia.common.violation;

import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@Data
@Builder
@NoArgsConstructor
public class ViolationContext {
@Getter
private final List<LeiaSchemaViolation> violations = new ArrayList<>();
private final LinkedList<Class<?>> klassPath = new LinkedList<>();

public void addViolation(final String message) {
violations.add(new LeiaSchemaViolationImpl(message, null, klassPath.peekLast()));
}

public void addViolation(final String message,
final String path) {
violations.add(new LeiaSchemaViolationImpl(message, path, klassPath.peekLast()));
}

public void pushClass(final Class<?> klass) {
klassPath.addLast(klass);
}

public void popClass() {
if (!klassPath.isEmpty()) {
klassPath.removeLast();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
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.*;
import com.grookage.leia.models.attributes.ArrayAttribute;
import com.grookage.leia.models.attributes.BooleanAttribute;
import com.grookage.leia.models.attributes.ByteAttribute;
import com.grookage.leia.models.attributes.DoubleAttribute;
import com.grookage.leia.models.attributes.EnumAttribute;
import com.grookage.leia.models.attributes.FloatAttribute;
import com.grookage.leia.models.attributes.IntegerAttribute;
import com.grookage.leia.models.attributes.LongAttribute;
import com.grookage.leia.models.attributes.MapAttribute;
import com.grookage.leia.models.attributes.ObjectAttribute;
import com.grookage.leia.models.attributes.StringAttribute;
import com.grookage.leia.models.schema.SchemaDetails;
import com.grookage.leia.models.schema.SchemaValidationType;
import lombok.SneakyThrows;
Expand All @@ -21,9 +34,9 @@ void testSchemaValidator() {
final var schemaDetails = ResourceHelper
.getResource("validSchema.json", SchemaDetails.class);
Assertions.assertNotNull(schemaDetails);
Assertions.assertTrue(SchemaValidationUtils.valid(schemaDetails, ValidTestClass.class));
Assertions.assertTrue(SchemaValidationUtils.valid(schemaDetails, ValidTestClass.class).isEmpty());
schemaDetails.setValidationType(SchemaValidationType.STRICT);
Assertions.assertFalse(SchemaValidationUtils.valid(schemaDetails, ValidTestClass.class));
Assertions.assertFalse(SchemaValidationUtils.valid(schemaDetails, ValidTestClass.class).isEmpty());
}

@Test
Expand All @@ -33,7 +46,7 @@ void testInvalidMatchingSchema() {
.getResource("validSchema.json", SchemaDetails.class);
schemaDetails.setValidationType(SchemaValidationType.MATCHING);
Assertions.assertNotNull(schemaDetails);
Assertions.assertFalse(SchemaValidationUtils.valid(schemaDetails, InvalidTestClass.class));
Assertions.assertFalse(SchemaValidationUtils.valid(schemaDetails, InvalidTestClass.class).isEmpty());
}

@Test
Expand Down Expand Up @@ -85,26 +98,26 @@ void testParametrizedArray() {
final var stringAttribute = new StringAttribute("stringAttribute", true, null);
final var arrayAttribute = new ArrayAttribute("arrayAttribute", true, null, stringAttribute);
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(arrayAttribute),
SetTestClass.class));
SetTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(arrayAttribute),
ListTestClass.class));
ListTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(arrayAttribute),
ArrayTestClass.class));
ArrayTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertFalse(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(arrayAttribute),
RawSetTestClass.class));
RawSetTestClass.class, new ViolationContext()).isEmpty());
}

@Test
void testRawArray() {
final var arrayAttribute = new ArrayAttribute("arrayAttribute", true, null, null);
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING,
Set.of(arrayAttribute), RawSetTestClass.class));
Set.of(arrayAttribute), RawSetTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING,
Set.of(arrayAttribute), SetTestClass.class));
Set.of(arrayAttribute), SetTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING,
Set.of(arrayAttribute), ListTestClass.class));
Set.of(arrayAttribute), ListTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING,
Set.of(arrayAttribute), ArrayTestClass.class));
Set.of(arrayAttribute), ArrayTestClass.class, new ViolationContext()).isEmpty());
}

@Test
Expand All @@ -113,22 +126,22 @@ void testParametrizedMap() {
final var valueAttribute = new StringAttribute("valueAttribute", true, null);
final var mapAttribute = new MapAttribute("mapAttribute", true, null, keyAttribute, valueAttribute);
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(mapAttribute),
MapTestClass.class));
MapTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(mapAttribute),
ConcurrentMapTestClass.class));
ConcurrentMapTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertFalse(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(mapAttribute),
RawMapTestClass.class));
RawMapTestClass.class, new ViolationContext()).isEmpty());
}

@Test
void testRawMap() {
final var mapAttribute = new MapAttribute("mapAttribute", true, null, null, null);
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(mapAttribute),
RawMapTestClass.class));
RawMapTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(mapAttribute),
MapTestClass.class));
MapTestClass.class, new ViolationContext()).isEmpty());
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(mapAttribute),
ConcurrentMapTestClass.class));
ConcurrentMapTestClass.class, new ViolationContext()).isEmpty());
}

@Test
Expand All @@ -137,8 +150,8 @@ void testNestedObject() {
final var schemaDetails = ResourceHelper
.getResource("validNestedSchema.json", SchemaDetails.class);
schemaDetails.setValidationType(SchemaValidationType.MATCHING);
Assertions.assertTrue(SchemaValidationUtils.valid(schemaDetails, ValidObjectTestClass.class));
Assertions.assertFalse(SchemaValidationUtils.valid(schemaDetails, InvalidObjectTestClass.class));
Assertions.assertTrue(SchemaValidationUtils.valid(schemaDetails, ValidObjectTestClass.class).isEmpty());
Assertions.assertFalse(SchemaValidationUtils.valid(schemaDetails, InvalidObjectTestClass.class).isEmpty());
}

@Test
Expand All @@ -147,7 +160,24 @@ void testGenericArrayType() {
final var listAttribute = new ArrayAttribute("listAttribute", true, null, stringAttribute);
final var arrayAttribute = new ArrayAttribute("arrayAttribute", true, null, listAttribute);
Assertions.assertTrue(SchemaValidationUtils.valid(SchemaValidationType.MATCHING, Set.of(arrayAttribute),
GenericArrayTestClass.class));
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 {
Expand Down
Loading

0 comments on commit dcbcefd

Please sign in to comment.