V0.3 implementation (#24)
* Added String variant to Data Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Started V0.3 work Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Reworked EventDeserializer trait Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Now event parsing works with v1 and changes Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Cargo fmt Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Reorganized test data Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Fixed serde for v03 Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Implemented spec version conversion Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * cargo fmt Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
parent
ad7ec80cde
commit
e49453f4a6
|
@ -1,5 +1,4 @@
|
|||
use super::SpecVersion;
|
||||
use crate::event::AttributesV10;
|
||||
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).
|
||||
|
@ -30,6 +29,11 @@ pub trait AttributesWriter {
|
|||
fn set_time(&mut self, time: Option<impl Into<DateTime<Utc>>>);
|
||||
}
|
||||
|
||||
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<impl Into<String>>);
|
||||
fn set_dataschema(&mut self, dataschema: Option<impl Into<String>>);
|
||||
|
@ -37,54 +41,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<Utc>> {
|
||||
match self {
|
||||
Attributes::V03(a) => a.get_time(),
|
||||
Attributes::V10(a) => a.get_time(),
|
||||
}
|
||||
}
|
||||
|
@ -93,30 +106,35 @@ impl AttributesReader for Attributes {
|
|||
impl AttributesWriter for Attributes {
|
||||
fn set_id(&mut self, id: impl Into<String>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_id(id),
|
||||
Attributes::V10(a) => a.set_id(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_source(&mut self, source: impl Into<String>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_source(source),
|
||||
Attributes::V10(a) => a.set_source(source),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_type(&mut self, ty: impl Into<String>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_type(ty),
|
||||
Attributes::V10(a) => a.set_type(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_subject(&mut self, subject: Option<impl Into<String>>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_subject(subject),
|
||||
Attributes::V10(a) => a.set_subject(subject),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_time(&mut self, time: Option<impl Into<DateTime<Utc>>>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_time(time),
|
||||
Attributes::V10(a) => a.set_time(time),
|
||||
}
|
||||
}
|
||||
|
@ -125,13 +143,30 @@ impl AttributesWriter for Attributes {
|
|||
impl DataAttributesWriter for Attributes {
|
||||
fn set_datacontenttype(&mut self, datacontenttype: Option<impl Into<String>>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_datacontenttype(datacontenttype),
|
||||
Attributes::V10(a) => a.set_datacontenttype(datacontenttype),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_dataschema(&mut self, dataschema: Option<impl Into<String>>) {
|
||||
match self {
|
||||
Attributes::V03(a) => a.set_dataschema(dataschema),
|
||||
Attributes::V10(a) => a.set_dataschema(dataschema),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::EventBuilderV10;
|
||||
use super::{EventBuilderV03, EventBuilderV10};
|
||||
|
||||
/// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<u8>),
|
||||
/// Event has a non-json string payload
|
||||
String(String),
|
||||
/// Event has a json payload
|
||||
Json(serde_json::Value),
|
||||
}
|
||||
|
||||
|
@ -30,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<Data> for serde_json::Value {
|
||||
fn into(self) -> Data {
|
||||
Data::Json(self)
|
||||
|
@ -44,7 +51,7 @@ impl Into<Data> for Vec<u8> {
|
|||
|
||||
impl Into<Data> for String {
|
||||
fn into(self) -> Data {
|
||||
Data::Json(self.into())
|
||||
Data::String(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,6 +62,7 @@ impl TryFrom<Data> for serde_json::Value {
|
|||
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)?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +74,7 @@ impl TryFrom<Data> for Vec<u8> {
|
|||
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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +85,8 @@ impl TryFrom<Data> for String {
|
|||
fn try_from(value: Data) -> Result<Self, Self::Error> {
|
||||
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()),
|
||||
Data::String(s) => Ok(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use super::{Attributes, Data, Event, EventDeserializerV10, EventSerializerV10};
|
||||
use crate::event::ExtensionValue;
|
||||
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;
|
||||
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) => {
|
||||
|
@ -28,16 +31,78 @@ 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_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 {
|
||||
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<E: serde::de::Error>(
|
||||
&self,
|
||||
map: &mut BTreeMap<String, Value>,
|
||||
) -> Result<Attributes, E>;
|
||||
|
||||
fn deserialize_data<E: serde::de::Error>(
|
||||
&self,
|
||||
content_type: &str,
|
||||
map: &mut BTreeMap<String, Value>,
|
||||
) -> Result<Option<Data>, E>;
|
||||
|
||||
fn deserialize_event<E: serde::de::Error>(
|
||||
mut map: BTreeMap<String, Value>,
|
||||
) -> Result<Event, E> {
|
||||
let attributes = Self::deserialize_attributes(&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())?)))
|
||||
.collect::<Result<HashMap<String, ExtensionValue>, serde_value::DeserializerError>>()
|
||||
.map_err(|e| E::custom(e))?;
|
||||
|
||||
Ok(Event {
|
||||
attributes,
|
||||
data,
|
||||
extensions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait EventSerializer<S: Serializer, A: Sized> {
|
||||
|
@ -67,30 +132,11 @@ impl<'de> Deserialize<'de> for Event {
|
|||
})
|
||||
.collect::<Result<BTreeMap<String, Value>, <D as Deserializer<'de>>::Error>>()?;
|
||||
|
||||
let event_deserializer =
|
||||
match parse_field!(map, "specversion", String, <D as Deserializer<'de>>::Error)?
|
||||
.as_str()
|
||||
{
|
||||
"1.0" => Ok(EventDeserializerV10 {}),
|
||||
s => Err(<D as Deserializer<'de>>::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::<Result<HashMap<String, ExtensionValue>, serde_value::DeserializerError>>()
|
||||
.map_err(|e| <D as Deserializer<'de>>::Error::custom(e))?;
|
||||
|
||||
Ok(Event {
|
||||
attributes,
|
||||
data,
|
||||
extensions,
|
||||
})
|
||||
match parse_field!(map, "specversion", String, <D as Deserializer<'de>>::Error)?.as_str() {
|
||||
"0.3" => EventDeserializerV03::deserialize_event(map),
|
||||
"1.0" => EventDeserializerV10::deserialize_event(map),
|
||||
s => Err(D::Error::unknown_variant(s, &SPEC_VERSIONS)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +146,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)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
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;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct Attributes {
|
||||
pub(crate) id: String,
|
||||
pub(crate) ty: String,
|
||||
pub(crate) source: String,
|
||||
pub(crate) datacontenttype: Option<String>,
|
||||
pub(crate) schemaurl: Option<String>,
|
||||
pub(crate) subject: Option<String>,
|
||||
pub(crate) time: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl AttributesReader for Attributes {
|
||||
fn get_id(&self) -> &str {
|
||||
&self.id
|
||||
}
|
||||
|
||||
fn get_source(&self) -> &str {
|
||||
&self.source
|
||||
}
|
||||
|
||||
fn get_specversion(&self) -> SpecVersion {
|
||||
SpecVersion::V03
|
||||
}
|
||||
|
||||
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<Utc>> {
|
||||
self.time.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AttributesWriter for Attributes {
|
||||
fn set_id(&mut self, id: impl Into<String>) {
|
||||
self.id = id.into()
|
||||
}
|
||||
|
||||
fn set_source(&mut self, source: impl Into<String>) {
|
||||
self.source = source.into()
|
||||
}
|
||||
|
||||
fn set_type(&mut self, ty: impl Into<String>) {
|
||||
self.ty = ty.into()
|
||||
}
|
||||
|
||||
fn set_subject(&mut self, subject: Option<impl Into<String>>) {
|
||||
self.subject = subject.map(Into::into)
|
||||
}
|
||||
|
||||
fn set_time(&mut self, time: Option<impl Into<DateTime<Utc>>>) {
|
||||
self.time = time.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl DataAttributesWriter for Attributes {
|
||||
fn set_datacontenttype(&mut self, datacontenttype: Option<impl Into<String>>) {
|
||||
self.datacontenttype = datacontenttype.map(Into::into)
|
||||
}
|
||||
|
||||
fn set_dataschema(&mut self, dataschema: Option<impl Into<String>>) {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
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 {
|
||||
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 {
|
||||
event: Event {
|
||||
attributes: Attributes::V03(AttributesV03::default()),
|
||||
data: None,
|
||||
extensions: HashMap::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(mut self, id: impl Into<String>) -> Self {
|
||||
self.event.set_id(id);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn source(mut self, source: impl Into<String>) -> Self {
|
||||
self.event.set_source(source);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn ty(mut self, ty: impl Into<String>) -> Self {
|
||||
self.event.set_type(ty);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn subject(mut self, subject: impl Into<String>) -> Self {
|
||||
self.event.set_subject(Some(subject));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn time(mut self, time: impl Into<DateTime<Utc>>) -> Self {
|
||||
self.event.set_time(Some(time));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn extension(
|
||||
mut self,
|
||||
extension_name: &str,
|
||||
extension_value: impl Into<ExtensionValue>,
|
||||
) -> Self {
|
||||
self.event.set_extension(extension_name, extension_value);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn data(mut self, datacontenttype: impl Into<String>, data: impl Into<Data>) -> Self {
|
||||
self.event.write_data(datacontenttype, data);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn data_with_schema(
|
||||
mut self,
|
||||
datacontenttype: impl Into<String>,
|
||||
schemaurl: impl Into<String>,
|
||||
data: impl Into<Data>,
|
||||
) -> 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> = 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,110 @@
|
|||
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};
|
||||
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<E: serde::de::Error>(
|
||||
map: &mut BTreeMap<String, Value>,
|
||||
) -> Result<crate::event::Attributes, E> {
|
||||
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::<Utc>::from(d)),
|
||||
Err(e) => Err(E::invalid_value(
|
||||
Unexpected::Str(&s),
|
||||
&e.to_string().as_str(),
|
||||
)),
|
||||
})
|
||||
.transpose()?,
|
||||
}))
|
||||
}
|
||||
|
||||
fn deserialize_data<E: serde::de::Error>(
|
||||
content_type: &str,
|
||||
map: &mut BTreeMap<String, Value>,
|
||||
) -> Result<Option<Data>, E> {
|
||||
let data = map.remove("data");
|
||||
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);
|
||||
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct EventSerializer {}
|
||||
|
||||
impl<S: serde::Serializer> crate::event::serde::EventSerializer<S, Attributes> for EventSerializer {
|
||||
fn serialize(
|
||||
attributes: &Attributes,
|
||||
data: &Option<Data>,
|
||||
extensions: &HashMap<String, ExtensionValue>,
|
||||
serializer: S,
|
||||
) -> Result<<S as Serializer>::Ok, <S as Serializer>::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", "0.3")?;
|
||||
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(schemaurl) = &attributes.schemaurl {
|
||||
state.serialize_entry("schemaurl", schemaurl)?;
|
||||
}
|
||||
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::encode(v))?;
|
||||
state.serialize_entry("datacontentencoding", "base64")?;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
for (k, v) in extensions {
|
||||
state.serialize_entry(k, v)?;
|
||||
}
|
||||
state.end()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use crate::event::attributes::DataAttributesWriter;
|
||||
use crate::event::{AttributesReader, AttributesWriter, SpecVersion};
|
||||
use crate::event::attributes::{AttributesConverter, DataAttributesWriter};
|
||||
use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersion};
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
@ -11,7 +12,6 @@ pub(crate) struct EventDeserializer {}
|
|||
|
||||
impl crate::event::serde::EventDeserializer for EventDeserializer {
|
||||
fn deserialize_attributes<E: serde::de::Error>(
|
||||
&self,
|
||||
map: &mut BTreeMap<String, Value>,
|
||||
) -> Result<crate::event::Attributes, E> {
|
||||
Ok(crate::event::Attributes::V10(Attributes {
|
||||
|
@ -34,28 +34,22 @@ impl crate::event::serde::EventDeserializer for EventDeserializer {
|
|||
}
|
||||
|
||||
fn deserialize_data<E: serde::de::Error>(
|
||||
&self,
|
||||
content_type: &str,
|
||||
map: &mut BTreeMap<String, Value>,
|
||||
) -> Result<Option<Data>, 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),
|
||||
}
|
||||
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) => 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +94,7 @@ impl<S: serde::Serializer> crate::event::serde::EventSerializer<S, Attributes> 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))?,
|
||||
_ => (),
|
||||
};
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#[test]
|
||||
fn use_event() {}
|
|
@ -7,30 +7,83 @@ 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,
|
||||
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())
|
||||
in_event,
|
||||
out_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_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<Event, serde_json::Error> =
|
||||
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_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<Event, serde_json::Error> = serde_json::from_value(in_json);
|
||||
assert_ok!(&deserialize_result);
|
||||
let deserialize_json = deserialize_result.unwrap();
|
||||
assert_eq!(deserialize_json, out_event)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
use chrono::{DateTime, TimeZone, Utc};
|
||||
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<u8> {
|
||||
serde_json::to_vec(&json!({"hello": "world"})).unwrap()
|
||||
}
|
||||
|
||||
pub fn xml_data() -> String {
|
||||
"<hello>world</hello>".to_string()
|
||||
}
|
||||
|
||||
pub fn subject() -> String {
|
||||
"cloudevents-sdk".to_string()
|
||||
}
|
||||
|
||||
pub fn time() -> DateTime<Utc> {
|
||||
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)
|
||||
}
|
|
@ -1,183 +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 datacontenttype() -> String {
|
||||
"application/json".to_string()
|
||||
}
|
||||
|
||||
pub fn dataschema() -> String {
|
||||
"http://localhost/schema".to_string()
|
||||
}
|
||||
|
||||
pub fn data() -> Value {
|
||||
json!({"hello": "world"})
|
||||
}
|
||||
|
||||
pub fn data_base_64() -> Vec<u8> {
|
||||
serde_json::to_vec(&json!({"hello": "world"})).unwrap()
|
||||
}
|
||||
|
||||
pub fn subject() -> String {
|
||||
"cloudevents-sdk".to_string()
|
||||
}
|
||||
|
||||
pub fn time() -> DateTime<Utc> {
|
||||
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(datacontenttype(), dataschema(), 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": datacontenttype(),
|
||||
"dataschema": dataschema(),
|
||||
"data": data()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn full_v1_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_with_schema(datacontenttype(), dataschema(), data_base_64())
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn full_v1_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();
|
||||
|
||||
let d = base64::encode(&data_base_64());
|
||||
|
||||
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": d
|
||||
})
|
||||
}
|
||||
pub mod v03;
|
||||
pub mod v10;
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
use super::*;
|
||||
use cloudevents::{Event, EventBuilder};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub fn minimal() -> Event {
|
||||
EventBuilder::v03()
|
||||
.id(id())
|
||||
.source(source())
|
||||
.ty(ty())
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn minimal_json() -> Value {
|
||||
json!({
|
||||
"specversion": "0.3",
|
||||
"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::v03()
|
||||
.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": "0.3",
|
||||
"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::v03()
|
||||
.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": "0.3",
|
||||
"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(),
|
||||
"schemaurl": 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": "0.3",
|
||||
"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(),
|
||||
"schemaurl": dataschema(),
|
||||
"datacontentencoding": "base64",
|
||||
"data": 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::v03()
|
||||
.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::v03()
|
||||
.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": "0.3",
|
||||
"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": "0.3",
|
||||
"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(),
|
||||
"datacontentencoding": "base64",
|
||||
"data": base64::encode(Vec::from(xml_data()))
|
||||
})
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
use super::*;
|
||||
use cloudevents::{Event, EventBuilder};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
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()))
|
||||
})
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
mod test_data;
|
||||
use cloudevents::event::{EventBuilderV03, EventBuilderV10};
|
||||
use test_data::*;
|
||||
|
||||
#[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)
|
||||
}
|
Loading…
Reference in New Issue