Search in sources :

Example 1 with AnnotationCompatibilityResult

use of com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult in project rest.li by linkedin.

the class TestAnnotationCompatibilityChecker method testCheckCompatibility.

@Test(dataProvider = "annotationCompatibilityCheckTestData")
public void testCheckCompatibility(String prevSchemaFile, String currSchemaFile, List<SchemaAnnotationHandler> handlers, List<AnnotationCompatibilityResult> expectedResults) throws IOException {
    DataSchema prevSchema = TestUtil.dataSchemaFromPdlInputStream(getClass().getResourceAsStream(prevSchemaFile));
    DataSchema currSchema = TestUtil.dataSchemaFromPdlInputStream(getClass().getResourceAsStream(currSchemaFile));
    List<AnnotationCompatibilityResult> results = AnnotationCompatibilityChecker.checkPegasusSchemaAnnotation(prevSchema, currSchema, handlers);
    Assert.assertEquals(results.size(), expectedResults.size());
    for (int i = 0; i < results.size(); i++) {
        Assert.assertEquals(results.get(i).getMessages().size(), expectedResults.get(i).getMessages().size());
        List<CompatibilityMessage> actualCompatibilityMessage = (List<CompatibilityMessage>) results.get(i).getMessages();
        List<CompatibilityMessage> expectCompatibilityMessage = (List<CompatibilityMessage>) expectedResults.get(i).getMessages();
        for (int j = 0; j < actualCompatibilityMessage.size(); j++) {
            Assert.assertEquals(actualCompatibilityMessage.get(j).toString(), expectCompatibilityMessage.get(j).toString());
        }
    }
}
Also used : DataSchema(com.linkedin.data.schema.DataSchema) AnnotationCompatibilityResult(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult) List(java.util.List) Test(org.testng.annotations.Test)

Example 2 with AnnotationCompatibilityResult

use of com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult in project rest.li by linkedin.

the class TestAnnotationCompatibilityChecker method annotationCompatibilityCheckTestData.

