summaryrefslogtreecommitdiffstats
path: root/crates/core/thin_edge_json/src
diff options
context:
space:
mode:
authorAlbin Suresh <albin.suresh@softwareag.com>2022-02-09 19:16:43 +0530
committerGitHub <noreply@github.com>2022-02-09 19:16:43 +0530
commit7a5f5bbb4d606fffad10e622d8a7c183d546c3ba (patch)
treec16dd9600f33ec8b16a75e233ce16fc281f3ed81 /crates/core/thin_edge_json/src
parent0249b1369e5cfcd53f6e590ab9aa4c23f0278b58 (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.rs162
-rw-r--r--crates/core/thin_edge_json/src/lib.rs1
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;