Search in sources :

Example 1 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class TestSchemaTranslator method testToAvroSchema.

private void testToAvroSchema(String schemaText, Object[] row) throws IOException {
    boolean debug = false;
    if (debug)
        System.out.println(schemaText);
    for (int i = 1; i < row.length; i++) {
        Object[] modeInputs = (Object[]) row[i];
        OptionalDefaultMode[] optionalDefaultModes = (OptionalDefaultMode[]) modeInputs[0];
        Object expected = modeInputs[1];
        for (EmbedSchemaMode embedSchemaMode : EmbedSchemaMode.values()) {
            for (OptionalDefaultMode optionalDefaultMode : optionalDefaultModes) {
                DataSchema schema = TestUtil.dataSchemaFromString(schemaText);
                String preTranslateSchemaText = schema.toString();
                Exception exc = null;
                String avroTextFromSchema = null;
                try {
                    avroTextFromSchema = SchemaTranslator.dataToAvroSchemaJson(schema, new DataToAvroSchemaTranslationOptions(optionalDefaultMode, JsonBuilder.Pretty.SPACES, embedSchemaMode));
                    if (debug) {
                        System.out.println("EmbeddedSchema: " + embedSchemaMode + ", OptionalDefaultMode: " + optionalDefaultMode + ", Avro Schema: " + avroTextFromSchema);
                    }
                } catch (Exception e) {
                    exc = e;
                    if (debug) {
                        e.printStackTrace();
                    }
                }
                if (expected instanceof String) {
                    assertNull(exc);
                    String expectedAvroText = (String) expected;
                    if (embedSchemaMode == EmbedSchemaMode.ROOT_ONLY && hasEmbeddedSchema(schema)) {
                        // when embeddedSchema is enabled
                        // for map, array, enums. and records, we embed the original Pegasus schema
                        DataMap expectedAvroDataMap = TestUtil.dataMapFromString(expectedAvroText);
                        DataMap resultAvroDataMap = TestUtil.dataMapFromString(avroTextFromSchema);
                        Object dataProperty = resultAvroDataMap.remove(SchemaTranslator.DATA_PROPERTY);
                        assertEquals(resultAvroDataMap, expectedAvroDataMap);
                        // look for embedded schema
                        assertNotNull(dataProperty);
                        assertTrue(dataProperty instanceof DataMap);
                        Object schemaProperty = ((DataMap) dataProperty).get(SchemaTranslator.SCHEMA_PROPERTY);
                        assertNotNull(schemaProperty);
                        assertTrue(schemaProperty instanceof DataMap);
                        // make sure embedded schema is same as the original schema
                        PegasusSchemaParser schemaParser = TestUtil.schemaParserFromObjects(Arrays.asList(schemaProperty));
                        DataSchema embeddedSchema = schemaParser.topLevelDataSchemas().get(0);
                        assertEquals(embeddedSchema, schema.getDereferencedDataSchema());
                        // look for optional default mode
                        Object optionalDefaultModeProperty = ((DataMap) dataProperty).get(SchemaTranslator.OPTIONAL_DEFAULT_MODE_PROPERTY);
                        assertNotNull(optionalDefaultMode);
                        assertEquals(optionalDefaultModeProperty, optionalDefaultMode.toString());
                    } else {
                        // for unions and primitives, we never embed the pegasus schema
                        if (embedSchemaMode == EmbedSchemaMode.NONE && hasEmbeddedSchema(schema)) {
                            // make sure no embedded schema when
                            DataMap resultAvroDataMap = TestUtil.dataMapFromString(avroTextFromSchema);
                            assertFalse(resultAvroDataMap.containsKey(SchemaTranslator.DATA_PROPERTY));
                        }
                        assertEquals(avroTextFromSchema, expectedAvroText);
                    }
                    String postTranslateSchemaText = schema.toString();
                    assertEquals(preTranslateSchemaText, postTranslateSchemaText);
                    // make sure Avro accepts it
                    Schema avroSchema = Schema.parse(avroTextFromSchema);
                    if (debug)
                        System.out.println("AvroSchema: " + avroSchema);
                    SchemaParser parser = new SchemaParser();
                    ValidationOptions options = new ValidationOptions();
                    options.setAvroUnionMode(true);
                    parser.setValidationOptions(options);
                    parser.parse(avroTextFromSchema);
                    assertFalse(parser.hasError(), parser.errorMessage());
                    if (optionalDefaultMode == DataToAvroSchemaTranslationOptions.DEFAULT_OPTIONAL_DEFAULT_MODE) {
                        // use other dataToAvroSchemaJson
                        String avroSchema2Json = SchemaTranslator.dataToAvroSchemaJson(TestUtil.dataSchemaFromString(schemaText));
                        String avroSchema2JsonCompact = SchemaTranslator.dataToAvroSchemaJson(TestUtil.dataSchemaFromString(schemaText), new DataToAvroSchemaTranslationOptions());
                        assertEquals(avroSchema2Json, avroSchema2JsonCompact);
                        Schema avroSchema2 = Schema.parse(avroSchema2Json);
                        assertEquals(avroSchema2, avroSchema);
                        // use dataToAvroSchema
                        Schema avroSchema3 = SchemaTranslator.dataToAvroSchema(TestUtil.dataSchemaFromString(schemaText));
                        assertEquals(avroSchema3, avroSchema2);
                    }
                    if (modeInputs.length >= 4) {
                        // check if the translated default value is good by using it.
                        // writer schema and Avro JSON value should not include fields with default values.
                        String writerSchemaText = (String) modeInputs[2];
                        String avroValueJson = (String) modeInputs[3];
                        Schema writerSchema = Schema.parse(writerSchemaText);
                        GenericRecord genericRecord = genericRecordFromString(avroValueJson, writerSchema, avroSchema);
                        if (modeInputs.length >= 5) {
                            String genericRecordJson = (String) modeInputs[4];
                            String genericRecordAsString = genericRecord.toString();
                            DataMap expectedGenericRecord = TestUtil.dataMapFromString(genericRecordJson);
                            DataMap resultGenericRecord = TestUtil.dataMapFromString(genericRecordAsString);
                            assertEquals(resultGenericRecord, expectedGenericRecord);
                        }
                    }
                    if (embedSchemaMode == EmbedSchemaMode.ROOT_ONLY && hasEmbeddedSchema(schema)) {
                        // if embedded schema is enabled, translate Avro back to Pegasus schema.
                        // the output Pegasus schema should be exactly same the input schema
                        // taking into account typeref.
                        AvroToDataSchemaTranslationOptions avroToDataSchemaMode = new AvroToDataSchemaTranslationOptions(AvroToDataSchemaTranslationMode.VERIFY_EMBEDDED_SCHEMA);
                        DataSchema embeddedSchema = SchemaTranslator.avroToDataSchema(avroTextFromSchema, avroToDataSchemaMode);
                        assertEquals(embeddedSchema, schema.getDereferencedDataSchema());
                    }
                } else {
                    Class<?> expectedExceptionClass = (Class<?>) expected;
                    String expectedString = (String) modeInputs[2];
                    assertNotNull(exc);
                    assertNull(avroTextFromSchema);
                    assertTrue(expectedExceptionClass.isInstance(exc));
                    assertTrue(exc.getMessage().contains(expectedString), "\"" + exc.getMessage() + "\" does not contain \"" + expectedString + "\"");
                }
            }
        }
    }
}
Also used : PegasusSchemaParser(com.linkedin.data.schema.PegasusSchemaParser) DataSchema(com.linkedin.data.schema.DataSchema) Schema(org.apache.avro.Schema) SchemaParser(com.linkedin.data.schema.SchemaParser) PegasusSchemaParser(com.linkedin.data.schema.PegasusSchemaParser) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) IOException(java.io.IOException) DataMap(com.linkedin.data.DataMap) DataSchema(com.linkedin.data.schema.DataSchema) GenericRecord(org.apache.avro.generic.GenericRecord)

