diff options
author | Albin Suresh <albin.suresh@softwareag.com> | 2022-02-09 19:16:43 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-09 19:16:43 +0530 |
commit | 7a5f5bbb4d606fffad10e622d8a7c183d546c3ba (patch) | |
tree | c16dd9600f33ec8b16a75e233ce16fc281f3ed81 /crates/core/thin_edge_json/src | |
parent | 0249b1369e5cfcd53f6e590ab9aa4c23f0278b58 (diff) |
[#809] Thin Edge JSON events support for Cumulocity mapper (#831)
* [#809] Thin Edge JSON events support for Cumulocity mapper
Diffstat (limited to 'crates/core/thin_edge_json/src')
-rw-r--r-- | crates/core/thin_edge_json/src/event.rs | 162 | ||||
-rw-r--r-- | crates/core/thin_edge_json/src/lib.rs | 1 |
2 files changed, 163 insertions, 0 deletions
diff --git a/crates/core/thin_edge_json/src/event.rs b/crates/core/thin_edge_json/src/event.rs new file mode 100644 index 00000000..fa58fdbc --- /dev/null +++ b/crates/core/thin_edge_json/src/event.rs @@ -0,0 +1,162 @@ +use serde::Deserialize; +use time::OffsetDateTime; + +use self::error::ThinEdgeJsonDeserializerError; + +/// In-memory representation of ThinEdge JSON event. +#[derive(Debug, Deserialize, PartialEq)] +pub struct ThinEdgeEvent { + pub name: String, + pub data: Option<ThinEdgeEventData>, +} + +/// In-memory representation of ThinEdge JSON event payload +#[derive(Debug, Deserialize, PartialEq)] +pub struct ThinEdgeEventData { + pub message: Option<String>, + #[serde(default)] + #[serde(deserialize_with = "clock::deserialize_iso8601_timestamp")] + pub time: Option<OffsetDateTime>, +} + +pub mod error { + #[derive(thiserror::Error, Debug)] + pub enum ThinEdgeJsonDeserializerError { + #[error("Unsupported topic: {0}")] + UnsupportedTopic(String), + + #[error("Event name can not be empty")] + EmptyEventName, + + #[error(transparent)] + SerdeJsonError(#[from] serde_json::error::Error), + } +} + +impl ThinEdgeEvent { + pub fn try_from( + mqtt_topic: &str, + mqtt_payload: &str, + ) -> Result<Self, ThinEdgeJsonDeserializerError> { + let topic_split: Vec<&str> = mqtt_topic.split('/').collect(); + if topic_split.len() == 3 { + let event_name = topic_split[2]; + if event_name.is_empty() { + return Err(ThinEdgeJsonDeserializerError::EmptyEventName); + } + + let event_data = if mqtt_payload.is_empty() { + None + } else { + Some(serde_json::from_str(mqtt_payload)?) + }; + + Ok(Self { + name: event_name.into(), + data: event_data, + }) + } else { + Err(ThinEdgeJsonDeserializerError::UnsupportedTopic( + mqtt_topic.into(), + )) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + use serde_json::{json, Value}; + use test_case::test_case; + use time::macros::datetime; + + #[test_case( + "tedge/events/click_event", + json!({ + "message": "Someone clicked", + "time": "2021-04-23T19:00:00+05:00", + }), + ThinEdgeEvent { + name: "click_event".into(), + data: Some(ThinEdgeEventData { + message: Some("Someone clicked".into()), + time: Some(datetime!(2021-04-23 19:00:00 +05:00)), + }), + }; + "event parsing" + )] + #[test_case( + "tedge/events/click_event", + json!({ + "message": "Someone clicked", + }), + ThinEdgeEvent { + name: "click_event".into(), + data: Some(ThinEdgeEventData { + message: Some("Someone clicked".into()), + time: None, + }), + }; + "event parsing without timestamp" + )] + #[test_case( + "tedge/events/click_event", + json!({ + "time": "2021-04-23T19:00:00+05:00", + }), + ThinEdgeEvent { + name: "click_event".into(), + data: Some(ThinEdgeEventData { + message: None, + time: Some(datetime!(2021-04-23 19:00:00 +05:00)), + }), + }; + "event parsing without message" + )] + #[test_case( + "tedge/events/click_event", + json!({}), + ThinEdgeEvent { + name: "click_event".into(), + data: Some(ThinEdgeEventData { + message: None, + time: None, + }), + }; + "event parsing without message or timestamp" + )] + fn parse_thin_edge_event_json( + event_topic: &str, + event_payload: Value, + expected_event: ThinEdgeEvent, + ) { + let event = + ThinEdgeEvent::try_from(event_topic, event_payload.to_string().as_str()).unwrap(); + + assert_eq!(event, expected_event); + } + + #[test] + fn event_translation_empty_event_name() { + let result = ThinEdgeEvent::try_from("tedge/events/", "{}"); + + assert_matches!(result, Err(ThinEdgeJsonDeserializerError::EmptyEventName)); + } + + #[test] + fn event_translation_more_than_three_topic_levels() { + let result = ThinEdgeEvent::try_from("tedge/events/page/click", "{}"); + + assert_matches!( + result, + Err(ThinEdgeJsonDeserializerError::UnsupportedTopic(_)) + ); + } + + #[test] + fn event_translation_empty_payload() { + let result = ThinEdgeEvent::try_from("tedge/events/click_event", ""); + assert_matches!(result.unwrap().data, None); + } +} diff --git a/crates/core/thin_edge_json/src/lib.rs b/crates/core/thin_edge_json/src/lib.rs index 441b5441..8915bf14 100644 --- a/crates/core/thin_edge_json/src/lib.rs +++ b/crates/core/thin_edge_json/src/lib.rs @@ -4,6 +4,7 @@ pub mod alarm; pub mod builder; pub mod data; +pub mod event; pub mod group; pub mod measurement; pub mod parser; |