use super::Event;
#[derive(Debug, Clone)]
pub struct FormattedMessage {
body: String,
content_type: &'static str,
}
impl FormattedMessage {
pub fn new(body: &str, content_type: &'static str) -> Self {
Self {
body: body.to_string(),
content_type,
}
}
pub fn json(body: &str) -> Self {
Self::new(body, "application/json")
}
pub fn text(body: &str) -> Self {
Self::new(body, "text/plain")
}
pub fn body(&self) -> &str {
&self.body
}
pub fn content_type(&self) -> &'static str {
self.content_type
}
}
pub trait MessageFormatter: Send + Sync {
fn name(&self) -> &str;
fn format(&self, event: &Event) -> Option<FormattedMessage>;
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
use uuid::Uuid;
#[test]
fn formatted_message_json() {
let msg = FormattedMessage::json(r#"{"text":"hello"}"#);
assert_eq!(msg.body(), r#"{"text":"hello"}"#);
assert_eq!(msg.content_type(), "application/json");
}
#[test]
fn formatted_message_text() {
let msg = FormattedMessage::text("hello world");
assert_eq!(msg.body(), "hello world");
assert_eq!(msg.content_type(), "text/plain");
}
#[test]
fn formatted_message_custom_content_type() {
let msg = FormattedMessage::new("<b>bold</b>", "text/html");
assert_eq!(msg.body(), "<b>bold</b>");
assert_eq!(msg.content_type(), "text/html");
}
struct TestFormatter;
impl MessageFormatter for TestFormatter {
fn name(&self) -> &str {
"test"
}
fn format(&self, event: &Event) -> Option<FormattedMessage> {
match event {
Event::RunCreated { workflow_name, .. } => {
let body = format!(r#"{{"text":"Run created for {}"}}"#, workflow_name);
Some(FormattedMessage::json(&body))
}
_ => None,
}
}
}
#[test]
fn formatter_formats_matching_event() {
let formatter = TestFormatter;
let event = Event::RunCreated {
run_id: Uuid::now_v7(),
workflow_name: "deploy".to_string(),
at: Utc::now(),
};
let msg = formatter.format(&event);
assert!(msg.is_some());
let msg = msg.unwrap();
assert!(msg.body().contains("deploy"));
assert_eq!(msg.content_type(), "application/json");
}
#[test]
fn formatter_skips_non_matching_event() {
let formatter = TestFormatter;
let event = Event::UserSignedIn {
user_id: Uuid::now_v7(),
username: "alice".to_string(),
at: Utc::now(),
};
assert!(formatter.format(&event).is_none());
}
#[test]
fn formatter_name() {
let formatter = TestFormatter;
assert_eq!(formatter.name(), "test");
}
}