From 50dd0bf3240c67e4ab5e2f62f2102ac38c0c1b71 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Mon, 6 Apr 2020 17:43:49 +0200 Subject: [PATCH 1/9] Added String variant to Data Signed-off-by: Francesco Guardiani --- src/event/data.rs | 73 ++++++++++++++++++----------------- src/event/v10/serde.rs | 1 + tests/serde_json.rs | 38 ++++++++++++++----- tests/test_data/mod.rs | 86 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 143 insertions(+), 55 deletions(-) diff --git a/src/event/data.rs b/src/event/data.rs index fcea8393..eeab81c7 100644 --- a/src/event/data.rs +++ b/src/event/data.rs @@ -1,10 +1,13 @@ use std::convert::{Into, TryFrom}; /// Event [data attribute](https://github.com/cloudevents/spec/blob/master/spec.md#event-data) representation -/// #[derive(Debug, PartialEq, Clone)] pub enum Data { + /// Event has a binary payload Binary(Vec), + /// Event has a non-json string payload + String(String), + /// Event has a json payload Json(serde_json::Value), } @@ -44,40 +47,40 @@ impl Into for Vec { impl Into for String { fn into(self) -> Data { - Data::Json(self.into()) + Data::String(self) } } -impl TryFrom for serde_json::Value { - type Error = serde_json::Error; - - fn try_from(value: Data) -> Result { - match value { - Data::Binary(v) => Ok(serde_json::from_slice(&v)?), - Data::Json(v) => Ok(v), - } - } -} - -impl TryFrom for Vec { - type Error = serde_json::Error; - - fn try_from(value: Data) -> Result { - match value { - Data::Binary(v) => Ok(serde_json::from_slice(&v)?), - Data::Json(v) => Ok(serde_json::to_vec(&v)?), - } - } -} - -impl TryFrom for String { - type Error = std::string::FromUtf8Error; - - fn try_from(value: Data) -> Result { - match value { - Data::Binary(v) => Ok(String::from_utf8(v)?), - Data::Json(serde_json::Value::String(s)) => Ok(s), // Return the string without quotes - Data::Json(v) => Ok(v.to_string()), - } - } -} +// impl TryFrom for serde_json::Value { +// type Error = serde_json::Error; +// +// fn try_from(value: Data) -> Result { +// match value { +// Data::Binary(v) => Ok(serde_json::from_slice(&v)?), +// Data::Json(v) => Ok(v), +// } +// } +// } +// +// impl TryFrom for Vec { +// type Error = serde_json::Error; +// +// fn try_from(value: Data) -> Result { +// match value { +// Data::Binary(v) => Ok(serde_json::from_slice(&v)?), +// Data::Json(v) => Ok(serde_json::to_vec(&v)?), +// } +// } +// } +// +// impl TryFrom for String { +// type Error = std::string::FromUtf8Error; +// +// fn try_from(value: Data) -> Result { +// match value { +// Data::Binary(v) => Ok(String::from_utf8(v)?), +// Data::Json(serde_json::Value::String(s)) => Ok(s), // Return the string without quotes +// Data::Json(v) => Ok(v.to_string()), +// } +// } +// } diff --git a/src/event/v10/serde.rs b/src/event/v10/serde.rs index e6a4a9aa..ee12a9d3 100644 --- a/src/event/v10/serde.rs +++ b/src/event/v10/serde.rs @@ -100,6 +100,7 @@ impl crate::event::serde::EventSerializer f } match data { Some(Data::Json(j)) => state.serialize_entry("data", j)?, + Some(Data::String(s)) => state.serialize_entry("data", s)?, Some(Data::Binary(v)) => state.serialize_entry("data_base64", &base64::encode(v))?, _ => (), }; diff --git a/tests/serde_json.rs b/tests/serde_json.rs index ac54cf02..d433e7c1 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -7,30 +7,50 @@ mod test_data; use test_data::*; /// This test is a parametrized test that uses data from tests/test_data -/// The test follows the flow Event -> serde_json::Value -> String -> Event #[rstest( - event, - expected_json, + in_event, + out_json, case::minimal_v1(minimal_v1(), minimal_v1_json()), case::full_v1_no_data(full_v1_no_data(), full_v1_no_data_json()), case::full_v1_with_json_data(full_v1_json_data(), full_v1_json_data_json()), - case::full_v1_with_base64_data(full_v1_binary_data(), full_v1_base64_data_json()) + case::full_v1_with_xml_string_data(full_v1_xml_string_data(), full_v1_xml_string_data_json()), + case::full_v1_with_xml_base64_data(full_v1_xml_binary_data(), full_v1_xml_base64_data_json()) )] -fn serialize_deserialize_should_succeed(event: Event, expected_json: Value) { +fn serialize_should_succeed(in_event: Event, out_json: Value) { // Event -> serde_json::Value - let serialize_result = serde_json::to_value(event.clone()); + let serialize_result = serde_json::to_value(in_event.clone()); assert_ok!(&serialize_result); let actual_json = serialize_result.unwrap(); - assert_eq!(&actual_json, &expected_json); + assert_eq!(&actual_json, &out_json); // serde_json::Value -> String let actual_json_serialized = actual_json.to_string(); - assert_eq!(actual_json_serialized, expected_json.to_string()); + assert_eq!(actual_json_serialized, out_json.to_string()); // String -> Event let deserialize_result: Result = serde_json::from_str(&actual_json_serialized); assert_ok!(&deserialize_result); let deserialize_json = deserialize_result.unwrap(); - assert_eq!(deserialize_json, event) + assert_eq!(deserialize_json, in_event) } + +/// This test is a parametrized test that uses data from tests/test_data +#[rstest( + in_json, + out_event, + case::minimal_v1(minimal_v1_json(), minimal_v1()), + case::full_v1_no_data(full_v1_no_data_json(), full_v1_no_data()), + case::full_v1_with_json_data(full_v1_json_data_json(), full_v1_json_data()), + case::full_v1_with_json_base64_data(full_v1_json_base64_data_json(), full_v1_json_data()) + case::full_v1_with_xml_string_data(full_v1_xml_string_data_json(), full_v1_xml_string_data()), + case::full_v1_with_xml_base64_data(full_v1_xml_base64_data_json(), full_v1_xml_binary_data()) +)] +fn deserialize_should_succeed(in_json: Value, out_event: Event) { + let deserialize_result: Result = + serde_json::from_value(in_json); + assert_ok!(&deserialize_result); + let deserialize_json = deserialize_result.unwrap(); + assert_eq!(deserialize_json, out_event) +} + diff --git a/tests/test_data/mod.rs b/tests/test_data/mod.rs index cd582d97..76e69b9f 100644 --- a/tests/test_data/mod.rs +++ b/tests/test_data/mod.rs @@ -14,22 +14,30 @@ pub fn source() -> String { "http://localhost".to_string() } -pub fn datacontenttype() -> String { +pub fn json_datacontenttype() -> String { "application/json".to_string() } +pub fn xml_datacontenttype() -> String { + "application/xml".to_string() +} + pub fn dataschema() -> String { "http://localhost/schema".to_string() } -pub fn data() -> Value { +pub fn json_data() -> Value { json!({"hello": "world"}) } -pub fn data_base_64() -> Vec { +pub fn json_data_base64() -> Vec { serde_json::to_vec(&json!({"hello": "world"})).unwrap() } +pub fn xml_data() -> String { + "world".to_string() +} + pub fn subject() -> String { "cloudevents-sdk".to_string() } @@ -116,7 +124,7 @@ pub fn full_v1_json_data() -> Event { .extension(&string_ext_name, string_ext_value) .extension(&bool_ext_name, bool_ext_value) .extension(&int_ext_name, int_ext_value) - .data_with_schema(datacontenttype(), dataschema(), data()) + .data_with_schema(json_datacontenttype(), dataschema(), json_data()) .build() } @@ -141,7 +149,28 @@ pub fn full_v1_json_data_json() -> Value { }) } -pub fn full_v1_binary_data() -> Event { +pub fn full_v1_json_base64_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": datacontenttype(), + "dataschema": dataschema(), + "data_base64": base64::encode(&json_data_base64()) + }) +} + +pub fn full_v1_xml_string_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); let (int_ext_name, int_ext_value) = int_extension(); @@ -155,16 +184,32 @@ pub fn full_v1_binary_data() -> Event { .extension(&string_ext_name, string_ext_value) .extension(&bool_ext_name, bool_ext_value) .extension(&int_ext_name, int_ext_value) - .data_with_schema(datacontenttype(), dataschema(), data_base_64()) + .data(xml_datacontenttype(), xml_data()) .build() } -pub fn full_v1_base64_data_json() -> Value { +pub fn full_v1_xml_binary_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); let (int_ext_name, int_ext_value) = int_extension(); - let d = base64::encode(&data_base_64()); + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data(xml_datacontenttype(), Vec::from(xml_data())) + .build() +} + +pub fn full_v1_xml_string_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); json!({ "specversion": "1.0", @@ -176,8 +221,27 @@ pub fn full_v1_base64_data_json() -> Value { string_ext_name: string_ext_value, bool_ext_name: bool_ext_value, int_ext_name: int_ext_value, - "datacontenttype": datacontenttype(), - "dataschema": dataschema(), - "data_base64": d + "datacontenttype": xml_datacontenttype(), + "data": xml_data() }) } + +pub fn full_v1_xml_base64_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": xml_datacontenttype(), + "data_base64": base64::encode(Vec::from(xml_data())) + }) +} \ No newline at end of file From a2627a89a6651ffedf37bdb28c683dcb951b10ed Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Mon, 6 Apr 2020 17:44:17 +0200 Subject: [PATCH 2/9] Started V0.3 work Signed-off-by: Francesco Guardiani --- src/event/attributes.rs | 19 +++++- src/event/mod.rs | 7 ++ src/event/serde.rs | 6 +- src/event/v03/attributes.rs | 105 +++++++++++++++++++++++++++++ src/event/v03/builder.rs | 127 ++++++++++++++++++++++++++++++++++++ src/event/v03/mod.rs | 8 +++ src/event/v03/serde.rs | 112 +++++++++++++++++++++++++++++++ 7 files changed, 381 insertions(+), 3 deletions(-) create mode 100644 src/event/v03/attributes.rs create mode 100644 src/event/v03/builder.rs create mode 100644 src/event/v03/serde.rs diff --git a/src/event/attributes.rs b/src/event/attributes.rs index a02fe390..6857a984 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -1,5 +1,4 @@ -use super::SpecVersion; -use crate::event::AttributesV10; +use super::{SpecVersion, AttributesV10, AttributesV03}; use chrono::{DateTime, Utc}; /// Trait to get [CloudEvents Context attributes](https://github.com/cloudevents/spec/blob/master/spec.md#context-attributes). @@ -37,54 +36,63 @@ pub(crate) trait DataAttributesWriter { #[derive(PartialEq, Debug, Clone)] pub enum Attributes { + V03(AttributesV03), V10(AttributesV10), } impl AttributesReader for Attributes { fn get_id(&self) -> &str { match self { + Attributes::V03(a) => a.get_id(), Attributes::V10(a) => a.get_id(), } } fn get_source(&self) -> &str { match self { + Attributes::V03(a) => a.get_source(), Attributes::V10(a) => a.get_source(), } } fn get_specversion(&self) -> SpecVersion { match self { + Attributes::V03(a) => a.get_specversion(), Attributes::V10(a) => a.get_specversion(), } } fn get_type(&self) -> &str { match self { + Attributes::V03(a) => a.get_type(), Attributes::V10(a) => a.get_type(), } } fn get_datacontenttype(&self) -> Option<&str> { match self { + Attributes::V03(a) => a.get_datacontenttype(), Attributes::V10(a) => a.get_datacontenttype(), } } fn get_dataschema(&self) -> Option<&str> { match self { + Attributes::V03(a) => a.get_dataschema(), Attributes::V10(a) => a.get_dataschema(), } } fn get_subject(&self) -> Option<&str> { match self { + Attributes::V03(a) => a.get_subject(), Attributes::V10(a) => a.get_subject(), } } fn get_time(&self) -> Option<&DateTime> { match self { + Attributes::V03(a) => a.get_time(), Attributes::V10(a) => a.get_time(), } } @@ -93,30 +101,35 @@ impl AttributesReader for Attributes { impl AttributesWriter for Attributes { fn set_id(&mut self, id: impl Into) { match self { + Attributes::V03(a) => a.set_id(id), Attributes::V10(a) => a.set_id(id), } } fn set_source(&mut self, source: impl Into) { match self { + Attributes::V03(a) => a.set_source(source), Attributes::V10(a) => a.set_source(source), } } fn set_type(&mut self, ty: impl Into) { match self { + Attributes::V03(a) => a.set_type(ty), Attributes::V10(a) => a.set_type(ty), } } fn set_subject(&mut self, subject: Option>) { match self { + Attributes::V03(a) => a.set_subject(subject), Attributes::V10(a) => a.set_subject(subject), } } fn set_time(&mut self, time: Option>>) { match self { + Attributes::V03(a) => a.set_time(time), Attributes::V10(a) => a.set_time(time), } } @@ -125,12 +138,14 @@ impl AttributesWriter for Attributes { impl DataAttributesWriter for Attributes { fn set_datacontenttype(&mut self, datacontenttype: Option>) { match self { + Attributes::V03(a) => a.set_datacontenttype(datacontenttype), Attributes::V10(a) => a.set_datacontenttype(datacontenttype), } } fn set_dataschema(&mut self, dataschema: Option>) { match self { + Attributes::V03(a) => a.set_dataschema(dataschema), Attributes::V10(a) => a.set_dataschema(dataschema), } } diff --git a/src/event/mod.rs b/src/event/mod.rs index 507e6de7..3af14943 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -15,6 +15,13 @@ pub use event::Event; pub use extensions::ExtensionValue; pub use spec_version::SpecVersion; +mod v03; + +pub use v03::Attributes as AttributesV03; +pub use v03::EventBuilder as EventBuilderV03; +pub(crate) use v03::EventDeserializer as EventDeserializerV03; +pub(crate) use v03::EventSerializer as EventSerializerV03; + mod v10; pub use v10::Attributes as AttributesV10; diff --git a/src/event/serde.rs b/src/event/serde.rs index cdaee561..9551c5a0 100644 --- a/src/event/serde.rs +++ b/src/event/serde.rs @@ -1,4 +1,4 @@ -use super::{Attributes, Data, Event, EventDeserializerV10, EventSerializerV10}; +use super::{Attributes, Data, Event, EventDeserializerV03, EventDeserializerV10, EventSerializerV03, EventSerializerV10}; use crate::event::ExtensionValue; use serde::de::{Error, IntoDeserializer, Unexpected}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -71,6 +71,7 @@ impl<'de> Deserialize<'de> for Event { match parse_field!(map, "specversion", String, >::Error)? .as_str() { + "0.3" => Ok(EventDeserializerV03 {}), "1.0" => Ok(EventDeserializerV10 {}), s => Err(>::Error::unknown_variant( s, @@ -100,6 +101,9 @@ impl Serialize for Event { S: Serializer, { match &self.attributes { + Attributes::V03(a) => { + EventSerializerV03::serialize(a, &self.data, &self.extensions, serializer) + } Attributes::V10(a) => { EventSerializerV10::serialize(a, &self.data, &self.extensions, serializer) } diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs new file mode 100644 index 00000000..c71ffd64 --- /dev/null +++ b/src/event/v03/attributes.rs @@ -0,0 +1,105 @@ +use crate::event::attributes::DataAttributesWriter; +use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; +use chrono::{DateTime, Utc}; +use hostname::get_hostname; +use uuid::Uuid; + +#[derive(PartialEq, Debug, Clone)] +pub struct Attributes { + pub(crate) id: String, + pub(crate) ty: String, + pub(crate) source: String, + pub(crate) datacontenttype: Option, + pub(crate) schemaurl: Option, + pub(crate) subject: Option, + pub(crate) time: Option>, +} + +impl AttributesReader for Attributes { + fn get_id(&self) -> &str { + &self.id + } + + fn get_source(&self) -> &str { + &self.source + } + + fn get_specversion(&self) -> SpecVersion { + SpecVersion::V10 + } + + fn get_type(&self) -> &str { + &self.ty + } + + fn get_datacontenttype(&self) -> Option<&str> { + match self.datacontenttype.as_ref() { + Some(s) => Some(&s), + None => None, + } + } + + fn get_dataschema(&self) -> Option<&str> { + match self.schemaurl.as_ref() { + Some(s) => Some(&s), + None => None, + } + } + + fn get_subject(&self) -> Option<&str> { + match self.subject.as_ref() { + Some(s) => Some(&s), + None => None, + } + } + + fn get_time(&self) -> Option<&DateTime> { + self.time.as_ref() + } +} + +impl AttributesWriter for Attributes { + fn set_id(&mut self, id: impl Into) { + self.id = id.into() + } + + fn set_source(&mut self, source: impl Into) { + self.source = source.into() + } + + fn set_type(&mut self, ty: impl Into) { + self.ty = ty.into() + } + + fn set_subject(&mut self, subject: Option>) { + self.subject = subject.map(Into::into) + } + + fn set_time(&mut self, time: Option>>) { + self.time = time.map(Into::into) + } +} + +impl DataAttributesWriter for Attributes { + fn set_datacontenttype(&mut self, datacontenttype: Option>) { + self.datacontenttype = datacontenttype.map(Into::into) + } + + fn set_dataschema(&mut self, dataschema: Option>) { + self.schemaurl = dataschema.map(Into::into) + } +} + +impl Default for Attributes { + fn default() -> Self { + Attributes { + id: Uuid::new_v4().to_string(), + ty: "type".to_string(), + source: get_hostname().unwrap_or("http://localhost/".to_string()), + datacontenttype: None, + schemaurl: None, + subject: None, + time: None, + } + } +} diff --git a/src/event/v03/builder.rs b/src/event/v03/builder.rs new file mode 100644 index 00000000..a3ca71ff --- /dev/null +++ b/src/event/v03/builder.rs @@ -0,0 +1,127 @@ +use super::Attributes as AttributesV03; +use crate::event::{Attributes, AttributesWriter, Data, Event, ExtensionValue}; +use chrono::{DateTime, Utc}; +use std::collections::HashMap; + +pub struct EventBuilder { + event: Event, +} + +impl EventBuilder { + // This works as soon as we have an event version converter + // pub fn from(event: Event) -> Self { + // EventBuilder { event } + // } + + pub fn new() -> Self { + EventBuilder { + event: Event { + attributes: Attributes::V03(AttributesV03::default()), + data: None, + extensions: HashMap::new(), + }, + } + } + + pub fn id(mut self, id: impl Into) -> Self { + self.event.set_id(id); + return self; + } + + pub fn source(mut self, source: impl Into) -> Self { + self.event.set_source(source); + return self; + } + + pub fn ty(mut self, ty: impl Into) -> Self { + self.event.set_type(ty); + return self; + } + + pub fn subject(mut self, subject: impl Into) -> Self { + self.event.set_subject(Some(subject)); + return self; + } + + pub fn time(mut self, time: impl Into>) -> Self { + self.event.set_time(Some(time)); + return self; + } + + pub fn extension( + mut self, + extension_name: &str, + extension_value: impl Into, + ) -> Self { + self.event.set_extension(extension_name, extension_value); + return self; + } + + pub fn data(mut self, datacontenttype: impl Into, data: impl Into) -> Self { + self.event.write_data(datacontenttype, data); + return self; + } + + pub fn data_with_schema( + mut self, + datacontenttype: impl Into, + schemaurl: impl Into, + data: impl Into, + ) -> Self { + self.event + .write_data_with_schema(datacontenttype, schemaurl, data); + return self; + } + + pub fn build(self) -> Event { + self.event + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::event::{AttributesReader, SpecVersion}; + + #[test] + fn build_event() { + let id = "aaa"; + let source = "http://localhost:8080"; + let ty = "bbb"; + let subject = "francesco"; + let time: DateTime = Utc::now(); + let extension_name = "ext"; + let extension_value = 10i64; + let content_type = "application/json"; + let schema = "http://localhost:8080/schema"; + let data = serde_json::json!({ + "hello": "world" + }); + + let event = EventBuilder::new() + .id(id) + .source(source) + .ty(ty) + .subject(subject) + .time(time) + .extension(extension_name, extension_value) + .data_with_schema(content_type, schema, data.clone()) + .build(); + + assert_eq!(SpecVersion::V03, event.get_specversion()); + assert_eq!(id, event.get_id()); + assert_eq!(source, event.get_source()); + assert_eq!(ty, event.get_type()); + assert_eq!(subject, event.get_subject().unwrap()); + assert_eq!(time, event.get_time().unwrap().clone()); + assert_eq!( + ExtensionValue::from(extension_value), + event.get_extension(extension_name).unwrap().clone() + ); + assert_eq!(content_type, event.get_datacontenttype().unwrap()); + assert_eq!(schema, event.get_dataschema().unwrap()); + + let event_data: serde_json::Value = event.try_get_data().unwrap().unwrap(); + assert_eq!(data, event_data); + } +} diff --git a/src/event/v03/mod.rs b/src/event/v03/mod.rs index e69de29b..cb483d29 100644 --- a/src/event/v03/mod.rs +++ b/src/event/v03/mod.rs @@ -0,0 +1,8 @@ +mod attributes; +mod builder; +mod serde; + +pub(crate) use crate::event::v03::serde::EventDeserializer; +pub(crate) use crate::event::v03::serde::EventSerializer; +pub use attributes::Attributes; +pub use builder::EventBuilder; \ No newline at end of file diff --git a/src/event/v03/serde.rs b/src/event/v03/serde.rs new file mode 100644 index 00000000..fa155c8a --- /dev/null +++ b/src/event/v03/serde.rs @@ -0,0 +1,112 @@ +use super::Attributes; +use crate::event::{Data, ExtensionValue}; +use chrono::{DateTime, Utc}; +use serde::de::{IntoDeserializer, Unexpected}; +use serde::ser::SerializeMap; +use serde::{Deserialize, Serializer}; +use serde_value::Value; +use std::collections::{BTreeMap, HashMap}; + +pub(crate) struct EventDeserializer {} + +impl crate::event::serde::EventDeserializer for EventDeserializer { + fn deserialize_attributes( + &self, + map: &mut BTreeMap, + ) -> Result { + Ok(crate::event::Attributes::V03(Attributes { + id: parse_field!(map, "id", String, E)?, + ty: parse_field!(map, "type", String, E)?, + source: parse_field!(map, "source", String, E)?, + datacontenttype: parse_optional_field!(map, "datacontenttype", String, E)?, + schemaurl: parse_optional_field!(map, "schemaurl", String, E)?, + subject: parse_optional_field!(map, "subject", String, E)?, + time: parse_optional_field!(map, "time", String, E)? + .map(|s| match DateTime::parse_from_rfc3339(&s) { + Ok(d) => Ok(DateTime::::from(d)), + Err(e) => Err(E::invalid_value( + Unexpected::Str(&s), + &e.to_string().as_str(), + )), + }) + .transpose()?, + })) + } + + fn deserialize_data( + &self, + map: &mut BTreeMap, + ) -> Result, E> { + let data = map.remove("data"); + let data_base64 = map.remove("data_base64"); + + match (data, data_base64) { + (Some(d), None) => Ok(Some(Data::Json( + serde_json::Value::deserialize(d.into_deserializer()).map_err(|e| E::custom(e))?, + ))), + (None, Some(d)) => match d { + Value::String(s) => Ok(Some(Data::from_base64(s.clone()).map_err(|e| { + E::invalid_value(Unexpected::Str(&s), &e.to_string().as_str()) + })?)), + other => Err(E::invalid_type( + crate::event::serde::value_to_unexpected(&other), + &"a string", + )), + }, + (Some(_), Some(_)) => Err(E::custom("Cannot have both data and data_base64 field")), + (None, None) => Ok(None), + } + } +} + +pub(crate) struct EventSerializer {} + +impl crate::event::serde::EventSerializer for EventSerializer { + fn serialize( + attributes: &Attributes, + data: &Option, + extensions: &HashMap, + serializer: S, + ) -> Result<::Ok, ::Error> { + let num = + 3 + if attributes.datacontenttype.is_some() { + 1 + } else { + 0 + } + if attributes.schemaurl.is_some() { + 1 + } else { + 0 + } + if attributes.subject.is_some() { 1 } else { 0 } + + if attributes.time.is_some() { 1 } else { 0 } + + if data.is_some() { 1 } else { 0 } + + extensions.len(); + let mut state = serializer.serialize_map(Some(num))?; + state.serialize_entry("specversion", "1.0")?; + state.serialize_entry("id", &attributes.id)?; + state.serialize_entry("type", &attributes.ty)?; + state.serialize_entry("source", &attributes.source)?; + if let Some(datacontenttype) = &attributes.datacontenttype { + state.serialize_entry("datacontenttype", datacontenttype)?; + } + if let Some(dataschema) = &attributes.schemaurl { + state.serialize_entry("dataschema", dataschema)?; + } + if let Some(subject) = &attributes.subject { + state.serialize_entry("subject", subject)?; + } + if let Some(time) = &attributes.time { + state.serialize_entry("time", time)?; + } + match data { + Some(Data::Json(j)) => state.serialize_entry("data", j)?, + Some(Data::String(s)) => state.serialize_entry("data", s)?, + Some(Data::Binary(v)) => state.serialize_entry("data_base64", &base64::encode(v))?, + _ => (), + }; + for (k, v) in extensions { + state.serialize_entry(k, v)?; + } + state.end() + } +} From d213d550734c3f7fb878d9b4078a15e683406dbc Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Tue, 7 Apr 2020 14:58:08 +0200 Subject: [PATCH 3/9] Reworked EventDeserializer trait Signed-off-by: Francesco Guardiani --- src/event/serde.rs | 47 +++++++++++++++++++++--------------------- src/event/v03/serde.rs | 6 ++---- src/event/v10/serde.rs | 2 -- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/event/serde.rs b/src/event/serde.rs index 9551c5a0..4007822c 100644 --- a/src/event/serde.rs +++ b/src/event/serde.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_value::Value; use std::collections::{BTreeMap, HashMap}; -const SPEC_VERSIONS: [&'static str; 1] = ["1.0"]; +const SPEC_VERSIONS: [&'static str; 2] = ["0.3", "1.0"]; macro_rules! parse_optional_field { ($map:ident, $name:literal, $value_variant:ident, $error:ty) => { @@ -30,14 +30,29 @@ macro_rules! parse_field { pub(crate) trait EventDeserializer { fn deserialize_attributes( - &self, map: &mut BTreeMap, ) -> Result; fn deserialize_data( - &self, map: &mut BTreeMap, ) -> Result, E>; + + fn deserialize_event(mut map: BTreeMap) -> Result + { + let attributes = Self::deserialize_attributes(&mut map)?; + let data = Self::deserialize_data(&mut map)?; + let extensions = map + .into_iter() + .map(|(k, v)| Ok((k, ExtensionValue::deserialize(v.into_deserializer())?))) + .collect::, serde_value::DeserializerError>>() + .map_err(|e| E::custom(e))?; + + Ok(Event { + attributes, + data, + extensions, + }) + } } pub(crate) trait EventSerializer { @@ -67,31 +82,15 @@ impl<'de> Deserialize<'de> for Event { }) .collect::, >::Error>>()?; - let event_deserializer = - match parse_field!(map, "specversion", String, >::Error)? - .as_str() + match parse_field!(map, "specversion", String, >::Error)?.as_str() { - "0.3" => Ok(EventDeserializerV03 {}), - "1.0" => Ok(EventDeserializerV10 {}), - s => Err(>::Error::unknown_variant( + "0.3" => EventDeserializerV03::deserialize_event(map), + "1.0" => EventDeserializerV10::deserialize_event(map), + s => Err(D::Error::unknown_variant( s, &SPEC_VERSIONS, )), - }?; - - let attributes = event_deserializer.deserialize_attributes(&mut map)?; - let data = event_deserializer.deserialize_data(&mut map)?; - let extensions = map - .into_iter() - .map(|(k, v)| Ok((k, ExtensionValue::deserialize(v.into_deserializer())?))) - .collect::, serde_value::DeserializerError>>() - .map_err(|e| >::Error::custom(e))?; - - Ok(Event { - attributes, - data, - extensions, - }) + } } } diff --git a/src/event/v03/serde.rs b/src/event/v03/serde.rs index fa155c8a..3be0b212 100644 --- a/src/event/v03/serde.rs +++ b/src/event/v03/serde.rs @@ -11,7 +11,6 @@ pub(crate) struct EventDeserializer {} impl crate::event::serde::EventDeserializer for EventDeserializer { fn deserialize_attributes( - &self, map: &mut BTreeMap, ) -> Result { Ok(crate::event::Attributes::V03(Attributes { @@ -34,7 +33,6 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { } fn deserialize_data( - &self, map: &mut BTreeMap, ) -> Result, E> { let data = map.remove("data"); @@ -89,8 +87,8 @@ impl crate::event::serde::EventSerializer f if let Some(datacontenttype) = &attributes.datacontenttype { state.serialize_entry("datacontenttype", datacontenttype)?; } - if let Some(dataschema) = &attributes.schemaurl { - state.serialize_entry("dataschema", dataschema)?; + if let Some(schemaurl) = &attributes.schemaurl { + state.serialize_entry("schemaurl", schemaurl)?; } if let Some(subject) = &attributes.subject { state.serialize_entry("subject", subject)?; diff --git a/src/event/v10/serde.rs b/src/event/v10/serde.rs index ee12a9d3..ddc59817 100644 --- a/src/event/v10/serde.rs +++ b/src/event/v10/serde.rs @@ -11,7 +11,6 @@ pub(crate) struct EventDeserializer {} impl crate::event::serde::EventDeserializer for EventDeserializer { fn deserialize_attributes( - &self, map: &mut BTreeMap, ) -> Result { Ok(crate::event::Attributes::V10(Attributes { @@ -34,7 +33,6 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { } fn deserialize_data( - &self, map: &mut BTreeMap, ) -> Result, E> { let data = map.remove("data"); From 7fa7e224d39db3fcc401e6e648a7520d2392a849 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Tue, 7 Apr 2020 17:28:21 +0200 Subject: [PATCH 4/9] Now event parsing works with v1 and changes Signed-off-by: Francesco Guardiani --- src/event/data.rs | 72 ++++++++++++++++++++----------------- src/event/serde.rs | 40 +++++++++++++++++++-- src/event/v03/attributes.rs | 2 +- src/event/v03/serde.rs | 1 + src/event/v10/serde.rs | 30 ++++++++-------- tests/serde_json.rs | 4 +-- tests/test_data/mod.rs | 10 +++--- 7 files changed, 101 insertions(+), 58 deletions(-) diff --git a/src/event/data.rs b/src/event/data.rs index eeab81c7..e511e512 100644 --- a/src/event/data.rs +++ b/src/event/data.rs @@ -33,6 +33,10 @@ impl Data { } } +pub(crate) fn is_json_content_type(ct: &str) -> bool { + ct == "application/json" || ct == "text/json" || ct.ends_with("+json") +} + impl Into for serde_json::Value { fn into(self) -> Data { Data::Json(self) @@ -51,36 +55,38 @@ impl Into for String { } } -// impl TryFrom for serde_json::Value { -// type Error = serde_json::Error; -// -// fn try_from(value: Data) -> Result { -// match value { -// Data::Binary(v) => Ok(serde_json::from_slice(&v)?), -// Data::Json(v) => Ok(v), -// } -// } -// } -// -// impl TryFrom for Vec { -// type Error = serde_json::Error; -// -// fn try_from(value: Data) -> Result { -// match value { -// Data::Binary(v) => Ok(serde_json::from_slice(&v)?), -// Data::Json(v) => Ok(serde_json::to_vec(&v)?), -// } -// } -// } -// -// impl TryFrom for String { -// type Error = std::string::FromUtf8Error; -// -// fn try_from(value: Data) -> Result { -// match value { -// Data::Binary(v) => Ok(String::from_utf8(v)?), -// Data::Json(serde_json::Value::String(s)) => Ok(s), // Return the string without quotes -// Data::Json(v) => Ok(v.to_string()), -// } -// } -// } +impl TryFrom for serde_json::Value { + type Error = serde_json::Error; + + fn try_from(value: Data) -> Result { + match value { + Data::Binary(v) => Ok(serde_json::from_slice(&v)?), + Data::Json(v) => Ok(v), + Data::String(s) => Ok(serde_json::from_str(&s)?), + } + } +} + +impl TryFrom for Vec { + type Error = serde_json::Error; + + fn try_from(value: Data) -> Result { + match value { + Data::Binary(v) => Ok(serde_json::from_slice(&v)?), + Data::Json(v) => Ok(serde_json::to_vec(&v)?), + Data::String(s) => Ok(s.into_bytes()), + } + } +} + +impl TryFrom for String { + type Error = std::string::FromUtf8Error; + + fn try_from(value: Data) -> Result { + match value { + Data::Binary(v) => Ok(String::from_utf8(v)?), + Data::Json(v) => Ok(v.to_string()), + Data::String(s) => Ok(s), + } + } +} diff --git a/src/event/serde.rs b/src/event/serde.rs index 4007822c..1bb09bad 100644 --- a/src/event/serde.rs +++ b/src/event/serde.rs @@ -1,5 +1,5 @@ use super::{Attributes, Data, Event, EventDeserializerV03, EventDeserializerV10, EventSerializerV03, EventSerializerV10}; -use crate::event::ExtensionValue; +use crate::event::{ExtensionValue, AttributesReader}; use serde::de::{Error, IntoDeserializer, Unexpected}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_value::Value; @@ -28,19 +28,55 @@ macro_rules! parse_field { }; } +macro_rules! parse_data_json { + ($in:ident, $error:ty) => { + Ok(serde_json::Value::deserialize($in.into_deserializer()).map_err(|e| <$error>::custom(e))?) + }; +} + +macro_rules! parse_data_string { + ($in:ident, $error:ty) => { + match $in { + Value::String(s) => Ok(s), + other => Err(E::invalid_type( + crate::event::serde::value_to_unexpected(&other), + &"a string", + )), + } + }; +} + +macro_rules! parse_data_base64 { + ($in:ident, $error:ty) => { + match $in { + Value::String(s) => base64::decode(&s).map_err(|e| { + <$error>::invalid_value(serde::de::Unexpected::Str(&s), &e.to_string().as_str()) + }), + other => Err(E::invalid_type( + crate::event::serde::value_to_unexpected(&other), + &"a string", + )), + } + }; +} + pub(crate) trait EventDeserializer { fn deserialize_attributes( map: &mut BTreeMap, ) -> Result; fn deserialize_data( + content_type: &str, map: &mut BTreeMap, ) -> Result, E>; fn deserialize_event(mut map: BTreeMap) -> Result { let attributes = Self::deserialize_attributes(&mut map)?; - let data = Self::deserialize_data(&mut map)?; + let data = Self::deserialize_data( + attributes.get_datacontenttype().unwrap_or("application/json"), + &mut map + )?; let extensions = map .into_iter() .map(|(k, v)| Ok((k, ExtensionValue::deserialize(v.into_deserializer())?))) diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs index c71ffd64..4adc125e 100644 --- a/src/event/v03/attributes.rs +++ b/src/event/v03/attributes.rs @@ -25,7 +25,7 @@ impl AttributesReader for Attributes { } fn get_specversion(&self) -> SpecVersion { - SpecVersion::V10 + SpecVersion::V03 } fn get_type(&self) -> &str { diff --git a/src/event/v03/serde.rs b/src/event/v03/serde.rs index 3be0b212..129ad3c3 100644 --- a/src/event/v03/serde.rs +++ b/src/event/v03/serde.rs @@ -33,6 +33,7 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { } fn deserialize_data( + content_type: &str, map: &mut BTreeMap, ) -> Result, E> { let data = map.remove("data"); diff --git a/src/event/v10/serde.rs b/src/event/v10/serde.rs index ddc59817..f8e27f22 100644 --- a/src/event/v10/serde.rs +++ b/src/event/v10/serde.rs @@ -6,6 +6,8 @@ use serde::ser::SerializeMap; use serde::{Deserialize, Serializer}; use serde_value::Value; use std::collections::{BTreeMap, HashMap}; +use crate::event::data::is_json_content_type; +use std::convert::TryInto; pub(crate) struct EventDeserializer {} @@ -33,27 +35,25 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { } fn deserialize_data( + content_type: &str, map: &mut BTreeMap, ) -> Result, E> { let data = map.remove("data"); let data_base64 = map.remove("data_base64"); - match (data, data_base64) { - (Some(d), None) => Ok(Some(Data::Json( - serde_json::Value::deserialize(d.into_deserializer()).map_err(|e| E::custom(e))?, - ))), - (None, Some(d)) => match d { - Value::String(s) => Ok(Some(Data::from_base64(s.clone()).map_err(|e| { - E::invalid_value(Unexpected::Str(&s), &e.to_string().as_str()) - })?)), - other => Err(E::invalid_type( - crate::event::serde::value_to_unexpected(&other), - &"a string", - )), + let is_json = is_json_content_type(content_type); + + Ok(match (data, data_base64, is_json) { + (Some(d), None, true) => Some(Data::Json(parse_data_json!(d, E)?)), + (Some(d), None, false) => Some(Data::String(parse_data_string!(d, E)?)), + (None, Some(d), true) => { + let data = parse_data_base64!(d, E)?; + Some(Data::Json(serde_json::from_slice(&data).map_err(|e| E::custom(e))?)) }, - (Some(_), Some(_)) => Err(E::custom("Cannot have both data and data_base64 field")), - (None, None) => Ok(None), - } + (None, Some(d), false) => Some(Data::Binary(parse_data_base64!(d, E)?)), + (Some(_), Some(_), _) => Err(E::custom("Cannot have both data and data_base64 field"))?, + (None, None, _) => None, + }) } } diff --git a/tests/serde_json.rs b/tests/serde_json.rs index d433e7c1..d249264f 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -14,7 +14,7 @@ use test_data::*; case::full_v1_no_data(full_v1_no_data(), full_v1_no_data_json()), case::full_v1_with_json_data(full_v1_json_data(), full_v1_json_data_json()), case::full_v1_with_xml_string_data(full_v1_xml_string_data(), full_v1_xml_string_data_json()), - case::full_v1_with_xml_base64_data(full_v1_xml_binary_data(), full_v1_xml_base64_data_json()) + case::full_v1_with_xml_base64_data(full_v1_xml_binary_data(), full_v1_xml_base64_data_json()), )] fn serialize_should_succeed(in_event: Event, out_json: Value) { // Event -> serde_json::Value @@ -42,7 +42,7 @@ fn serialize_should_succeed(in_event: Event, out_json: Value) { case::minimal_v1(minimal_v1_json(), minimal_v1()), case::full_v1_no_data(full_v1_no_data_json(), full_v1_no_data()), case::full_v1_with_json_data(full_v1_json_data_json(), full_v1_json_data()), - case::full_v1_with_json_base64_data(full_v1_json_base64_data_json(), full_v1_json_data()) + case::full_v1_with_json_base64_data(full_v1_json_base64_data_json(), full_v1_json_data()), case::full_v1_with_xml_string_data(full_v1_xml_string_data_json(), full_v1_xml_string_data()), case::full_v1_with_xml_base64_data(full_v1_xml_base64_data_json(), full_v1_xml_binary_data()) )] diff --git a/tests/test_data/mod.rs b/tests/test_data/mod.rs index 76e69b9f..e09d1b9b 100644 --- a/tests/test_data/mod.rs +++ b/tests/test_data/mod.rs @@ -30,7 +30,7 @@ pub fn json_data() -> Value { json!({"hello": "world"}) } -pub fn json_data_base64() -> Vec { +pub fn json_data_binary() -> Vec { serde_json::to_vec(&json!({"hello": "world"})).unwrap() } @@ -143,9 +143,9 @@ pub fn full_v1_json_data_json() -> Value { string_ext_name: string_ext_value, bool_ext_name: bool_ext_value, int_ext_name: int_ext_value, - "datacontenttype": datacontenttype(), + "datacontenttype": json_datacontenttype(), "dataschema": dataschema(), - "data": data() + "data": json_data() }) } @@ -164,9 +164,9 @@ pub fn full_v1_json_base64_data_json() -> Value { string_ext_name: string_ext_value, bool_ext_name: bool_ext_value, int_ext_name: int_ext_value, - "datacontenttype": datacontenttype(), + "datacontenttype": json_datacontenttype(), "dataschema": dataschema(), - "data_base64": base64::encode(&json_data_base64()) + "data_base64": base64::encode(&json_data_binary()) }) } From 4a644a832713358c1120cf892d7ee62c22b6d1d7 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Tue, 7 Apr 2020 17:28:58 +0200 Subject: [PATCH 5/9] Cargo fmt Signed-off-by: Francesco Guardiani --- src/event/attributes.rs | 2 +- src/event/serde.rs | 63 +++++++++++++++++++++-------------------- src/event/v03/mod.rs | 2 +- src/event/v03/serde.rs | 7 ++--- src/event/v10/serde.rs | 8 ++++-- tests/serde_json.rs | 6 ++-- tests/test_data/mod.rs | 2 +- 7 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/event/attributes.rs b/src/event/attributes.rs index 6857a984..cd679701 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -1,4 +1,4 @@ -use super::{SpecVersion, AttributesV10, AttributesV03}; +use super::{AttributesV03, AttributesV10, SpecVersion}; use chrono::{DateTime, Utc}; /// Trait to get [CloudEvents Context attributes](https://github.com/cloudevents/spec/blob/master/spec.md#context-attributes). diff --git a/src/event/serde.rs b/src/event/serde.rs index 1bb09bad..c66cfada 100644 --- a/src/event/serde.rs +++ b/src/event/serde.rs @@ -1,5 +1,8 @@ -use super::{Attributes, Data, Event, EventDeserializerV03, EventDeserializerV10, EventSerializerV03, EventSerializerV10}; -use crate::event::{ExtensionValue, AttributesReader}; +use super::{ + Attributes, Data, Event, EventDeserializerV03, EventDeserializerV10, EventSerializerV03, + EventSerializerV10, +}; +use crate::event::{AttributesReader, ExtensionValue}; use serde::de::{Error, IntoDeserializer, Unexpected}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_value::Value; @@ -30,33 +33,34 @@ macro_rules! parse_field { macro_rules! parse_data_json { ($in:ident, $error:ty) => { - Ok(serde_json::Value::deserialize($in.into_deserializer()).map_err(|e| <$error>::custom(e))?) + Ok(serde_json::Value::deserialize($in.into_deserializer()) + .map_err(|e| <$error>::custom(e))?) }; } macro_rules! parse_data_string { ($in:ident, $error:ty) => { match $in { - Value::String(s) => Ok(s), - other => Err(E::invalid_type( - crate::event::serde::value_to_unexpected(&other), - &"a string", - )), - } + Value::String(s) => Ok(s), + other => Err(E::invalid_type( + crate::event::serde::value_to_unexpected(&other), + &"a string", + )), + } }; } macro_rules! parse_data_base64 { ($in:ident, $error:ty) => { match $in { - Value::String(s) => base64::decode(&s).map_err(|e| { - <$error>::invalid_value(serde::de::Unexpected::Str(&s), &e.to_string().as_str()) - }), - other => Err(E::invalid_type( - crate::event::serde::value_to_unexpected(&other), - &"a string", - )), - } + Value::String(s) => base64::decode(&s).map_err(|e| { + <$error>::invalid_value(serde::de::Unexpected::Str(&s), &e.to_string().as_str()) + }), + other => Err(E::invalid_type( + crate::event::serde::value_to_unexpected(&other), + &"a string", + )), + } }; } @@ -70,12 +74,15 @@ pub(crate) trait EventDeserializer { map: &mut BTreeMap, ) -> Result, E>; - fn deserialize_event(mut map: BTreeMap) -> Result - { + fn deserialize_event( + mut map: BTreeMap, + ) -> Result { let attributes = Self::deserialize_attributes(&mut map)?; let data = Self::deserialize_data( - attributes.get_datacontenttype().unwrap_or("application/json"), - &mut map + attributes + .get_datacontenttype() + .unwrap_or("application/json"), + &mut map, )?; let extensions = map .into_iter() @@ -118,15 +125,11 @@ impl<'de> Deserialize<'de> for Event { }) .collect::, >::Error>>()?; - match parse_field!(map, "specversion", String, >::Error)?.as_str() - { - "0.3" => EventDeserializerV03::deserialize_event(map), - "1.0" => EventDeserializerV10::deserialize_event(map), - s => Err(D::Error::unknown_variant( - s, - &SPEC_VERSIONS, - )), - } + match parse_field!(map, "specversion", String, >::Error)?.as_str() { + "0.3" => EventDeserializerV03::deserialize_event(map), + "1.0" => EventDeserializerV10::deserialize_event(map), + s => Err(D::Error::unknown_variant(s, &SPEC_VERSIONS)), + } } } diff --git a/src/event/v03/mod.rs b/src/event/v03/mod.rs index cb483d29..4ab6a7a0 100644 --- a/src/event/v03/mod.rs +++ b/src/event/v03/mod.rs @@ -5,4 +5,4 @@ mod serde; pub(crate) use crate::event::v03::serde::EventDeserializer; pub(crate) use crate::event::v03::serde::EventSerializer; pub use attributes::Attributes; -pub use builder::EventBuilder; \ No newline at end of file +pub use builder::EventBuilder; diff --git a/src/event/v03/serde.rs b/src/event/v03/serde.rs index 129ad3c3..c6922741 100644 --- a/src/event/v03/serde.rs +++ b/src/event/v03/serde.rs @@ -72,11 +72,8 @@ impl crate::event::serde::EventSerializer f 1 } else { 0 - } + if attributes.schemaurl.is_some() { - 1 - } else { - 0 - } + if attributes.subject.is_some() { 1 } else { 0 } + } + if attributes.schemaurl.is_some() { 1 } else { 0 } + + if attributes.subject.is_some() { 1 } else { 0 } + if attributes.time.is_some() { 1 } else { 0 } + if data.is_some() { 1 } else { 0 } + extensions.len(); diff --git a/src/event/v10/serde.rs b/src/event/v10/serde.rs index f8e27f22..715c24be 100644 --- a/src/event/v10/serde.rs +++ b/src/event/v10/serde.rs @@ -1,4 +1,5 @@ use super::Attributes; +use crate::event::data::is_json_content_type; use crate::event::{Data, ExtensionValue}; use chrono::{DateTime, Utc}; use serde::de::{IntoDeserializer, Unexpected}; @@ -6,7 +7,6 @@ use serde::ser::SerializeMap; use serde::{Deserialize, Serializer}; use serde_value::Value; use std::collections::{BTreeMap, HashMap}; -use crate::event::data::is_json_content_type; use std::convert::TryInto; pub(crate) struct EventDeserializer {} @@ -48,8 +48,10 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { (Some(d), None, false) => Some(Data::String(parse_data_string!(d, E)?)), (None, Some(d), true) => { let data = parse_data_base64!(d, E)?; - Some(Data::Json(serde_json::from_slice(&data).map_err(|e| E::custom(e))?)) - }, + Some(Data::Json( + serde_json::from_slice(&data).map_err(|e| E::custom(e))?, + )) + } (None, Some(d), false) => Some(Data::Binary(parse_data_base64!(d, E)?)), (Some(_), Some(_), _) => Err(E::custom("Cannot have both data and data_base64 field"))?, (None, None, _) => None, diff --git a/tests/serde_json.rs b/tests/serde_json.rs index d249264f..dd2cb60a 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -14,7 +14,7 @@ use test_data::*; case::full_v1_no_data(full_v1_no_data(), full_v1_no_data_json()), case::full_v1_with_json_data(full_v1_json_data(), full_v1_json_data_json()), case::full_v1_with_xml_string_data(full_v1_xml_string_data(), full_v1_xml_string_data_json()), - case::full_v1_with_xml_base64_data(full_v1_xml_binary_data(), full_v1_xml_base64_data_json()), + case::full_v1_with_xml_base64_data(full_v1_xml_binary_data(), full_v1_xml_base64_data_json()) )] fn serialize_should_succeed(in_event: Event, out_json: Value) { // Event -> serde_json::Value @@ -47,10 +47,8 @@ fn serialize_should_succeed(in_event: Event, out_json: Value) { case::full_v1_with_xml_base64_data(full_v1_xml_base64_data_json(), full_v1_xml_binary_data()) )] fn deserialize_should_succeed(in_json: Value, out_event: Event) { - let deserialize_result: Result = - serde_json::from_value(in_json); + let deserialize_result: Result = serde_json::from_value(in_json); assert_ok!(&deserialize_result); let deserialize_json = deserialize_result.unwrap(); assert_eq!(deserialize_json, out_event) } - diff --git a/tests/test_data/mod.rs b/tests/test_data/mod.rs index e09d1b9b..bc2b401b 100644 --- a/tests/test_data/mod.rs +++ b/tests/test_data/mod.rs @@ -244,4 +244,4 @@ pub fn full_v1_xml_base64_data_json() -> Value { "datacontenttype": xml_datacontenttype(), "data_base64": base64::encode(Vec::from(xml_data())) }) -} \ No newline at end of file +} From eb4cc7a1af94f047a195b27dc0150b2aafe69ccf Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Tue, 7 Apr 2020 18:07:16 +0200 Subject: [PATCH 6/9] Reorganized test data Signed-off-by: Francesco Guardiani --- src/event/builder.rs | 12 +- src/event/serde.rs | 9 ++ src/event/v10/serde.rs | 7 +- tests/serde_json.rs | 22 ++-- tests/test_data/data.rs | 59 ++++++++++ tests/test_data/mod.rs | 250 +--------------------------------------- tests/test_data/v03.rs | 192 ++++++++++++++++++++++++++++++ tests/test_data/v10.rs | 192 ++++++++++++++++++++++++++++++ 8 files changed, 479 insertions(+), 264 deletions(-) create mode 100644 tests/test_data/data.rs create mode 100644 tests/test_data/v03.rs create mode 100644 tests/test_data/v10.rs diff --git a/src/event/builder.rs b/src/event/builder.rs index b72dbc87..a7c2a011 100644 --- a/src/event/builder.rs +++ b/src/event/builder.rs @@ -1,4 +1,4 @@ -use super::EventBuilderV10; +use super::{EventBuilderV10, EventBuilderV03}; /// Builder to create [`Event`]: /// ``` @@ -14,8 +14,18 @@ use super::EventBuilderV10; pub struct EventBuilder {} impl EventBuilder { + /// Creates a new builder for latest CloudEvents version + pub fn new() -> EventBuilderV10 { + return Self::v10(); + } + /// Creates a new builder for CloudEvents V1.0 pub fn v10() -> EventBuilderV10 { return EventBuilderV10::new(); } + + /// Creates a new builder for CloudEvents V0.3 + pub fn v03() -> EventBuilderV03 { + return EventBuilderV03::new(); + } } diff --git a/src/event/serde.rs b/src/event/serde.rs index c66cfada..d88e27ae 100644 --- a/src/event/serde.rs +++ b/src/event/serde.rs @@ -50,6 +50,15 @@ macro_rules! parse_data_string { }; } +macro_rules! parse_json_data_base64 { + ($in:ident, $error:ty) => { + { + let data = parse_data_base64!($in, $error)?; + serde_json::from_slice(&data).map_err(|e| <$error>::custom(e)) + } + }; +} + macro_rules! parse_data_base64 { ($in:ident, $error:ty) => { match $in { diff --git a/src/event/v10/serde.rs b/src/event/v10/serde.rs index 715c24be..4f51725d 100644 --- a/src/event/v10/serde.rs +++ b/src/event/v10/serde.rs @@ -46,12 +46,7 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { Ok(match (data, data_base64, is_json) { (Some(d), None, true) => Some(Data::Json(parse_data_json!(d, E)?)), (Some(d), None, false) => Some(Data::String(parse_data_string!(d, E)?)), - (None, Some(d), true) => { - let data = parse_data_base64!(d, E)?; - Some(Data::Json( - serde_json::from_slice(&data).map_err(|e| E::custom(e))?, - )) - } + (None, Some(d), true) => Some(Data::Json(parse_json_data_base64!(d, E)?)), (None, Some(d), false) => Some(Data::Binary(parse_data_base64!(d, E)?)), (Some(_), Some(_), _) => Err(E::custom("Cannot have both data and data_base64 field"))?, (None, None, _) => None, diff --git a/tests/serde_json.rs b/tests/serde_json.rs index dd2cb60a..9bc7b3d1 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -10,11 +10,11 @@ use test_data::*; #[rstest( in_event, out_json, - case::minimal_v1(minimal_v1(), minimal_v1_json()), - case::full_v1_no_data(full_v1_no_data(), full_v1_no_data_json()), - case::full_v1_with_json_data(full_v1_json_data(), full_v1_json_data_json()), - case::full_v1_with_xml_string_data(full_v1_xml_string_data(), full_v1_xml_string_data_json()), - case::full_v1_with_xml_base64_data(full_v1_xml_binary_data(), full_v1_xml_base64_data_json()) + case::minimal_v1(v10::minimal(), v10::minimal_json()), + case::full_v1_no_data(v10::full_no_data(), v10::full_no_data_json()), + case::full_v1_with_json_data(v10::full_json_data(), v10::full_json_data_json()), + case::full_v1_with_xml_string_data(v10::full_xml_string_data(), v10::full_xml_string_data_json()), + case::full_v1_with_xml_base64_data(v10::full_xml_binary_data(), v10::full_xml_base64_data_json()) )] fn serialize_should_succeed(in_event: Event, out_json: Value) { // Event -> serde_json::Value @@ -39,12 +39,12 @@ fn serialize_should_succeed(in_event: Event, out_json: Value) { #[rstest( in_json, out_event, - case::minimal_v1(minimal_v1_json(), minimal_v1()), - case::full_v1_no_data(full_v1_no_data_json(), full_v1_no_data()), - case::full_v1_with_json_data(full_v1_json_data_json(), full_v1_json_data()), - case::full_v1_with_json_base64_data(full_v1_json_base64_data_json(), full_v1_json_data()), - case::full_v1_with_xml_string_data(full_v1_xml_string_data_json(), full_v1_xml_string_data()), - case::full_v1_with_xml_base64_data(full_v1_xml_base64_data_json(), full_v1_xml_binary_data()) + case::minimal_v1(v10::minimal_json(), v10::minimal()), + case::full_v1_no_data(v10::full_no_data_json(), v10::full_no_data()), + case::full_v1_with_json_data(v10::full_json_data_json(), v10::full_json_data()), + case::full_v1_with_json_base64_data(v10::full_json_base64_data_json(), v10::full_json_data()), + case::full_v1_with_xml_string_data(v10::full_xml_string_data_json(), v10::full_xml_string_data()), + case::full_v1_with_xml_base64_data(v10::full_xml_base64_data_json(), v10::full_xml_binary_data()) )] fn deserialize_should_succeed(in_json: Value, out_event: Event) { let deserialize_result: Result = serde_json::from_value(in_json); diff --git a/tests/test_data/data.rs b/tests/test_data/data.rs new file mode 100644 index 00000000..eacec1d1 --- /dev/null +++ b/tests/test_data/data.rs @@ -0,0 +1,59 @@ +use chrono::{DateTime, TimeZone, Utc}; +use cloudevents::{Event, EventBuilder}; +use serde_json::{json, Value}; + +pub fn id() -> String { + "0001".to_string() +} + +pub fn ty() -> String { + "test_event.test_application".to_string() +} + +pub fn source() -> String { + "http://localhost".to_string() +} + +pub fn json_datacontenttype() -> String { + "application/json".to_string() +} + +pub fn xml_datacontenttype() -> String { + "application/xml".to_string() +} + +pub fn dataschema() -> String { + "http://localhost/schema".to_string() +} + +pub fn json_data() -> Value { + json!({"hello": "world"}) +} + +pub fn json_data_binary() -> Vec { + serde_json::to_vec(&json!({"hello": "world"})).unwrap() +} + +pub fn xml_data() -> String { + "world".to_string() +} + +pub fn subject() -> String { + "cloudevents-sdk".to_string() +} + +pub fn time() -> DateTime { + Utc.ymd(2020, 3, 16).and_hms(11, 50, 00) +} + +pub fn string_extension() -> (String, String) { + ("string_ex".to_string(), "val".to_string()) +} + +pub fn bool_extension() -> (String, bool) { + ("bool_ex".to_string(), true) +} + +pub fn int_extension() -> (String, i64) { + ("int_ex".to_string(), 10) +} \ No newline at end of file diff --git a/tests/test_data/mod.rs b/tests/test_data/mod.rs index bc2b401b..2e4f45c3 100644 --- a/tests/test_data/mod.rs +++ b/tests/test_data/mod.rs @@ -1,247 +1,5 @@ -use chrono::{DateTime, TimeZone, Utc}; -use cloudevents::{Event, EventBuilder}; -use serde_json::{json, Value}; +mod data; +pub use data::*; -pub fn id() -> String { - "0001".to_string() -} - -pub fn ty() -> String { - "test_event.test_application".to_string() -} - -pub fn source() -> String { - "http://localhost".to_string() -} - -pub fn json_datacontenttype() -> String { - "application/json".to_string() -} - -pub fn xml_datacontenttype() -> String { - "application/xml".to_string() -} - -pub fn dataschema() -> String { - "http://localhost/schema".to_string() -} - -pub fn json_data() -> Value { - json!({"hello": "world"}) -} - -pub fn json_data_binary() -> Vec { - serde_json::to_vec(&json!({"hello": "world"})).unwrap() -} - -pub fn xml_data() -> String { - "world".to_string() -} - -pub fn subject() -> String { - "cloudevents-sdk".to_string() -} - -pub fn time() -> DateTime { - Utc.ymd(2020, 3, 16).and_hms(11, 50, 00) -} - -pub fn string_extension() -> (String, String) { - ("string_ex".to_string(), "val".to_string()) -} - -pub fn bool_extension() -> (String, bool) { - ("bool_ex".to_string(), true) -} - -pub fn int_extension() -> (String, i64) { - ("int_ex".to_string(), 10) -} - -pub fn minimal_v1() -> Event { - EventBuilder::v10() - .id(id()) - .source(source()) - .ty(ty()) - .build() -} - -pub fn minimal_v1_json() -> Value { - json!({ - "specversion": "1.0", - "id": id(), - "type": ty(), - "source": source(), - }) -} - -pub fn full_v1_no_data() -> Event { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - EventBuilder::v10() - .id(id()) - .source(source()) - .ty(ty()) - .subject(subject()) - .time(time()) - .extension(&string_ext_name, string_ext_value) - .extension(&bool_ext_name, bool_ext_value) - .extension(&int_ext_name, int_ext_value) - .build() -} - -pub fn full_v1_no_data_json() -> Value { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - json!({ - "specversion": "1.0", - "id": id(), - "type": ty(), - "source": source(), - "subject": subject(), - "time": time(), - string_ext_name: string_ext_value, - bool_ext_name: bool_ext_value, - int_ext_name: int_ext_value - }) -} - -pub fn full_v1_json_data() -> Event { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - EventBuilder::v10() - .id(id()) - .source(source()) - .ty(ty()) - .subject(subject()) - .time(time()) - .extension(&string_ext_name, string_ext_value) - .extension(&bool_ext_name, bool_ext_value) - .extension(&int_ext_name, int_ext_value) - .data_with_schema(json_datacontenttype(), dataschema(), json_data()) - .build() -} - -pub fn full_v1_json_data_json() -> Value { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - json!({ - "specversion": "1.0", - "id": id(), - "type": ty(), - "source": source(), - "subject": subject(), - "time": time(), - string_ext_name: string_ext_value, - bool_ext_name: bool_ext_value, - int_ext_name: int_ext_value, - "datacontenttype": json_datacontenttype(), - "dataschema": dataschema(), - "data": json_data() - }) -} - -pub fn full_v1_json_base64_data_json() -> Value { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - json!({ - "specversion": "1.0", - "id": id(), - "type": ty(), - "source": source(), - "subject": subject(), - "time": time(), - string_ext_name: string_ext_value, - bool_ext_name: bool_ext_value, - int_ext_name: int_ext_value, - "datacontenttype": json_datacontenttype(), - "dataschema": dataschema(), - "data_base64": base64::encode(&json_data_binary()) - }) -} - -pub fn full_v1_xml_string_data() -> Event { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - EventBuilder::v10() - .id(id()) - .source(source()) - .ty(ty()) - .subject(subject()) - .time(time()) - .extension(&string_ext_name, string_ext_value) - .extension(&bool_ext_name, bool_ext_value) - .extension(&int_ext_name, int_ext_value) - .data(xml_datacontenttype(), xml_data()) - .build() -} - -pub fn full_v1_xml_binary_data() -> Event { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - EventBuilder::v10() - .id(id()) - .source(source()) - .ty(ty()) - .subject(subject()) - .time(time()) - .extension(&string_ext_name, string_ext_value) - .extension(&bool_ext_name, bool_ext_value) - .extension(&int_ext_name, int_ext_value) - .data(xml_datacontenttype(), Vec::from(xml_data())) - .build() -} - -pub fn full_v1_xml_string_data_json() -> Value { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - json!({ - "specversion": "1.0", - "id": id(), - "type": ty(), - "source": source(), - "subject": subject(), - "time": time(), - string_ext_name: string_ext_value, - bool_ext_name: bool_ext_value, - int_ext_name: int_ext_value, - "datacontenttype": xml_datacontenttype(), - "data": xml_data() - }) -} - -pub fn full_v1_xml_base64_data_json() -> Value { - let (string_ext_name, string_ext_value) = string_extension(); - let (bool_ext_name, bool_ext_value) = bool_extension(); - let (int_ext_name, int_ext_value) = int_extension(); - - json!({ - "specversion": "1.0", - "id": id(), - "type": ty(), - "source": source(), - "subject": subject(), - "time": time(), - string_ext_name: string_ext_value, - bool_ext_name: bool_ext_value, - int_ext_name: int_ext_value, - "datacontenttype": xml_datacontenttype(), - "data_base64": base64::encode(Vec::from(xml_data())) - }) -} +pub mod v03; +pub mod v10; diff --git a/tests/test_data/v03.rs b/tests/test_data/v03.rs new file mode 100644 index 00000000..6822fa09 --- /dev/null +++ b/tests/test_data/v03.rs @@ -0,0 +1,192 @@ +use chrono::{DateTime, TimeZone, Utc}; +use cloudevents::{Event, EventBuilder}; +use serde_json::{json, Value}; +use super::*; + +pub fn minimal() -> Event { + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .build() +} + +pub fn minimal_json() -> Value { + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + }) +} + +pub fn full_no_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .build() +} + +pub fn full_no_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value + }) +} + +pub fn full_json_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data_with_schema(json_datacontenttype(), dataschema(), json_data()) + .build() +} + +pub fn full_json_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": json_datacontenttype(), + "dataschema": dataschema(), + "data": json_data() + }) +} + +pub fn full_json_base64_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": json_datacontenttype(), + "dataschema": dataschema(), + "data_base64": base64::encode(&json_data_binary()) + }) +} + +pub fn full_xml_string_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data(xml_datacontenttype(), xml_data()) + .build() +} + +pub fn full_xml_binary_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data(xml_datacontenttype(), Vec::from(xml_data())) + .build() +} + +pub fn full_xml_string_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": xml_datacontenttype(), + "data": xml_data() + }) +} + +pub fn full_xml_base64_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": xml_datacontenttype(), + "data_base64": base64::encode(Vec::from(xml_data())) + }) +} \ No newline at end of file diff --git a/tests/test_data/v10.rs b/tests/test_data/v10.rs new file mode 100644 index 00000000..6822fa09 --- /dev/null +++ b/tests/test_data/v10.rs @@ -0,0 +1,192 @@ +use chrono::{DateTime, TimeZone, Utc}; +use cloudevents::{Event, EventBuilder}; +use serde_json::{json, Value}; +use super::*; + +pub fn minimal() -> Event { + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .build() +} + +pub fn minimal_json() -> Value { + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + }) +} + +pub fn full_no_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .build() +} + +pub fn full_no_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value + }) +} + +pub fn full_json_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data_with_schema(json_datacontenttype(), dataschema(), json_data()) + .build() +} + +pub fn full_json_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": json_datacontenttype(), + "dataschema": dataschema(), + "data": json_data() + }) +} + +pub fn full_json_base64_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": json_datacontenttype(), + "dataschema": dataschema(), + "data_base64": base64::encode(&json_data_binary()) + }) +} + +pub fn full_xml_string_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data(xml_datacontenttype(), xml_data()) + .build() +} + +pub fn full_xml_binary_data() -> Event { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + EventBuilder::v10() + .id(id()) + .source(source()) + .ty(ty()) + .subject(subject()) + .time(time()) + .extension(&string_ext_name, string_ext_value) + .extension(&bool_ext_name, bool_ext_value) + .extension(&int_ext_name, int_ext_value) + .data(xml_datacontenttype(), Vec::from(xml_data())) + .build() +} + +pub fn full_xml_string_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": xml_datacontenttype(), + "data": xml_data() + }) +} + +pub fn full_xml_base64_data_json() -> Value { + let (string_ext_name, string_ext_value) = string_extension(); + let (bool_ext_name, bool_ext_value) = bool_extension(); + let (int_ext_name, int_ext_value) = int_extension(); + + json!({ + "specversion": "1.0", + "id": id(), + "type": ty(), + "source": source(), + "subject": subject(), + "time": time(), + string_ext_name: string_ext_value, + bool_ext_name: bool_ext_value, + int_ext_name: int_ext_value, + "datacontenttype": xml_datacontenttype(), + "data_base64": base64::encode(Vec::from(xml_data())) + }) +} \ No newline at end of file From 517bc066743332ef623511d55b911c4b21f8f074 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Tue, 7 Apr 2020 20:00:37 +0200 Subject: [PATCH 7/9] Fixed serde for v03 Signed-off-by: Francesco Guardiani --- src/event/builder.rs | 2 +- src/event/serde.rs | 10 +++----- src/event/v03/serde.rs | 40 +++++++++++++++-------------- src/event/v10/serde.rs | 1 - tests/event.rs | 2 -- tests/serde_json.rs | 57 +++++++++++++++++++++++++++++++++-------- tests/test_data/data.rs | 3 +-- tests/test_data/v03.rs | 37 +++++++++++++------------- tests/test_data/v10.rs | 5 ++-- 9 files changed, 94 insertions(+), 63 deletions(-) delete mode 100644 tests/event.rs diff --git a/src/event/builder.rs b/src/event/builder.rs index a7c2a011..5dbfef35 100644 --- a/src/event/builder.rs +++ b/src/event/builder.rs @@ -1,4 +1,4 @@ -use super::{EventBuilderV10, EventBuilderV03}; +use super::{EventBuilderV03, EventBuilderV10}; /// Builder to create [`Event`]: /// ``` diff --git a/src/event/serde.rs b/src/event/serde.rs index d88e27ae..c3910097 100644 --- a/src/event/serde.rs +++ b/src/event/serde.rs @@ -51,12 +51,10 @@ macro_rules! parse_data_string { } macro_rules! parse_json_data_base64 { - ($in:ident, $error:ty) => { - { - let data = parse_data_base64!($in, $error)?; - serde_json::from_slice(&data).map_err(|e| <$error>::custom(e)) - } - }; + ($in:ident, $error:ty) => {{ + let data = parse_data_base64!($in, $error)?; + serde_json::from_slice(&data).map_err(|e| <$error>::custom(e)) + }}; } macro_rules! parse_data_base64 { diff --git a/src/event/v03/serde.rs b/src/event/v03/serde.rs index c6922741..58f0f650 100644 --- a/src/event/v03/serde.rs +++ b/src/event/v03/serde.rs @@ -1,4 +1,5 @@ use super::Attributes; +use crate::event::data::is_json_content_type; use crate::event::{Data, ExtensionValue}; use chrono::{DateTime, Utc}; use serde::de::{IntoDeserializer, Unexpected}; @@ -37,24 +38,22 @@ impl crate::event::serde::EventDeserializer for EventDeserializer { map: &mut BTreeMap, ) -> Result, E> { let data = map.remove("data"); - let data_base64 = map.remove("data_base64"); + let is_base64 = map + .remove("datacontentencoding") + .map(String::deserialize) + .transpose() + .map_err(|e| E::custom(e))? + .map(|dce| dce.to_lowercase() == "base64") + .unwrap_or(false); + let is_json = is_json_content_type(content_type); - match (data, data_base64) { - (Some(d), None) => Ok(Some(Data::Json( - serde_json::Value::deserialize(d.into_deserializer()).map_err(|e| E::custom(e))?, - ))), - (None, Some(d)) => match d { - Value::String(s) => Ok(Some(Data::from_base64(s.clone()).map_err(|e| { - E::invalid_value(Unexpected::Str(&s), &e.to_string().as_str()) - })?)), - other => Err(E::invalid_type( - crate::event::serde::value_to_unexpected(&other), - &"a string", - )), - }, - (Some(_), Some(_)) => Err(E::custom("Cannot have both data and data_base64 field")), - (None, None) => Ok(None), - } + Ok(match (data, is_base64, is_json) { + (Some(d), false, true) => Some(Data::Json(parse_data_json!(d, E)?)), + (Some(d), false, false) => Some(Data::String(parse_data_string!(d, E)?)), + (Some(d), true, true) => Some(Data::Json(parse_json_data_base64!(d, E)?)), + (Some(d), true, false) => Some(Data::Binary(parse_data_base64!(d, E)?)), + (None, _, _) => None, + }) } } @@ -78,7 +77,7 @@ impl crate::event::serde::EventSerializer f + if data.is_some() { 1 } else { 0 } + extensions.len(); let mut state = serializer.serialize_map(Some(num))?; - state.serialize_entry("specversion", "1.0")?; + state.serialize_entry("specversion", "0.3")?; state.serialize_entry("id", &attributes.id)?; state.serialize_entry("type", &attributes.ty)?; state.serialize_entry("source", &attributes.source)?; @@ -97,7 +96,10 @@ impl crate::event::serde::EventSerializer f match data { Some(Data::Json(j)) => state.serialize_entry("data", j)?, Some(Data::String(s)) => state.serialize_entry("data", s)?, - Some(Data::Binary(v)) => state.serialize_entry("data_base64", &base64::encode(v))?, + Some(Data::Binary(v)) => { + state.serialize_entry("data", &base64::encode(v))?; + state.serialize_entry("datacontentencoding", "base64")?; + } _ => (), }; for (k, v) in extensions { diff --git a/src/event/v10/serde.rs b/src/event/v10/serde.rs index 4f51725d..fa219549 100644 --- a/src/event/v10/serde.rs +++ b/src/event/v10/serde.rs @@ -7,7 +7,6 @@ use serde::ser::SerializeMap; use serde::{Deserialize, Serializer}; use serde_value::Value; use std::collections::{BTreeMap, HashMap}; -use std::convert::TryInto; pub(crate) struct EventDeserializer {} diff --git a/tests/event.rs b/tests/event.rs deleted file mode 100644 index 7ad4c3a3..00000000 --- a/tests/event.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[test] -fn use_event() {} diff --git a/tests/serde_json.rs b/tests/serde_json.rs index 9bc7b3d1..14f01619 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -10,11 +10,28 @@ use test_data::*; #[rstest( in_event, out_json, - case::minimal_v1(v10::minimal(), v10::minimal_json()), - case::full_v1_no_data(v10::full_no_data(), v10::full_no_data_json()), - case::full_v1_with_json_data(v10::full_json_data(), v10::full_json_data_json()), - case::full_v1_with_xml_string_data(v10::full_xml_string_data(), v10::full_xml_string_data_json()), - case::full_v1_with_xml_base64_data(v10::full_xml_binary_data(), v10::full_xml_base64_data_json()) + case::minimal_v03(v03::minimal(), v03::minimal_json()), + case::full_v03_no_data(v03::full_no_data(), v03::full_no_data_json()), + case::full_v03_with_json_data(v03::full_json_data(), v03::full_json_data_json()), + case::full_v03_with_xml_string_data( + v03::full_xml_string_data(), + v03::full_xml_string_data_json() + ), + case::full_v03_with_xml_base64_data( + v03::full_xml_binary_data(), + v03::full_xml_base64_data_json() + ), + case::minimal_v10(v10::minimal(), v10::minimal_json()), + case::full_v10_no_data(v10::full_no_data(), v10::full_no_data_json()), + case::full_v10_with_json_data(v10::full_json_data(), v10::full_json_data_json()), + case::full_v10_with_xml_string_data( + v10::full_xml_string_data(), + v10::full_xml_string_data_json() + ), + case::full_v10_with_xml_base64_data( + v10::full_xml_binary_data(), + v10::full_xml_base64_data_json() + ) )] fn serialize_should_succeed(in_event: Event, out_json: Value) { // Event -> serde_json::Value @@ -39,12 +56,30 @@ fn serialize_should_succeed(in_event: Event, out_json: Value) { #[rstest( in_json, out_event, - case::minimal_v1(v10::minimal_json(), v10::minimal()), - case::full_v1_no_data(v10::full_no_data_json(), v10::full_no_data()), - case::full_v1_with_json_data(v10::full_json_data_json(), v10::full_json_data()), - case::full_v1_with_json_base64_data(v10::full_json_base64_data_json(), v10::full_json_data()), - case::full_v1_with_xml_string_data(v10::full_xml_string_data_json(), v10::full_xml_string_data()), - case::full_v1_with_xml_base64_data(v10::full_xml_base64_data_json(), v10::full_xml_binary_data()) + case::minimal_v03(v03::minimal_json(), v03::minimal()), + case::full_v03_no_data(v03::full_no_data_json(), v03::full_no_data()), + case::full_v03_with_json_data(v03::full_json_data_json(), v03::full_json_data()), + case::full_v03_with_json_base64_data(v03::full_json_base64_data_json(), v03::full_json_data()), + case::full_v03_with_xml_string_data( + v03::full_xml_string_data_json(), + v03::full_xml_string_data() + ), + case::full_v03_with_xml_base64_data( + v03::full_xml_base64_data_json(), + v03::full_xml_binary_data() + ), + case::minimal_v10(v10::minimal_json(), v10::minimal()), + case::full_v10_no_data(v10::full_no_data_json(), v10::full_no_data()), + case::full_v10_with_json_data(v10::full_json_data_json(), v10::full_json_data()), + case::full_v10_with_json_base64_data(v10::full_json_base64_data_json(), v10::full_json_data()), + case::full_v10_with_xml_string_data( + v10::full_xml_string_data_json(), + v10::full_xml_string_data() + ), + case::full_v10_with_xml_base64_data( + v10::full_xml_base64_data_json(), + v10::full_xml_binary_data() + ) )] fn deserialize_should_succeed(in_json: Value, out_event: Event) { let deserialize_result: Result = serde_json::from_value(in_json); diff --git a/tests/test_data/data.rs b/tests/test_data/data.rs index eacec1d1..087b20d2 100644 --- a/tests/test_data/data.rs +++ b/tests/test_data/data.rs @@ -1,5 +1,4 @@ use chrono::{DateTime, TimeZone, Utc}; -use cloudevents::{Event, EventBuilder}; use serde_json::{json, Value}; pub fn id() -> String { @@ -56,4 +55,4 @@ pub fn bool_extension() -> (String, bool) { pub fn int_extension() -> (String, i64) { ("int_ex".to_string(), 10) -} \ No newline at end of file +} diff --git a/tests/test_data/v03.rs b/tests/test_data/v03.rs index 6822fa09..00e53478 100644 --- a/tests/test_data/v03.rs +++ b/tests/test_data/v03.rs @@ -1,10 +1,9 @@ -use chrono::{DateTime, TimeZone, Utc}; +use super::*; use cloudevents::{Event, EventBuilder}; use serde_json::{json, Value}; -use super::*; pub fn minimal() -> Event { - EventBuilder::v10() + EventBuilder::v03() .id(id()) .source(source()) .ty(ty()) @@ -13,7 +12,7 @@ pub fn minimal() -> Event { pub fn minimal_json() -> Value { json!({ - "specversion": "1.0", + "specversion": "0.3", "id": id(), "type": ty(), "source": source(), @@ -25,7 +24,7 @@ pub fn full_no_data() -> Event { let (bool_ext_name, bool_ext_value) = bool_extension(); let (int_ext_name, int_ext_value) = int_extension(); - EventBuilder::v10() + EventBuilder::v03() .id(id()) .source(source()) .ty(ty()) @@ -43,7 +42,7 @@ pub fn full_no_data_json() -> Value { let (int_ext_name, int_ext_value) = int_extension(); json!({ - "specversion": "1.0", + "specversion": "0.3", "id": id(), "type": ty(), "source": source(), @@ -60,7 +59,7 @@ pub fn full_json_data() -> Event { let (bool_ext_name, bool_ext_value) = bool_extension(); let (int_ext_name, int_ext_value) = int_extension(); - EventBuilder::v10() + EventBuilder::v03() .id(id()) .source(source()) .ty(ty()) @@ -79,7 +78,7 @@ pub fn full_json_data_json() -> Value { let (int_ext_name, int_ext_value) = int_extension(); json!({ - "specversion": "1.0", + "specversion": "0.3", "id": id(), "type": ty(), "source": source(), @@ -89,7 +88,7 @@ pub fn full_json_data_json() -> Value { bool_ext_name: bool_ext_value, int_ext_name: int_ext_value, "datacontenttype": json_datacontenttype(), - "dataschema": dataschema(), + "schemaurl": dataschema(), "data": json_data() }) } @@ -100,7 +99,7 @@ pub fn full_json_base64_data_json() -> Value { let (int_ext_name, int_ext_value) = int_extension(); json!({ - "specversion": "1.0", + "specversion": "0.3", "id": id(), "type": ty(), "source": source(), @@ -110,8 +109,9 @@ pub fn full_json_base64_data_json() -> Value { bool_ext_name: bool_ext_value, int_ext_name: int_ext_value, "datacontenttype": json_datacontenttype(), - "dataschema": dataschema(), - "data_base64": base64::encode(&json_data_binary()) + "schemaurl": dataschema(), + "datacontentencoding": "base64", + "data": base64::encode(&json_data_binary()) }) } @@ -120,7 +120,7 @@ pub fn full_xml_string_data() -> Event { let (bool_ext_name, bool_ext_value) = bool_extension(); let (int_ext_name, int_ext_value) = int_extension(); - EventBuilder::v10() + EventBuilder::v03() .id(id()) .source(source()) .ty(ty()) @@ -138,7 +138,7 @@ pub fn full_xml_binary_data() -> Event { let (bool_ext_name, bool_ext_value) = bool_extension(); let (int_ext_name, int_ext_value) = int_extension(); - EventBuilder::v10() + EventBuilder::v03() .id(id()) .source(source()) .ty(ty()) @@ -157,7 +157,7 @@ pub fn full_xml_string_data_json() -> Value { let (int_ext_name, int_ext_value) = int_extension(); json!({ - "specversion": "1.0", + "specversion": "0.3", "id": id(), "type": ty(), "source": source(), @@ -177,7 +177,7 @@ pub fn full_xml_base64_data_json() -> Value { let (int_ext_name, int_ext_value) = int_extension(); json!({ - "specversion": "1.0", + "specversion": "0.3", "id": id(), "type": ty(), "source": source(), @@ -187,6 +187,7 @@ pub fn full_xml_base64_data_json() -> Value { bool_ext_name: bool_ext_value, int_ext_name: int_ext_value, "datacontenttype": xml_datacontenttype(), - "data_base64": base64::encode(Vec::from(xml_data())) + "datacontentencoding": "base64", + "data": base64::encode(Vec::from(xml_data())) }) -} \ No newline at end of file +} diff --git a/tests/test_data/v10.rs b/tests/test_data/v10.rs index 6822fa09..f564c4d6 100644 --- a/tests/test_data/v10.rs +++ b/tests/test_data/v10.rs @@ -1,7 +1,6 @@ -use chrono::{DateTime, TimeZone, Utc}; +use super::*; use cloudevents::{Event, EventBuilder}; use serde_json::{json, Value}; -use super::*; pub fn minimal() -> Event { EventBuilder::v10() @@ -189,4 +188,4 @@ pub fn full_xml_base64_data_json() -> Value { "datacontenttype": xml_datacontenttype(), "data_base64": base64::encode(Vec::from(xml_data())) }) -} \ No newline at end of file +} From 4750bf930e297313c88cc075f325e2d06e7ffc5b Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Wed, 8 Apr 2020 17:50:34 +0200 Subject: [PATCH 8/9] Implemented spec version conversion Signed-off-by: Francesco Guardiani --- src/event/attributes.rs | 20 ++++++++++++++++++++ src/event/v03/attributes.rs | 21 ++++++++++++++++++++- src/event/v03/builder.rs | 13 +++++++++---- src/event/v10/attributes.rs | 22 ++++++++++++++++++++-- src/event/v10/builder.rs | 13 +++++++++---- tests/version_conversion.rs | 17 +++++++++++++++++ 6 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 tests/version_conversion.rs diff --git a/src/event/attributes.rs b/src/event/attributes.rs index cd679701..d48d5d5f 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -29,6 +29,11 @@ pub trait AttributesWriter { fn set_time(&mut self, time: Option>>); } +pub (crate) trait AttributesConverter { + fn into_v03(self) -> AttributesV03; + fn into_v10(self) -> AttributesV10; +} + pub(crate) trait DataAttributesWriter { fn set_datacontenttype(&mut self, datacontenttype: Option>); fn set_dataschema(&mut self, dataschema: Option>); @@ -150,3 +155,18 @@ impl DataAttributesWriter for Attributes { } } } + +impl Attributes { + pub fn into_v10(self) -> Self { + match self { + Attributes::V03(v03) => Attributes::V10(v03.into_v10()), + _ => self + } + } + pub fn into_v03(self) -> Self { + match self { + Attributes::V10(v10) => Attributes::V03(v10.into_v03()), + _ => self + } + } +} \ No newline at end of file diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs index 4adc125e..5529eba0 100644 --- a/src/event/v03/attributes.rs +++ b/src/event/v03/attributes.rs @@ -1,5 +1,6 @@ -use crate::event::attributes::DataAttributesWriter; +use crate::event::attributes::{DataAttributesWriter, AttributesConverter}; use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; +use crate::event::AttributesV10; use chrono::{DateTime, Utc}; use hostname::get_hostname; use uuid::Uuid; @@ -103,3 +104,21 @@ impl Default for Attributes { } } } + +impl AttributesConverter for Attributes { + fn into_v03(self) -> Self { + self + } + + fn into_v10(self) -> AttributesV10 { + AttributesV10 { + id: self.id, + ty: self.ty, + source: self.source, + datacontenttype: self.datacontenttype, + dataschema: self.schemaurl, + subject: self.subject, + time: self.time + } + } +} diff --git a/src/event/v03/builder.rs b/src/event/v03/builder.rs index a3ca71ff..41aca7c4 100644 --- a/src/event/v03/builder.rs +++ b/src/event/v03/builder.rs @@ -8,10 +8,15 @@ pub struct EventBuilder { } impl EventBuilder { - // This works as soon as we have an event version converter - // pub fn from(event: Event) -> Self { - // EventBuilder { event } - // } + pub fn from(event: Event) -> Self { + EventBuilder { + event: Event { + attributes: event.attributes.into_v03(), + data: event.data, + extensions: event.extensions, + }, + } + } pub fn new() -> Self { EventBuilder { diff --git a/src/event/v10/attributes.rs b/src/event/v10/attributes.rs index 183f1a95..5878b5ed 100644 --- a/src/event/v10/attributes.rs +++ b/src/event/v10/attributes.rs @@ -1,5 +1,5 @@ -use crate::event::attributes::DataAttributesWriter; -use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; +use crate::event::attributes::{DataAttributesWriter, AttributesConverter}; +use crate::event::{AttributesReader, AttributesWriter, SpecVersion, AttributesV03}; use chrono::{DateTime, Utc}; use hostname::get_hostname; use uuid::Uuid; @@ -103,3 +103,21 @@ impl Default for Attributes { } } } + +impl AttributesConverter for Attributes { + fn into_v10(self) -> Self { + self + } + + fn into_v03(self) -> AttributesV03 { + AttributesV03 { + id: self.id, + ty: self.ty, + source: self.source, + datacontenttype: self.datacontenttype, + schemaurl: self.dataschema, + subject: self.subject, + time: self.time + } + } +} diff --git a/src/event/v10/builder.rs b/src/event/v10/builder.rs index 3b3ed949..9b7f8888 100644 --- a/src/event/v10/builder.rs +++ b/src/event/v10/builder.rs @@ -8,10 +8,15 @@ pub struct EventBuilder { } impl EventBuilder { - // This works as soon as we have an event version converter - // pub fn from(event: Event) -> Self { - // EventBuilder { event } - // } + pub fn from(event: Event) -> Self { + EventBuilder { + event: Event { + attributes: event.attributes.into_v10(), + data: event.data, + extensions: event.extensions, + }, + } + } pub fn new() -> Self { EventBuilder { diff --git a/tests/version_conversion.rs b/tests/version_conversion.rs new file mode 100644 index 00000000..fca10dbf --- /dev/null +++ b/tests/version_conversion.rs @@ -0,0 +1,17 @@ +mod test_data; +use test_data::*; +use cloudevents::event::{EventBuilderV10, EventBuilderV03}; + +#[test] +fn v10_to_v03() { + let in_event = v10::full_json_data(); + let out_event = EventBuilderV03::from(in_event).build(); + assert_eq!(v03::full_json_data(), out_event) +} + +#[test] +fn v03_to_v10() { + let in_event = v03::full_json_data(); + let out_event = EventBuilderV10::from(in_event).build(); + assert_eq!(v10::full_json_data(), out_event) +} \ No newline at end of file From ca2f828541178b881c071085ce6bdc22f01e0042 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Wed, 8 Apr 2020 17:51:47 +0200 Subject: [PATCH 9/9] cargo fmt Signed-off-by: Francesco Guardiani --- src/event/attributes.rs | 8 ++++---- src/event/v03/attributes.rs | 6 +++--- src/event/v10/attributes.rs | 6 +++--- tests/version_conversion.rs | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/event/attributes.rs b/src/event/attributes.rs index d48d5d5f..5cfa5be2 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -29,7 +29,7 @@ pub trait AttributesWriter { fn set_time(&mut self, time: Option>>); } -pub (crate) trait AttributesConverter { +pub(crate) trait AttributesConverter { fn into_v03(self) -> AttributesV03; fn into_v10(self) -> AttributesV10; } @@ -160,13 +160,13 @@ impl Attributes { pub fn into_v10(self) -> Self { match self { Attributes::V03(v03) => Attributes::V10(v03.into_v10()), - _ => self + _ => self, } } pub fn into_v03(self) -> Self { match self { Attributes::V10(v10) => Attributes::V03(v10.into_v03()), - _ => self + _ => self, } } -} \ No newline at end of file +} diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs index 5529eba0..1e75629e 100644 --- a/src/event/v03/attributes.rs +++ b/src/event/v03/attributes.rs @@ -1,6 +1,6 @@ -use crate::event::attributes::{DataAttributesWriter, AttributesConverter}; -use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; +use crate::event::attributes::{AttributesConverter, DataAttributesWriter}; use crate::event::AttributesV10; +use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; use chrono::{DateTime, Utc}; use hostname::get_hostname; use uuid::Uuid; @@ -118,7 +118,7 @@ impl AttributesConverter for Attributes { datacontenttype: self.datacontenttype, dataschema: self.schemaurl, subject: self.subject, - time: self.time + time: self.time, } } } diff --git a/src/event/v10/attributes.rs b/src/event/v10/attributes.rs index 5878b5ed..cd3d92b7 100644 --- a/src/event/v10/attributes.rs +++ b/src/event/v10/attributes.rs @@ -1,5 +1,5 @@ -use crate::event::attributes::{DataAttributesWriter, AttributesConverter}; -use crate::event::{AttributesReader, AttributesWriter, SpecVersion, AttributesV03}; +use crate::event::attributes::{AttributesConverter, DataAttributesWriter}; +use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersion}; use chrono::{DateTime, Utc}; use hostname::get_hostname; use uuid::Uuid; @@ -117,7 +117,7 @@ impl AttributesConverter for Attributes { datacontenttype: self.datacontenttype, schemaurl: self.dataschema, subject: self.subject, - time: self.time + time: self.time, } } } diff --git a/tests/version_conversion.rs b/tests/version_conversion.rs index fca10dbf..5ba05e99 100644 --- a/tests/version_conversion.rs +++ b/tests/version_conversion.rs @@ -1,6 +1,6 @@ mod test_data; +use cloudevents::event::{EventBuilderV03, EventBuilderV10}; use test_data::*; -use cloudevents::event::{EventBuilderV10, EventBuilderV03}; #[test] fn v10_to_v03() { @@ -14,4 +14,4 @@ fn v03_to_v10() { let in_event = v03::full_json_data(); let out_event = EventBuilderV10::from(in_event).build(); assert_eq!(v10::full_json_data(), out_event) -} \ No newline at end of file +}