Search in sources :

Example 21 with ValidationResult

use of com.linkedin.data.schema.validation.ValidationResult 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 22 with ValidationResult

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

the class AbstractSchemaParser method validateDefaults.

/**
   * Validate that the default value complies with the {@link DataSchema} of the record.
   *
   * @param recordSchema of the record.
   */
protected void validateDefaults(RecordDataSchema recordSchema) {
    for (RecordDataSchema.Field field : recordSchema.getFields()) {
        Object value = field.getDefault();
        if (value != null) {
            DataSchema valueSchema = field.getType();
            ValidationResult result = ValidateDataAgainstSchema.validate(value, valueSchema, _validationOptions);
            if (result.isValid() == false) {
                startErrorMessage(value).append("Default value ").append(value).append(" of field \"").append(field.getName()).append("\" declared in record \"").append(recordSchema.getFullName()).append("\" failed validation.\n");
                MessageUtil.appendMessages(errorMessageBuilder(), result.getMessages());
            }
            Object fixed = result.getFixed();
            field.setDefault(fixed);
        }
        if (field.getDefault() instanceof DataComplex) {
            ((DataComplex) field.getDefault()).setReadOnly();
        }
    }
}
Also used : DataComplex(com.linkedin.data.DataComplex) ValidationResult(com.linkedin.data.schema.validation.ValidationResult)

Example 23 with ValidationResult

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

the class AnyRecordValidator method validate.

@Override
public void validate(ValidatorContext context) {
    DataElement dataElement = context.dataElement();
    Object value = dataElement.getValue();
    DataSchema schema = dataElement.getSchema();
    if (schema.getType() != DataSchema.Type.RECORD || (((RecordDataSchema) schema).getFullName()).equals(SCHEMA_NAME) == false) {
        context.addResult(new Message(context.dataElement().path(), "%1$s invoked on schema that is not %2$s", AnyRecordValidator.class.getName(), SCHEMA_NAME));
    } else if (value.getClass() != DataMap.class) {
        context.addResult(new Message(context.dataElement().path(), "%1$s expects data to be a DataMap, data is %2$s", AnyRecordValidator.class.getName(), value));
    } else {
        DataMap dataMap = (DataMap) value;
        if (dataMap.size() != 1) {
            context.addResult(new Message(context.dataElement().path(), "%1$s expects data to be a DataMap with one entry, data is %2$s", AnyRecordValidator.class.getName(), value));
        } else {
            Map.Entry<String, Object> entry = dataMap.entrySet().iterator().next();
            String anySchemaName = entry.getKey();
            Object anyValue = entry.getValue();
            DataSchema anySchema = schemaFromName(context, anySchemaName);
            if (anySchema != null) {
                DataElement anyElement = new SimpleDataElement(anyValue, entry.getKey(), anySchema, dataElement);
                // do we want to have cache for anySchemaName to validator
                // do we care about classMap argument to DataSchemaAnnotationValidator
                DataSchemaAnnotationValidator validator = new DataSchemaAnnotationValidator(anySchema);
                if (validator.isInitOk() == false) {
                    boolean errorIfNotValidated = getParameter(context.validationOptions()).isValidSchema();
                    context.addResult(new Message(context.dataElement().path(), errorIfNotValidated, "%1$s failed to initialize %2$s with %3$s", AnyRecordValidator.class.getName(), DataSchemaAnnotationValidator.class.getSimpleName(), anySchema));
                    addResult(context, errorIfNotValidated, validator.getInitMessages());
                } else {
                    ValidationResult result = ValidateDataAgainstSchema.validate(anyElement, context.validationOptions(), validator);
                    addResult(context, result.getMessages());
                    if (result.hasFix())
                        context.setHasFix(true);
                    if (result.hasFixupReadOnlyError())
                        context.setHasFixupReadOnlyError(true);
                }
            }
        }
    }
}
Also used : RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) DataSchema(com.linkedin.data.schema.DataSchema) NamedDataSchema(com.linkedin.data.schema.NamedDataSchema) SimpleDataElement(com.linkedin.data.element.SimpleDataElement) DataElement(com.linkedin.data.element.DataElement) Message(com.linkedin.data.message.Message) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) SimpleDataElement(com.linkedin.data.element.SimpleDataElement) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) DataMap(com.linkedin.data.DataMap)

Example 24 with ValidationResult

use of com.linkedin.data.schema.validation.ValidationResult 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 25 with ValidationResult

use of com.linkedin.data.schema.validation.ValidationResult 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)

Aggregations

ValidationResult (com.linkedin.data.schema.validation.ValidationResult)38 Test (org.testng.annotations.Test)17 ValidationOptions (com.linkedin.data.schema.validation.ValidationOptions)16 DataMap (com.linkedin.data.DataMap)12 ValidationDemo (com.linkedin.restli.examples.greetings.api.ValidationDemo)11 RootBuilderWrapper (com.linkedin.restli.test.util.RootBuilderWrapper)8 DataSchema (com.linkedin.data.schema.DataSchema)7 ArrayList (java.util.ArrayList)7 RecordDataSchema (com.linkedin.data.schema.RecordDataSchema)6 HashMap (java.util.HashMap)6 Message (com.linkedin.data.message.Message)5 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)5 Map (java.util.Map)5 PatchRequest (com.linkedin.restli.common.PatchRequest)4 TestUtil.dataMapFromString (com.linkedin.data.TestUtil.dataMapFromString)3 TestUtil.dataSchemaFromString (com.linkedin.data.TestUtil.dataSchemaFromString)3 DataElement (com.linkedin.data.element.DataElement)3 SimpleDataElement (com.linkedin.data.element.SimpleDataElement)3 NamedDataSchema (com.linkedin.data.schema.NamedDataSchema)3 ResourceMethod (com.linkedin.restli.common.ResourceMethod)3