Example 2 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class TestPatchFilterValidator method testPatchFilterValidator.

@Test
public void testPatchFilterValidator() throws IOException {
    String schemaText = "{\n" + "  \"type\" : \"record\",\n" + "  \"name\" : \"Foo\",\n" + "  \"fields\" : [\n" + "    { \"name\" : \"fooInt\", \"type\" : \"int\", \"optional\" : true },\n" + "    { \"name\" : \"fooString\", \"type\" : \"string\", \"optional\" : true },\n" + "    {\n" + "      \"name\" : \"bar\",\n" + "      \"type\" : {\n" + "        \"type\" : \"record\",\n" + "        \"name\" : \"Bar\",\n" + "        \"fields\" : [\n" + "          { \"name\" : \"barInt\", \"type\" : \"int\", \"optional\" : true },\n" + "          { \"name\" : \"barString\", \"type\" : \"string\", \"optional\" : true },\n" + "          {\n" + "            \"name\" : \"baz\",\n" + "            \"type\" : {\n" + "               \"type\" : \"record\",\n" + "               \"name\" : \"Baz\",\n" + "               \"fields\" : [\n" + "                { \"name\" : \"bazInt\", \"type\" : \"int\", \"optional\" : true },\n" + "                { \"name\" : \"bazString\", \"type\" : \"string\", \"optional\" : true }\n" + "              ]\n" + "            },\n" + "            \"optional\" : true\n" + "          }\n" + "        ]\n" + "      },\n" + "      \"optional\" : true\n" + "    }\n" + "  ]\n" + "}\n";
    Object[][] inputs = { // }
    { // deleted /fooInt
    "{ }", "{ \"$delete\" : [ \"fooInt\" ] }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, ""), asList(Mode.ANCESTOR_AND_SET, "") }, { //   must not call validator for parents and ancestors not modified
    "{ \"fooString\" : \"excluded\", \"bar\" : { \"barInt\" : -1 } }", "{ \"$delete\" : [ \"fooInt\" ] }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, ""), asList(Mode.ANCESTOR_AND_SET, "") }, { // deleted /bar/barInt
    "{ \"bar\" : { } }", "{ \"bar\" : { \"$delete\" : [ \"barInt\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { //   must not call validator for parents and ancestors not modified
    "{ \"fooInt\" : -1, \"fooString\" : \"excluded\", \"bar\" : { } }", "{ \"bar\" : { \"$delete\" : [ \"barInt\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { // deleted /bar/baz/bazInt
    "{ \"bar\" : { \"baz\" : { } } }", "{ \"bar\" : { \"baz\" : { \"$delete\" : [ \"bazInt\" ] } } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar/baz"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz") }, { //   must not call validator for parents and ancestors not modified
    "{ \"fooInt\" : -1, \"fooString\" : \"excluded\", \"bar\" : { \"barInt\" : -1, \"baz\" : { } } }", "{ \"bar\" : { \"baz\" : { \"$delete\" : [ \"bazInt\" ] } } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar/baz"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz") }, { // deleted /bar/baz
    "{ \"bar\" : { } }", "{ \"bar\" : { \"$delete\" : [ \"baz\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { //   must not call validator for parents and ancestors not modified
    "{ \"fooInt\" : -1, \"fooString\" : \"excluded\", \"bar\" : { \"barInt\" : -1 } }", "{ \"bar\" : { \"$delete\" : [ \"baz\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { // set /fooInt (set field in root record)
    "{ \"fooInt\" : 2 }", "{ \"$set\" : { \"fooInt\" : 2 } }", "", asList(Mode.SET_ONLY, "/fooInt"), asList(Mode.PARENT_AND_SET, "", "/fooInt"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt") }, { //   must not call validator for parents and ancestors not modified
    "{ \"fooInt\" : 2, \"fooString\" : \"excluded\", \"bar\" : { \"baz\" : { } } }", "{ \"$set\" : { \"fooInt\" : 2 } }", "", asList(Mode.SET_ONLY, "/fooInt"), asList(Mode.PARENT_AND_SET, "", "/fooInt"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excluded\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : 2,\n" + "    \"barString\" : \"excluded\",\n" + "    \"baz\" : {}\n" + "  }\n" + "}", "{ \"bar\" : { \"$set\" : { \"barInt\" : 2 } } }", "", asList(Mode.SET_ONLY, "/bar/barInt"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/barInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/barInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : -1,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"barString\" : \"x\",\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"excludes\"\n" + "    }\n" + "  }\n" + "}", "{ \"bar\" : { \"$set\" : { \"barString\" : \"x\" } } }", "", asList(Mode.SET_ONLY, "/bar/barString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/barString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/barString") }, { // set /bar/baz/bazInt (set field in nested grandchild record)
    "{ \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } }", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excluded\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : 2,\n" + "    \"barString\" : \"excluded\",\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"excluded\"\n" + "    }\n" + "  }\n" + "}", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : -1,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"excludes\"\n" + "    }\n" + "  }\n" + "}", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // set /bar (set record in root record)
    "{ \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } }", "{ \"$set\" : { \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excluded\",\n" + "  \"bar\" : {\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2\n" + "    }\n" + "  }\n" + "}", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // set /bar/baz (set record in nested child record)
    "{ \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } }", "{ \"bar\" : { \"$set\" : { \"baz\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excluded\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : 2,\n" + "    \"barString\" : \"excluded\",\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2\n" + "    }\n" + "  }\n" + "}", "{ \"bar\" : { \"$set\" : { \"baz\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { //   must not call validator for parents and ancestors not modified
    "{\n" + "  \"fooInt\" : -1,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"barString\" : \"excludes\",\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"x\"\n" + "    }\n" + "  }\n" + "}", "{ \"bar\" : { \"$set\" : { \"baz\" : { \"bazInt\" : 2, \"bazString\" : \"x\" } } } }", "", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { // set /fooInt, /fooString (set multiple fields in root record)
    "{ \"fooInt\" : 2, \"fooString\" : \"x\" }", "{ \"$set\" : { \"fooInt\" : 2, \"fooString\" : \"x\" } }", "", asList(Mode.SET_ONLY, "/fooInt", "/fooString"), asList(Mode.PARENT_AND_SET, "", "/fooInt", "/fooString"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt", "/fooString") }, { // set /bar/barInt, /bar/barString (set multiple fields in nested child record)
    "{ \"bar\" : { \"barInt\" : 2, \"barString\" : \"x\" } }", "{ \"bar\" : { \"$set\" : { \"barInt\" : 2, \"barString\" : \"x\" } } }", "", asList(Mode.SET_ONLY, "/bar/barInt", "/bar/barString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/barInt", "/bar/barString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/barInt", "/bar/barString") }, { // set /bar/baz/bazInt, /bar/baz/bazString (set multiple fields in nested grandchild record)
    "{ \"bar\" : { \"baz\" : { \"bazInt\" : 2, \"bazString\" : \"x\" } } }", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2, \"bazString\" : \"x\" } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { // set /fooInt, /bar/barInt, /bar/baz/bazInt
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"bar\" : {\n" + "    \"barInt\" : 2,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2\n" + "    }\n" + "  }\n" + "}", "{\n" + "  \"$set\" : { \"fooInt\" : 2 },\n" + "  \"bar\" : {\n" + "    \"$set\" : { \"barInt\" : 2 },\n" + "    \"baz\" : {\n" + "      \"$set\" : { \"bazInt\" : 2 }\n" + "    }\n" + "  }\n" + "}", "", asList(Mode.SET_ONLY, "/fooInt", "/bar/barInt", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "", "/fooInt", "/bar", "/bar/barInt", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt", "/bar", "/bar/barInt", "/bar/baz", "/bar/baz/bazInt") }, { // nothing set
    "{\n" + "  \"fooInt\" : -1,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : -1,\n" + "      \"bazString\" : \"excludes\"\n" + "    }\n" + "  }\n" + "}", "{}", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET), asList(Mode.ANCESTOR_AND_SET) }, { //   must not call next validator for /fooString, /bar/barInt
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"x\"\n" + "    }\n" + "  }\n" + "}", "{\n" + "  \"$set\" : { \"fooInt\" : 2 },\n" + "  \"bar\" : {\n" + "    \"$set\" : {\n" + "      \"baz\" : { \"bazInt\" : 2, \"bazString\" : \"x\" }\n" + "    }\n" + "  }\n" + "}", "", asList(Mode.SET_ONLY, "/fooInt", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "", "/fooInt", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { //   must not call next validator for /fooInt, /fooString, /bar/barInt
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"x\"\n" + "    }\n" + "  }\n" + "}", "{\n" + "  \"$set\" : {\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"x\"\n" + "    }\n" + "  }\n" + "}", "/bar", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { //   must not call next validator for /fooInt, /fooString, /bar/barInt
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"x\"\n" + "    }\n" + "  }\n" + "}", "{\n" + "  \"baz\" : {\n" + "    \"$set\" : {\n" + "      \"bazInt\" : 2\n" + "    }\n" + "  }\n" + "}", "/bar", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { //   must not call next validator for /fooInt, /fooString, /bar/barInt
    "{\n" + "  \"fooInt\" : 2,\n" + "  \"fooString\" : \"excludes\",\n" + "  \"bar\" : {\n" + "    \"barInt\" : -1,\n" + "    \"baz\" : {\n" + "      \"bazInt\" : 2,\n" + "      \"bazString\" : \"x\"\n" + "    }\n" + "  }\n" + "}", "{\n" + "  \"$set\" : { \"bazInt\" : 2 }\n" + "}", "/bar/baz", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") } };
    DataSchema schema = dataSchemaFromString(schemaText);
    ValidationOptions options = new ValidationOptions(RequiredMode.CAN_BE_ABSENT_IF_HAS_DEFAULT, CoercionMode.NORMAL);
    for (Object[] row : inputs) {
        String value = (String) row[0];
        String patch = (String) row[1];
        String patchPath = (String) row[2];
        DataMap valueMap = dataMapFromString(value);
        DataMap opMap = dataMapFromString(patch);
        if (debug) {
            out.println("Value: " + value);
            out.println("Patch: " + patch);
            if (patchPath.isEmpty() == false)
                out.println("PatchPath: " + patchPath);
        }
        for (int i = 3; i < row.length; i++) {
            VisitedValidator visitedValidator = new VisitedValidator();
            @SuppressWarnings("unchecked") List<Object> check = (List<Object>) row[i];
            Mode mode = (Mode) check.get(0);
            Validator validator;
            if (patchPath.isEmpty()) {
                validator = new PatchFilterValidator(visitedValidator, opMap, mode);
            } else {
                DataElement patchElement = DataElementUtil.element(valueMap, schema, patchPath);
                assertNotSame(patchElement, null);
                validator = new PatchFilterValidator(visitedValidator, opMap, mode, patchElement);
            }
            ValidationResult result = ValidateDataAgainstSchema.validate(valueMap, schema, options, validator);
            if (debug) {
                out.println("Mode: " + mode);
                out.print("Result: " + result);
                out.println("VisitedPaths: " + visitedValidator._visitedPaths);
            }
            assertTrue(result.isValid());
            for (int j = 1; j < check.size(); j++) {
                assertTrue(visitedValidator._visitedPaths.contains(check.get(j)));
            }
            assertEquals(visitedValidator._visitedPaths.size(), check.size() - 1);
        }
    }
}
Also used : Mode(com.linkedin.data.transform.patch.validator.PatchFilterValidator.Mode) RequiredMode(com.linkedin.data.schema.validation.RequiredMode) CoercionMode(com.linkedin.data.schema.validation.CoercionMode) TestUtil.dataMapFromString(com.linkedin.data.TestUtil.dataMapFromString) TestUtil.dataSchemaFromString(com.linkedin.data.TestUtil.dataSchemaFromString) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) DataMap(com.linkedin.data.DataMap) DataSchema(com.linkedin.data.schema.DataSchema) DataElement(com.linkedin.data.element.DataElement) TestUtil.asList(com.linkedin.data.TestUtil.asList) ArrayList(java.util.ArrayList) List(java.util.List) Validator(com.linkedin.data.schema.validator.Validator) Test(org.testng.annotations.Test)

Example 3 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class TestAnyRecordValidator method testValidationResultFlags.

@Test
public void testValidationResultFlags() throws IOException {
    Object[][] inputs = { { ANYRECORDCLIENT_SCHEMA, "{" + "  \"required\" : {\n" + "    \"com.linkedin.data.schema.validator.AnyRecord\" : {\n" + "      \"com.linkedin.Cat\" : { \"c\" : 1 }\n" + "    }\n" + "  }\n" + "}", false, new ValidationOptions(RequiredMode.IGNORE, CoercionMode.NORMAL), ResultFlag.VALID, ResultFlag.HAS_FIX, ResultFlag.NOT_HAS_FIXUP_READONLY_ERROR, new String[] {} }, { ANYRECORDCLIENT_SCHEMA, "{" + "  \"required\" : {\n" + "    \"com.linkedin.data.schema.validator.AnyRecord\" : {\n" + "      \"com.linkedin.Cat\" : { \"c\" : 1 }\n" + "    }\n" + "  }\n" + "}", true, new ValidationOptions(RequiredMode.IGNORE, CoercionMode.NORMAL), ResultFlag.NOT_VALID, ResultFlag.HAS_FIX, ResultFlag.HAS_FIXUP_READONLY_ERROR, new String[] { "ERROR", "/required/com.linkedin.data.schema.validator.AnyRecord/com.linkedin.Cat/c", "cannot be fixed because DataMap backing com.linkedin.Cat type is read-only" } } };
    final boolean debug = false;
    final AnyRecordValidator.Parameter anyRecordValidatorParameter = new AnyRecordValidator.Parameter(true, _resolver);
    for (Object[] row : inputs) {
        int i = 0;
        DataSchema schema = (DataSchema) row[i++];
        DataMap object = TestUtil.dataMapFromString((String) row[i++]);
        boolean makeReadOnly = (Boolean) row[i++];
        ValidationOptions options = (ValidationOptions) row[i++];
        if (makeReadOnly) {
            object.makeReadOnly();
        }
        AnyRecordValidator.setParameter(options, anyRecordValidatorParameter);
        DataSchemaAnnotationValidator validator = new DataSchemaAnnotationValidator(schema);
        if (debug)
            TestUtil.out.println(validator);
        ValidationResult result = ValidateDataAgainstSchema.validate(object, schema, options, validator);
        checkValidationResult(result, row, i, debug);
    }
}
Also used : ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) DataMap(com.linkedin.data.DataMap) DataSchema(com.linkedin.data.schema.DataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) NamedDataSchema(com.linkedin.data.schema.NamedDataSchema) Test(org.testng.annotations.Test)

Example 4 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class TestValidator method testValidatorPriority.

@Test
public void testValidatorPriority() throws IOException {
    Map<String, Class<? extends Validator>> validatorClassMap = new HashMap<String, Class<? extends Validator>>();
    validatorClassMap.put("v1", OrderValidator.class);
    validatorClassMap.put("v2", OrderValidator.class);
    validatorClassMap.put("v3", OrderValidator.class);
    validatorClassMap.put("v4", OrderValidator.class);
    validatorClassMap.put("v5", OrderValidator.class);
    validatorClassMap.put("v6", OrderValidator.class);
    Object[][] inputs = { { // positive priority values
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [], \n" + "  \"validate\" : {\n" + "    \"v1\" : { \"validatorPriority\" : 1, \"name\" : \"p1\" },\n" + "    \"v2\" : { \"validatorPriority\" : 2, \"name\" : \"p2\" },\n" + "    \"v3\" : { \"validatorPriority\" : 3, \"name\" : \"p3\" },\n" + "    \"v4\" : { \"validatorPriority\" : 4, \"name\" : \"p4\" },\n" + "    \"v5\" : { \"validatorPriority\" : 5, \"name\" : \"p5\" },\n" + "    \"v6\" : { \"validatorPriority\" : 6, \"name\" : \"p6\" }\n" + "  }\n" + "}\n", "{}", new String[] { ":p6", ":p5", ":p5", ":p4", ":p4", ":p3", ":p3", ":p2", ":p2", ":p1" } }, { // negative priority values
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [], \n" + "  \"validate\" : {\n" + "    \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"p-1\" },\n" + "    \"v2\" : { \"validatorPriority\" : 0, \"name\" : \"p=0\" },\n" + "    \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"p+1\" }\n" + "  }\n" + "}\n", "{}", new String[] { ":p+1", ":p=0", ":p=0", ":p-1" } }, { // default priority value
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [], \n" + "  \"validate\" : {\n" + "    \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"p-1\" },\n" + "    \"v2\" : { \"name\" : \"pdefault\" },\n" + "    \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"p+1\" }\n" + "  }\n" + "}\n", "{}", new String[] { ":p+1", ":pdefault", ":pdefault", ":p-1" } }, { // same priority values
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [], \n" + "  \"validate\" : {\n" + "    \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"p-1a\" },\n" + "    \"v2\" : { \"validatorPriority\" : -1, \"name\" : \"p-1b\" },\n" + "    \"v3\" : { \"validatorPriority\" : 0, \"name\" : \"p0a\" },\n" + "    \"v4\" : { \"validatorPriority\" : 0, \"name\" : \"p0b\" },\n" + "    \"v5\" : { \"validatorPriority\" : 1, \"name\" : \"p+1a\" },\n" + "    \"v6\" : { \"validatorPriority\" : 1, \"name\" : \"p+1b\" }\n" + "  }\n" + "}\n", "{}", new String[] { ":p+1a", ":p0a", ":p+1a", ":p0b", ":p+1b", ":p0a", ":p+1b", ":p0b", ":p0a", ":p-1a", ":p0a", ":p-1b", ":p0b", ":p-1a", ":p0b", ":p-1b" } }, { // typeref inner before outer
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [\n" + "    {\n" + "      \"name\" : \"i\",\n" + "      \"type\" : {\n" + "        \"type\" : \"typeref\",\n" + "        \"name\" : \"Ref1\",\n" + "        \"ref\" : {\n" + "          \"type\" : \"typeref\",\n" + "          \"name\" : \"Ref2\",\n" + "          \"ref\" : \"int\",\n" + "          \"validate\" : {\n" + "            \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"r2-1\" },\n" + "            \"v2\" : { \"name\" : \"r2=0\" },\n" + "            \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"r2+1\" }\n" + "          }\n" + "        },\n" + "        \"validate\" : {\n" + "          \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"r1-1\" },\n" + "          \"v2\" : { \"name\" : \"r1=0\" },\n" + "          \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"r1+1\" }\n" + "        }\n" + "      }\n" + "    }\n" + "  ]\n" + "}\n", "{\n" + "  \"i\" : 4\n" + "}", new String[] { "/i:r2+1", "/i:r2=0", "/i:r2=0", "/i:r2-1", "/i:r2-1", "/i:r1+1", "/i:r1+1", "/i:r1=0", "/i:r1=0", "/i:r1-1" } }, { // array items before array
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [\n" + "    {\n" + "      \"name\" : \"a\",\n" + "      \"type\" : {\n" + "        \"type\" : \"array\",\n" + "        \"items\" : {\n" + "          \"type\" : \"typeref\",\n" + "          \"name\" : \"IntRef\",\n" + "          \"ref\" : \"int\",\n" + "          \"validate\" : {\n" + "            \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"i-1\" },\n" + "            \"v2\" : { \"name\" : \"i=0\" },\n" + "            \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"i+1\" }\n" + "          }\n" + "        },\n" + "        \"validate\" : {\n" + "          \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"a-1\" },\n" + "          \"v2\" : { \"name\" : \"a=0\" },\n" + "          \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"a+1\" }\n" + "        }\n" + "      }\n" + "    }\n" + "  ]\n" + "}\n", "{\n" + "  \"a\" : [ 1 ]\n" + "}", new String[] { "/a/0:i+1", "/a/0:i=0", "/a/0:i=0", "/a/0:i-1", "/a/0:i-1", "/a:a+1", "/a:a+1", "/a:a=0", "/a:a=0", "/a:a-1" } }, { // map values before map
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [\n" + "    {\n" + "      \"name\" : \"m\",\n" + "      \"type\" : {\n" + "        \"type\" : \"map\",\n" + "        \"values\" : {\n" + "          \"type\" : \"typeref\",\n" + "          \"name\" : \"IntRef\",\n" + "          \"ref\" : \"int\",\n" + "          \"validate\" : {\n" + "            \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"v-1\" },\n" + "            \"v2\" : { \"name\" : \"v=0\" },\n" + "            \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"v+1\" }\n" + "          }\n" + "        },\n" + "        \"validate\" : {\n" + "          \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"m-1\" },\n" + "          \"v2\" : { \"name\" : \"m=0\" },\n" + "          \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"m+1\" }\n" + "        }\n" + "      }\n" + "    }\n" + "  ]\n" + "}\n", "{\n" + "  \"m\" : { \"x\" : 1 } }\n" + "}", new String[] { "/m/x:v+1", "/m/x:v=0", "/m/x:v=0", "/m/x:v-1", "/m/x:v-1", "/m:m+1", "/m:m+1", "/m:m=0", "/m:m=0", "/m:m-1" } }, { // union member before typeref of union
    "{\n" + "  \"name\" : \"Foo\",\n" + "  \"type\" : \"record\",\n" + "  \"fields\" : [\n" + "    {\n" + "      \"name\" : \"u\",\n" + "      \"type\" : {\n" + "        \"type\" : \"typeref\",\n" + "        \"name\" : \"Union\",\n" + "        \"ref\" : [\n" + "          {\n" + "            \"type\" : \"typeref\",\n" + "            \"name\" : \"Int\",\n" + "            \"ref\" : \"int\",\n" + "            \"validate\" : {\n" + "              \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"i-1\" },\n" + "              \"v2\" : { \"name\" : \"i=0\" },\n" + "              \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"i+1\" }\n" + "            }\n" + "          },\n" + "          \"string\"\n" + "        ],\n" + "        \"validate\" : {\n" + "          \"v1\" : { \"validatorPriority\" : -1, \"name\" : \"u-1\" },\n" + "          \"v2\" : { \"name\" : \"u=0\" },\n" + "          \"v3\" : { \"validatorPriority\" : 1, \"name\" : \"u+1\" }\n" + "        }\n" + "      }\n" + "    }\n" + "  ]\n" + "}\n", "{\n" + "  \"u\" : { \"int\" : 4 }\n" + "}", new String[] { "/u/int:i+1", "/u/int:i=0", "/u/int:i=0", "/u/int:i-1", "/u/int:i-1", "/u:u+1", "/u:u+1", "/u:u=0", "/u:u=0", "/u:u-1" } } };
    boolean debug = false;
    for (Object[] row : inputs) {
        int i = 0;
        String schemaText = (String) row[i++];
        String dataMapText = (String) row[i++];
        DataSchema schema = dataSchemaFromString(schemaText);
        DataMap dataMap = dataMapFromString(dataMapText);
        DataSchemaAnnotationValidator dataSchemaAnnotationValidator = new DataSchemaAnnotationValidator();
        dataSchemaAnnotationValidator.init(schema, validatorClassMap);
        if (debug)
            out.println(dataSchemaAnnotationValidator.getInitMessages());
        assertTrue(dataSchemaAnnotationValidator.isInitOk());
        if (debug)
            out.println(dataSchemaAnnotationValidator);
        dataSchemaAnnotationValidator.setDebugMode(debug);
        OrderValidator._orderList.clear();
        ValidationOptions validationOptions = new ValidationOptions();
        ValidationResult validationResult = ValidateDataAgainstSchema.validate(dataMap, schema, validationOptions, dataSchemaAnnotationValidator);
        assertTrue(validationResult.isValid());
        if (debug)
            out.println(validationResult.getMessages());
        if (debug)
            out.println(OrderValidator._orderList);
        String[] expectedRelations = (String[]) row[i++];
        assertTrue(expectedRelations.length % 2 == 0);
        for (int r = 0; r < expectedRelations.length; r += 2) {
            OrderRelation orderRelation = new OrderRelation(new OrderEntry(expectedRelations[r]), new OrderEntry(expectedRelations[r + 1]));
            assertTrue(orderRelation.isSatisfied(OrderValidator._orderList));
        }
    }
}
Also used : HashMap(java.util.HashMap) TestUtil.dataMapFromString(com.linkedin.data.TestUtil.dataMapFromString) TestUtil.dataSchemaFromString(com.linkedin.data.TestUtil.dataSchemaFromString) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) DataMap(com.linkedin.data.DataMap) DataSchema(com.linkedin.data.schema.DataSchema) Test(org.testng.annotations.Test)

Example 5 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class TestValidator method testValidator.

public void testValidator(String schemaText, Object[][] input, Map<String, Class<? extends Validator>> validatorClassMap, String[] validatorCheckStrings, int tests) throws IOException, InstantiationException {
    DataSchema schema = dataSchemaFromString(schemaText);
    DataSchemaAnnotationValidator annotationValidator = new DataSchemaAnnotationValidator();
    annotationValidator.init(schema, validatorClassMap);
    if (debug)
        annotationValidator.setDebugMode(true);
    String annotationValidatorString = annotationValidator.toString();
    if (debug)
        out.println(annotationValidator);
    for (String checkString : validatorCheckStrings) {
        assertTrue(annotationValidatorString.contains(checkString));
    }
    for (Object[] row : input) {
        DataMap value = (DataMap) row[0];
        try {
            if ((tests & SCHEMA_VALIDATOR) != 0) {
                VisitedTrackingValidator visitedValidator = new VisitedTrackingValidator(annotationValidator);
                ValidationOptions validationOptions = new ValidationOptions(RequiredMode.CAN_BE_ABSENT_IF_HAS_DEFAULT, CoercionMode.NORMAL);
                ValidationResult result = ValidateDataAgainstSchema.validate(value.copy(), schema, validationOptions, visitedValidator);
                checkValidationResult(value, result, row, visitedValidator);
            }
            if ((tests & OBJECT_VALIDATOR) != 0) {
                VisitedTrackingValidator visitedValidator = new VisitedTrackingValidator(annotationValidator);
                ValidationOptions validationOptions = new ValidationOptions();
                ValidationResult result = ValidateDataAgainstSchema.validate(value.copy(), schema, validationOptions, visitedValidator);
                checkValidationResult(value, result, row, visitedValidator);
            }
        } catch (CloneNotSupportedException e) {
            throw new IllegalStateException("unexpected exception", e);
        }
    }
}
Also used : DataSchema(com.linkedin.data.schema.DataSchema) TestUtil.dataMapFromString(com.linkedin.data.TestUtil.dataMapFromString) TestUtil.dataSchemaFromString(com.linkedin.data.TestUtil.dataSchemaFromString) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) DataMap(com.linkedin.data.DataMap)

Aggregations

ValidationOptions (com.linkedin.data.schema.validation.ValidationOptions)29 ValidationResult (com.linkedin.data.schema.validation.ValidationResult)16 DataMap (com.linkedin.data.DataMap)13 Test (org.testng.annotations.Test)11 DataSchema (com.linkedin.data.schema.DataSchema)10 RecordDataSchema (com.linkedin.data.schema.RecordDataSchema)7 DataList (com.linkedin.data.DataList)4 RecordTemplate (com.linkedin.data.template.RecordTemplate)4 Greeting (com.linkedin.restli.examples.greetings.api.Greeting)4 ByteString (com.linkedin.data.ByteString)3 TestUtil.dataMapFromString (com.linkedin.data.TestUtil.dataMapFromString)3 TestUtil.dataSchemaFromString (com.linkedin.data.TestUtil.dataSchemaFromString)3 ArrayDataSchema (com.linkedin.data.schema.ArrayDataSchema)3 NamedDataSchema (com.linkedin.data.schema.NamedDataSchema)3 SchemaParser (com.linkedin.data.schema.SchemaParser)3 DataSchemaAnnotationValidator (com.linkedin.data.schema.validator.DataSchemaAnnotationValidator)3 DataElement (com.linkedin.data.element.DataElement)2 SimpleDataElement (com.linkedin.data.element.SimpleDataElement)2 Message (com.linkedin.data.message.Message)2 DataSchemaResolver (com.linkedin.data.schema.DataSchemaResolver)2