@DataProvider
private Object[][] annotationCompatibilityCheckTestData() throws IOException {
    // Set up expected result: both previous schema and current schema contain the same PathSpecs.
    CompatibilityCheckContext checkContext = generateAnnotationCheckContext(new PathSpec("TestSchema1/field1/$field"));
    CompatibilityCheckContext checkContext1 = generateAnnotationCheckContext(new PathSpec("TestSchema1/field2/$field"));
    AnnotationCompatibilityResult expectResultWithCompatibleChange1 = generateExpectResult(new CompatibilityMessage(checkContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_COMPATIBLE_CHANGE, "Updating annotation field \"%s\" value is backward compatible change", ANNOTATION_FIELD_NAME));
    AnnotationCompatibilityResult expectResultWithInCompatibleChange1 = generateExpectResult(new CompatibilityMessage(checkContext1.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Deleting existed annotation \"%s\" is backward incompatible change", BAR_ANNOTATION_NAMESPACE));
    // Set up expected result: only previous schema contains the resolvedProperty with the same annotation namespace as SchemaAnnotationHandler
    CompatibilityCheckContext checkContext2 = generateAnnotationCheckContext(new PathSpec("TestSchema2/field1/$field"));
    AnnotationCompatibilityResult expectResult2 = generateExpectResult(new CompatibilityMessage(checkContext2.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Adding new annotation \"%s\" is backward compatible change", BAR_ANNOTATION_NAMESPACE));
    // Set up expected result: only current schema contains the resolvedProperty with the same annotation namespace as SchemaAnnotationHandler
    CompatibilityCheckContext checkContext3 = generateAnnotationCheckContext(new PathSpec("TestSchema3/field1/$field"));
    AnnotationCompatibilityResult expectResult3 = generateExpectResult(new CompatibilityMessage(checkContext3.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Deleting existed annotation \"%s\" is backward incompatible change", BAR_ANNOTATION_NAMESPACE));
    // Set up expected results: multiple handlers.
    CompatibilityCheckContext checkContext4 = generateAnnotationCheckContext(new PathSpec("TestSchema4/field1/$field"));
    AnnotationCompatibilityResult barHandlerExpectResult = generateExpectResult(new CompatibilityMessage(checkContext4.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Adding new annotation \"%s\" is backward compatible change", BAR_ANNOTATION_NAMESPACE));
    AnnotationCompatibilityResult bazHandlerExpectResult = generateExpectResult(new CompatibilityMessage(checkContext4.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_COMPATIBLE_CHANGE, "Updating annotation field \"%s\" value is backward compatible change", ANNOTATION_FIELD_NAME));
    // Set up expected results: field has annotation, field type schema also has annotation.
    AnnotationCompatibilityResult fieldAnnotationResult = new AnnotationCompatibilityResult();
    CompatibilityCheckContext checkContext5 = generateAnnotationCheckContext(new PathSpec("TestSchema5/field1"));
    AnnotationCompatibilityResult fieldTypeSchemaAnnotationResult = generateExpectResult(new CompatibilityMessage(checkContext5.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_COMPATIBLE_CHANGE, "Updating annotation field \"%s\" value is backward compatible change", ANNOTATION_FIELD_NAME));
    // Set up expected results: field has annotation, field type schema also has annotation.
    CompatibilityCheckContext unionMemberKeyCheckContext = generateAnnotationCheckContext(new PathSpec("TestSchema6/field1/u1/$unionMemberKey"));
    AnnotationCompatibilityResult unionMemberKeyAnnotationResult = generateExpectResult(new CompatibilityMessage(unionMemberKeyCheckContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_COMPATIBLE_CHANGE, "Updating annotation field \"%s\" value is backward compatible change", ANNOTATION_FIELD_NAME));
    CompatibilityCheckContext unionMemberSchemaCheckContext = generateAnnotationCheckContext(new PathSpec("TestSchema6/field1/u1"));
    AnnotationCompatibilityResult unionMemberSchemaAnnotationResult = generateExpectResult(new CompatibilityMessage(unionMemberSchemaCheckContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_COMPATIBLE_CHANGE, "Updating annotation field \"%s\" value is backward compatible change", ANNOTATION_FIELD_NAME));
    // Set up expected result: an extension annotation field value is updated.
    CompatibilityCheckContext schoolContext = generateAnnotationCheckContext(new PathSpec("SchoolExtensions/testField/$field"));
    AnnotationCompatibilityResult schoolExtensionExpectResult = generateExpectResult(new CompatibilityMessage(schoolContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Updating extension annotation field: \"%s\" value is considering as a backward incompatible change.", "using"));
    // Set up expected result: an extension annotation field is removed.
    CompatibilityCheckContext fruitContext = generateAnnotationCheckContext(new PathSpec("FruitExtensions/testField/$field"));
    AnnotationCompatibilityResult fruitExtensionExpectResult = generateExpectResult(new CompatibilityMessage(fruitContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Removing extension annotation field: \"%s\" is considering as a backward incompatible change.", "params"));
    // Set up expected result: a new field with annotation is added.
    CompatibilityCheckContext fooContext = generateAnnotationCheckContext(new PathSpec("FooExtensions/barField/$field"));
    AnnotationCompatibilityResult fooExtensionExpectResult = generateExpectResult(new CompatibilityMessage(fooContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_COMPATIBLE_CHANGE, "Adding extension annotation on new field: \"%s\" is backward compatible change", "barField"));
    // Existing fields annotations do not change, checkCompatibility will return an empty result.
    AnnotationCompatibilityResult emptyResult = new AnnotationCompatibilityResult();
    // Set up expected result: an extension annotation is removed.
    CompatibilityCheckContext albumContext = generateAnnotationCheckContext(new PathSpec("AlbumExtensions/testField/$field"));
    AnnotationCompatibilityResult albumExtensionExpectResult = generateExpectResult(new CompatibilityMessage(albumContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Removing extension annotation is a backward incompatible change.", ""));
    // Set up expected result: an extension annotation is removed.
    CompatibilityCheckContext companyContext = generateAnnotationCheckContext(new PathSpec("CompanyExtensions/testField/$field"));
    AnnotationCompatibilityResult companyExtensionExpectResult = generateExpectResult(new CompatibilityMessage(companyContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Adding extension annotation field: \"%s\" is a backward incompatible change.", "using"));
    // Set up expected result: a field with extension annotation is removed.
    CompatibilityCheckContext bookContext = generateAnnotationCheckContext(new PathSpec("BookExtensions/testField/$field"));
    AnnotationCompatibilityResult bookExtensionExpectResult = generateExpectResult(new CompatibilityMessage(bookContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Removing field: \"%s\" with extension annotation is a backward incompatible change.", "testField"));
    // Set up expected result: adding extension annotation on an existing field
    CompatibilityCheckContext jobContext = generateAnnotationCheckContext(new PathSpec("JobExtensions/testField/$field"));
    AnnotationCompatibilityResult jobExtensionExpectResult = generateExpectResult(new CompatibilityMessage(jobContext.getPathSpecToSchema(), CompatibilityMessage.Impact.ANNOTATION_INCOMPATIBLE_CHANGE, "Adding extension annotation on an existing field: \"%s\" is backward incompatible change", "testField"));
    return new Object[][] { { "previousSchema/TestSchema1.pdl", "currentSchema/TestSchema1.pdl", Collections.singletonList(generateSchemaAnnotationHandler(BAR_ANNOTATION_NAMESPACE)), Arrays.asList(expectResultWithCompatibleChange1, expectResultWithInCompatibleChange1) }, { "previousSchema/TestSchema2.pdl", "currentSchema/TestSchema2.pdl", Collections.singletonList(generateSchemaAnnotationHandler(BAR_ANNOTATION_NAMESPACE)), Collections.singletonList(expectResult2) }, { "previousSchema/TestSchema3.pdl", "currentSchema/TestSchema3.pdl", Collections.singletonList(generateSchemaAnnotationHandler(BAR_ANNOTATION_NAMESPACE)), Collections.singletonList(expectResult3) }, { "previousSchema/TestSchema4.pdl", "currentSchema/TestSchema4.pdl", Arrays.asList(generateSchemaAnnotationHandler(BAR_ANNOTATION_NAMESPACE), generateSchemaAnnotationHandler(BAZ_ANNOTATION_NAMESPACE)), Arrays.asList(barHandlerExpectResult, bazHandlerExpectResult) }, { "previousSchema/TestSchema5.pdl", "currentSchema/TestSchema5.pdl", Arrays.asList(generateSchemaAnnotationHandler(BAR_ANNOTATION_NAMESPACE), generateSchemaAnnotationHandler(BAZ_ANNOTATION_NAMESPACE)), Arrays.asList(fieldAnnotationResult, fieldTypeSchemaAnnotationResult) }, { "previousSchema/TestSchema6.pdl", "currentSchema/TestSchema6.pdl", Arrays.asList(generateSchemaAnnotationHandler(BAR_ANNOTATION_NAMESPACE), generateSchemaAnnotationHandler(BAZ_ANNOTATION_NAMESPACE)), Arrays.asList(unionMemberSchemaAnnotationResult, unionMemberKeyAnnotationResult) }, { "previousSchema/SchoolExtensions.pdl", "currentSchema/SchoolExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Collections.singletonList(schoolExtensionExpectResult) }, { "previousSchema/FruitExtensions.pdl", "currentSchema/FruitExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Collections.singletonList(fruitExtensionExpectResult) }, { "previousSchema/FooExtensions.pdl", "currentSchema/FooExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Arrays.asList(emptyResult, fooExtensionExpectResult) }, { "previousSchema/AlbumExtensions.pdl", "currentSchema/AlbumExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Collections.singletonList(albumExtensionExpectResult) }, { "previousSchema/CompanyExtensions.pdl", "currentSchema/CompanyExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Collections.singletonList(companyExtensionExpectResult) }, { "previousSchema/BookExtensions.pdl", "currentSchema/BookExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Arrays.asList(bookExtensionExpectResult, emptyResult) }, { "previousSchema/JobExtensions.pdl", "currentSchema/JobExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Collections.singletonList(jobExtensionExpectResult) }, { "previousSchema/IdentityExtensions.pdl", "currentSchema/IdentityExtensions.pdl", Collections.singletonList(new ExtensionSchemaAnnotationHandler()), Collections.singletonList(emptyResult) } };
}
Also used : ExtensionSchemaAnnotationHandler(com.linkedin.data.schema.annotation.ExtensionSchemaAnnotationHandler) AnnotationCompatibilityResult(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult) CompatibilityCheckContext(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.CompatibilityCheckContext) PathSpec(com.linkedin.data.schema.PathSpec) DataProvider(org.testng.annotations.DataProvider)

Example 3 with AnnotationCompatibilityResult

use of com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult in project rest.li by linkedin.

the class AnnotationCompatibilityChecker method getCompatibilityResult.

/**
 * Iterate the nodeToResolverPropertiesMap, if a node's resolvedProperty contains the same annotationNamespace as SchemaAnnotationHandler,
 * calling annotationCompatibilityCheck api which is provided in the SchemaAnnotationHandler to do the annotation compatibility check.
 */
private static List<AnnotationCompatibilityResult> getCompatibilityResult(Map<PathSpec, Pair<CompatibilityCheckContext, Map<String, Object>>> prevResolvedPropertiesMap, Map<PathSpec, Pair<CompatibilityCheckContext, Map<String, Object>>> currResolvedPropertiesMap, List<SchemaAnnotationHandler> handlers) {
    List<AnnotationCompatibilityResult> results = new ArrayList<>();
    prevResolvedPropertiesMap.forEach((pathSpec, prevCheckContextAndResolvedProperty) -> {
        Map<String, Object> prevResolvedProperties = prevCheckContextAndResolvedProperty.getValue();
        handlers.forEach(handler -> {
            String annotationNamespace = handler.getAnnotationNamespace();
            if (currResolvedPropertiesMap.containsKey(pathSpec)) {
                // If previous schema node and current schema node have the same pathSpec,
                // they may or may not contain the same annotation namespace as SchemaAnnotationHandler, we need to check further.
                Pair<CompatibilityCheckContext, Map<String, Object>> currCheckContextAndResolvedProperty = currResolvedPropertiesMap.get(pathSpec);
                Map<String, Object> currResolvedProperties = currCheckContextAndResolvedProperty.getValue();
                // we do the annotation check.
                if (prevResolvedProperties.containsKey(annotationNamespace) || currResolvedProperties.containsKey(annotationNamespace)) {
                    AnnotationCompatibilityResult result = handler.checkCompatibility(prevResolvedProperties, currResolvedProperties, prevCheckContextAndResolvedProperty.getKey(), currCheckContextAndResolvedProperty.getKey());
                    results.add(result);
                }
            } else {
                if (prevResolvedProperties.containsKey(annotationNamespace)) {
                    // prevResolvedPropertiesMap has a pathSpec which the newResolvedPropertiesMap does not have,
                    // it means an existing field is removed.
                    // pass an empty currResolvedPropertiesMap and empty currAnnotationContext to the annotation check.
                    AnnotationCompatibilityResult result = handler.checkCompatibility(prevResolvedProperties, new HashMap<>(), prevCheckContextAndResolvedProperty.getKey(), new CompatibilityCheckContext());
                    results.add(result);
                }
            }
        });
        if (currResolvedPropertiesMap.containsKey(pathSpec)) {
            currResolvedPropertiesMap.remove(pathSpec);
        }
    });
    currResolvedPropertiesMap.forEach((pathSpec, currCheckContextAndResolvedProperty) -> {
        handlers.forEach(handler -> {
            String annotationNamespace = handler.getAnnotationNamespace();
            Map<String, Object> currResolvedProperties = currCheckContextAndResolvedProperty.getValue();
            if (currResolvedProperties.containsKey(annotationNamespace)) {
                // currResolvedPropertiesMap has a PathSpec which the prevResolvedPropertiesMap does not have,
                // it means there is a new field with new annotations,
                // pass an empty prevResolvedPropertiesMap and empty prevAnnotationContext to the annotation check.
                AnnotationCompatibilityResult result = handler.checkCompatibility(new HashMap<>(), currResolvedProperties, new CompatibilityCheckContext(), currCheckContextAndResolvedProperty.getKey());
                results.add(result);
            }
        });
    });
    return results;
}
Also used : AnnotationCompatibilityResult(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult) ArrayList(java.util.ArrayList) CompatibilityCheckContext(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.CompatibilityCheckContext) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with AnnotationCompatibilityResult

use of com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult in project rest.li by linkedin.

the class TestAnnotationCompatibilityChecker method generateExpectResult.

private AnnotationCompatibilityResult generateExpectResult(CompatibilityMessage compatibilityMessage) {
    SchemaAnnotationHandler.AnnotationCompatibilityResult result = new SchemaAnnotationHandler.AnnotationCompatibilityResult();
    result.addMessage(compatibilityMessage);
    return result;
}
Also used : AnnotationCompatibilityResult(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult) ExtensionSchemaAnnotationHandler(com.linkedin.data.schema.annotation.ExtensionSchemaAnnotationHandler) SchemaAnnotationHandler(com.linkedin.data.schema.annotation.SchemaAnnotationHandler) AnnotationCompatibilityResult(com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult)

Aggregations

AnnotationCompatibilityResult (com.linkedin.data.schema.annotation.SchemaAnnotationHandler.AnnotationCompatibilityResult)4 ExtensionSchemaAnnotationHandler (com.linkedin.data.schema.annotation.ExtensionSchemaAnnotationHandler)2 CompatibilityCheckContext (com.linkedin.data.schema.annotation.SchemaAnnotationHandler.CompatibilityCheckContext)2 DataSchema (com.linkedin.data.schema.DataSchema)1 PathSpec (com.linkedin.data.schema.PathSpec)1 SchemaAnnotationHandler (com.linkedin.data.schema.annotation.SchemaAnnotationHandler)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 DataProvider (org.testng.annotations.DataProvider)1 Test (org.testng.annotations.Test)1