From 4649ca7f39407cf7d8c395ed92bd3e3320d64d64 Mon Sep 17 00:00:00 2001 From: John Joyce Date: Wed, 4 Aug 2021 22:23:16 -0700 Subject: [PATCH] fix(gms): Validate unrecognized model fields. (#3034) --- .../metadata/resources/ResourceUtils.java | 9 +++- .../metadata/resources/ResourceUtilsTest.java | 47 +++++++++++++++++++ .../metadata/extractor/AspectExtractor.java | 3 ++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 gms/impl/src/test/java/com/linkedin/metadata/resources/ResourceUtilsTest.java diff --git a/gms/impl/src/main/java/com/linkedin/metadata/resources/ResourceUtils.java b/gms/impl/src/main/java/com/linkedin/metadata/resources/ResourceUtils.java index d4679a910b..8257bb230b 100644 --- a/gms/impl/src/main/java/com/linkedin/metadata/resources/ResourceUtils.java +++ b/gms/impl/src/main/java/com/linkedin/metadata/resources/ResourceUtils.java @@ -1,6 +1,9 @@ package com.linkedin.metadata.resources; import com.linkedin.common.urn.UrnValidator; +import com.linkedin.data.schema.validation.CoercionMode; +import com.linkedin.data.schema.validation.RequiredMode; +import com.linkedin.data.schema.validation.UnrecognizedFieldMode; import com.linkedin.data.schema.validation.ValidateDataAgainstSchema; import com.linkedin.data.schema.validation.ValidationOptions; import com.linkedin.data.schema.validation.ValidationResult; @@ -13,7 +16,11 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class ResourceUtils { - private static final ValidationOptions DEFAULT_VALIDATION_OPTIONS = new ValidationOptions(); + private static final ValidationOptions DEFAULT_VALIDATION_OPTIONS = new ValidationOptions( + RequiredMode.CAN_BE_ABSENT_IF_HAS_DEFAULT, + CoercionMode.NORMAL, + UnrecognizedFieldMode.DISALLOW + ); private static final UrnValidator URN_VALIDATOR = new UrnValidator(); /** diff --git a/gms/impl/src/test/java/com/linkedin/metadata/resources/ResourceUtilsTest.java b/gms/impl/src/test/java/com/linkedin/metadata/resources/ResourceUtilsTest.java new file mode 100644 index 0000000000..76914ba422 --- /dev/null +++ b/gms/impl/src/test/java/com/linkedin/metadata/resources/ResourceUtilsTest.java @@ -0,0 +1,47 @@ +package com.linkedin.metadata.resources; + +import com.linkedin.common.BrowsePath; +import com.linkedin.common.Owner; +import com.linkedin.common.OwnershipType; +import com.linkedin.common.Status; +import com.linkedin.common.urn.Urn; +import com.linkedin.data.DataMap; +import com.linkedin.restli.common.HttpStatus; +import com.linkedin.restli.server.RestLiServiceException; +import org.testng.annotations.Test; +import org.testng.Assert; + + +public class ResourceUtilsTest { + @Test + public void testValidateOrThrowThrowsOnMissingUnrecognizedField() { + DataMap rawMap = new DataMap(); + rawMap.put("removed", true); + rawMap.put("extraField", 1); + Status status = new Status(rawMap); + Assert.assertThrows(RestLiServiceException.class, () -> ResourceUtils.validateOrThrow(status, HttpStatus.S_500_INTERNAL_SERVER_ERROR)); + } + + @Test + public void testValidateOrThrowThrowsOnMissingRequiredField() { + DataMap rawMap = new DataMap(); + BrowsePath status = new BrowsePath(rawMap); + Assert.assertThrows(RestLiServiceException.class, () -> ResourceUtils.validateOrThrow(status, HttpStatus.S_500_INTERNAL_SERVER_ERROR)); + } + + @Test + public void testValidateOrThrowDoesNotThrowOnMissingOptionalField() throws Exception { + DataMap rawMap = new DataMap(); + Owner owner = new Owner(rawMap); + owner.setOwner(Urn.createFromString("urn:li:corpuser:test")); + owner.setType(OwnershipType.DATAOWNER); + ResourceUtils.validateOrThrow(owner, HttpStatus.S_500_INTERNAL_SERVER_ERROR); + } + + @Test + public void testValidateOrThrowDoesNotThrowOnMissingDefaultField() { + DataMap rawMap = new DataMap(); + Status status = new Status(rawMap); + ResourceUtils.validateOrThrow(status, HttpStatus.S_500_INTERNAL_SERVER_ERROR); + } +} diff --git a/metadata-io/src/main/java/com/linkedin/metadata/extractor/AspectExtractor.java b/metadata-io/src/main/java/com/linkedin/metadata/extractor/AspectExtractor.java index 4fa289c6bf..61180cd059 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/extractor/AspectExtractor.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/extractor/AspectExtractor.java @@ -33,6 +33,9 @@ public class AspectExtractor { final Map aspectsByName = new HashMap<>(); for (DataElement dataElement = iterator.next(); dataElement != null; dataElement = iterator.next()) { + if (dataElement.getSchemaPathSpec() == null) { + continue; + } final PathSpec pathSpec = dataElement.getSchemaPathSpec(); List pathComponents = pathSpec.getPathComponents(); // three components representing /aspect/*/