[
https://issues.apache.org/jira/browse/AVRO-3460?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Martin Tzvetanov Grigorov reassigned AVRO-3460:
-----------------------------------------------
Assignee: Martin Tzvetanov Grigorov
> [rust] Value::validate does not validate against Schema Refs
> ------------------------------------------------------------
>
> Key: AVRO-3460
> URL: https://issues.apache.org/jira/browse/AVRO-3460
> Project: Apache Avro
> Issue Type: Bug
> Components: rust
> Reporter: Jack Klamer
> Assignee: Martin Tzvetanov Grigorov
> Priority: Major
>
> The Value::validate() method is a preprocessing step before encoding the
> value into the buffer. The encode function assumes the value to be valid. The
> validate method recurses as necessary to validate against the schema
> provided. The function does not recurse to validate against schema refs found
> in the schema provided meaning that all values are validated to true against
> all schema Ref's which is incorrect.
> {code}
> pub fn validate(&self, schema: &Schema) -> bool {
> match (self, schema) {
> (_, &Schema::Ref { name: _ }) => true,
> ....{code}
> In practice this failure requires a user to forget to change their Schema
> when changing their struct and that struct change happens to be the second
> use of a struct within the enclosing struct. (Or fixed or enum).
> Because encode assumes the values passed to it are valid, it is possible for
> the encoding to complete without error in some situations.
>
>
> Two tests that should pass and currently fail, useful for anyone interested
> {code}
> #[test]
> fn test_validation_with_refs() {
> let schema = Schema::parse_str(
> r#"
> {
> "type":"record",
> "name":"TestStruct",
> "fields": [
> {
> "name":"a",
> "type":{
> "type":"record",
> "name": "Inner",
> "fields": [ {
> "name":"z",
> "type":"int"
> }]
> }
> },
> {
> "name":"b",
> "type":"Inner"
> }
> ]
> }"#,
> )
> .unwrap();
> let inner_value_right = Value::Record(vec![("z".into(),
> Value::Int(3))]);
> let inner_value_wrong1 = Value::Record(vec![("z".into(),
> Value::Null)]);
> let inner_value_wrong2 = Value::Record(vec![("a".into(),
> Value::String("testing".into()))]);
> let outer1 = Value::Record(vec![
> ("a".into(), inner_value_right.clone()),
> ("b".into(), inner_value_wrong1),
> ]);
> let outer2 = Value::Record(vec![
> ("a".into(), inner_value_right),
> ("b".into(), inner_value_wrong2),
> ]);
> assert!(!outer1.validate(&schema), "field b record is invalid against
> the schema"); // this should pass, but doesn't
> assert!(!outer2.validate(&schema), "field b record is invalid against
> the schema"); // this should pass, but doesn't
> }
> #[derive(Serialize, Clone)]
> struct TestInner {
> z: i32
> }
> #[derive(Serialize)]
> struct TestRefSchemaStruct1 {
> a: TestInner,
> b: String // could be literally anything
> }
> #[derive(Serialize)]
> struct TestRefSchemaStruct2 {
> a: TestInner,
> b: i32 // could be literally anything
> }
> #[derive(Serialize)]
> struct TestRefSchemaStruct3 {
> a: TestInner,
> b: Option<TestInner> // could be literally anything
> }
> #[test]
> fn test_validation_with_refs_real_struct() {
> let schema = Schema::parse_str(
> r#"
> {
> "type":"record",
> "name":"TestStruct",
> "fields": [
> {
> "name":"a",
> "type":{
> "type":"record",
> "name": "Inner",
> "fields": [ {
> "name":"z",
> "type":"int"
> }]
> }
> },
> {
> "name":"b",
> "type":"Inner"
> }
> ]
> }"#,
> )
> .unwrap();
> let test_inner = TestInner{z:3};
> let test_outer1 = TestRefSchemaStruct1{a:test_inner.clone(),
> b:"testing".into()};
> let test_outer2 = TestRefSchemaStruct2{a:test_inner.clone(), b:24};
> let test_outer3 = TestRefSchemaStruct3{a:test_inner.clone(), b:None};
>
> use crate::ser::Serializer;
> let mut ser = Serializer::default();
> let test_outer1: Value = test_outer1.serialize(&mut ser ).unwrap();
> let mut ser = Serializer::default();
> let test_outer2: Value = test_outer2.serialize(&mut ser ).unwrap();
> let mut ser = Serializer::default();
> let test_outer3: Value = test_outer3.serialize(&mut ser ).unwrap();
> assert!(!test_outer1.validate(&schema), "field b record is invalid
> against the schema"); // this should pass, but doesn't
> assert!(!test_outer2.validate(&schema), "field b record is invalid
> against the schema"); // this should pass, but doesn't
> assert!(!test_outer3.validate(&schema), "field b record is invalid
> against the schema"); // this should pass, but doesn't
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.20.1#820001)