You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@avro.apache.org by "ASF subversion and git services (Jira)" <ji...@apache.org> on 2023/07/10 12:13:00 UTC

[jira] [Commented] (AVRO-3787) [Rust] Deserialization fails to use default if an enum in a record in a union is given an unknown symbol

    [ https://issues.apache.org/jira/browse/AVRO-3787?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17741584#comment-17741584 ] 

ASF subversion and git services commented on AVRO-3787:
-------------------------------------------------------

Commit 2b70b3392ed4db37c2611ffebc8dd440858ff136 in avro's branch refs/heads/avro-3787-enum-validation from Martin Tzvetanov Grigorov
[ https://gitbox.apache.org/repos/asf?p=avro.git;h=2b70b3392 ]

AVRO-3787: [Rust] Deserialization fails to use default if an enum in a record in a union is given an unknown symbol

Do not fail the validation if the provided enum symbol is not in the
list of available ones if there schema defines a default symbol

Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>


> [Rust] Deserialization fails to use default if an enum in a record in a union is given an unknown symbol 
> ---------------------------------------------------------------------------------------------------------
>
>                 Key: AVRO-3787
>                 URL: https://issues.apache.org/jira/browse/AVRO-3787
>             Project: Apache Avro
>          Issue Type: Bug
>          Components: rust
>            Reporter: Evan Blackwell
>            Priority: Major
>
> When providing from_avro_datum with a reader_schema, there is a FindUnionVariant error if * There is a union with one of the types being a record that has an enum type field
>  * The enum type has a default
>  * The value in the message is a symbol in the writer schema but not the reader schema
>  * The enum can be defined earlier in the schema or inline in the record
> Test that has a reference type and fails
>  
> {code:java}
> #[test]
>     fn deserialize_union_with_unknown_symbol() -> TestResult {
>         #[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
>         pub struct BarUseParent {
>             #[serde(rename = "barUse")]
>             pub bar_use: Bar,
>         }
>         #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, serde::Deserialize, serde::Serialize)]
>         pub enum Bar {
>             #[serde(rename = "bar0")]
>             Bar0,
>             #[serde(rename = "bar1")]
>             Bar1,
>             #[serde(rename = "bar2")]
>             Bar2,
>         }
>         #[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
>         pub struct Foo {
>             #[serde(rename = "barInit")]
>             pub bar_init: Bar,
>             #[serde(rename = "barUseParent")]
>             pub bar_use_parent: Option<BarUseParent>,
>         }
>         let writer_schema = r#"{
>             "type": "record",
>             "name": "Foo",
>             "fields":
>             [
>                 {
>                     "name": "barInit",
>                     "type":
>                     {
>                         "type": "enum",
>                         "name": "Bar",
>                         "symbols":
>                         [
>                             "bar0",
>                             "bar1",
>                             "bar2"
>                         ],
>                         "default": "bar0"
>                     }
>                 },
>                 {
>                     "name": "barUseParent",
>                     "type": [
>                         "null",
>                         {
>                             "type": "record",
>                             "name": "BarUseParent",
>                             "fields": [
>                                 {
>                                     "name": "barUse",
>                                     "type": "Bar"
>                                 }
>                             ]
>                         }
>                     ]
>                 }
>             ]
>         }"#;
>         let reader_schema = r#"{
>             "type": "record",
>             "name": "Foo",
>             "fields":
>             [
>                 {
>                     "name": "barInit",
>                     "type":
>                     {
>                         "type": "enum",
>                         "name": "Bar",
>                         "symbols":
>                         [
>                             "bar0",
>                             "bar1"
>                         ],
>                         "default": "bar0"
>                     }
>                 },
>                 {
>                     "name": "barUseParent",
>                     "type": [
>                         "null",
>                         {
>                             "type": "record",
>                             "name": "BarUseParent",
>                             "fields": [
>                                 {
>                                     "name": "barUse",
>                                     "type": "Bar"
>                                 }
>                             ]
>                         }
>                     ]
>                 }
>             ]
>             }"#;
>         let writer_schema = Schema::parse_str(writer_schema)?;
>         let foo = Foo {
>             bar_init: Bar::Bar1,
>             bar_use_parent: Some(BarUseParent { bar_use: Bar::Bar2} ),
>         };
>         let avro_value = crate::to_value(foo)?;
>         assert!(
>             avro_value.validate(&writer_schema),
>             "value is valid for schema",
>         );
>         let datum = crate::to_avro_datum(&writer_schema, avro_value)?;
>         let mut x = &datum[..];
>         let reader_schema = Schema::parse_str(reader_schema)?;
>         let deser_value = crate::from_avro_datum(&writer_schema, &mut x, Some(&reader_schema))?;
>         match deser_value {
>             types::Value::Record(fields) => {
>                 assert_eq!(fields.len(), 2);
>                 assert_eq!(fields[0].0, "barInit");
>                 assert_eq!(fields[0].1, types::Value::Enum(1, "bar1".to_string()));
>                 assert_eq!(fields[1].0, "barUseParent");
>                 // TODO: test value
>             }
>             _ => panic!("Expected Value::Record"),
>         }
>         Ok(())
>     } {code}
>  
>  
> Test that defines the enum in the record and fails
>  
> {code:java}
> #[test]
>     fn deserialize_union_with_unknown_symbol_no_ref() -> TestResult {
>         #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, serde::Deserialize, serde::Serialize)]
>         pub enum Bar {
>             #[serde(rename = "bar0")]
>             Bar0,
>             #[serde(rename = "bar1")]
>             Bar1,
>             #[serde(rename = "bar2")]
>             Bar2,
>         }
>         #[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
>         #[serde(default)]
>         pub struct BarParent {
>             #[serde(rename = "Bar")]
>             pub bar: Bar,
>         }
>         #[inline(always)]
>         fn default_barparent_bar() -> Bar { Bar::Bar0 }        impl Default for BarParent {
>             fn default() -> BarParent {
>                 BarParent {
>                     bar: default_barparent_bar(),
>                 }
>             }
>         }
>         #[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
>         pub struct Foo {
>             #[serde(rename = "barParent")]
>             pub bar_parent: Option<BarParent>,
>         }
>         let writer_schema = r#"{
>             "type": "record",
>             "name": "Foo",
>             "fields":
>             [
>                 {
>                     "name": "barParent",
>                     "type": [
>                         "null",
>                         {
>                             "type": "record",
>                             "name": "BarParent",
>                             "fields": [
>                                 {
>                                     "type": "enum",
>                                     "name": "Bar",
>                                     "symbols":
>                                     [
>                                         "bar0",
>                                         "bar1",
>                                         "bar2"
>                                     ],
>                                     "default": "bar0"
>                                 }
>                             ]
>                         }
>                     ]
>                 }
>             ]
>         }"#;
>         let reader_schema = r#"{
>             "type": "record",
>             "name": "Foo",
>             "fields":
>             [
>                 {
>                     "name": "barParent",
>                     "type": [
>                         "null",
>                         {
>                             "type": "record",
>                             "name": "BarParent",
>                             "fields": [
>                                 {
>                                     "type": "enum",
>                                     "name": "Bar",
>                                     "symbols":
>                                     [
>                                         "bar0",
>                                         "bar1"
>                                     ],
>                                     "default": "bar0"
>                                 }
>                             ]
>                         }
>                     ]
>                 }
>             ]
>         }"#;
>         let writer_schema = Schema::parse_str(writer_schema)?;
>         let foo = Foo {
>             bar_parent: Some(BarParent { bar: Bar::Bar2} ),
>         };
>         let avro_value = crate::to_value(foo)?;
>         assert!(
>             avro_value.validate(&writer_schema),
>             "value is valid for schema",
>         );
>         let datum = crate::to_avro_datum(&writer_schema, avro_value)?;
>         let mut x = &datum[..];
>         let reader_schema = Schema::parse_str(reader_schema)?;
>         let deser_value = crate::from_avro_datum(&writer_schema, &mut x, Some(&reader_schema))?;
>         match deser_value {
>             types::Value::Record(fields) => {
>                 assert_eq!(fields.len(), 1);
>                 // assert_eq!(fields[0].0, "barInit");
>                 // assert_eq!(fields[0].1, types::Value::Enum(0, "bar0".to_string()));
>                 assert_eq!(fields[0].0, "barParent");
>                 // assert_eq!(fields[1].1, types::Value::Enum(1, "bar1".to_string()));
>             }
>             _ => panic!("Expected Value::Record"),
>         }
>         Ok(())
>     } {code}
>  
> Both tests fail with the same error: 
> {code:java}
> apache_avro::error::Error: Could not find matching type in union {code}
> If I write the same tests but give the value Bar1, then they pass, so it seems to only be if it's an unknown symbol.
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)