use std::time::Duration;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use super::poll_config::PollEndpointConfig;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ExecutionResult {
pub proceed: bool,
pub outcome_value: Option<serde_json::Value>,
#[serde(default, with = "super::option_duration_millis")]
pub sleep_for: Option<Duration>,
pub persistence_data: Option<serde_json::Value>,
pub event_name: Option<String>,
pub event_key: Option<String>,
pub event_as_of: Option<DateTime<Utc>>,
pub branch_values: Option<Vec<serde_json::Value>>,
pub poll_endpoint: Option<PollEndpointConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub output_data: Option<serde_json::Value>,
}
impl ExecutionResult {
pub fn next() -> Self {
Self {
proceed: true,
..Default::default()
}
}
pub fn outcome(value: impl Into<serde_json::Value>) -> Self {
Self {
proceed: true,
outcome_value: Some(value.into()),
..Default::default()
}
}
pub fn persist(data: serde_json::Value) -> Self {
Self {
proceed: false,
persistence_data: Some(data),
..Default::default()
}
}
pub fn branch(
values: Vec<serde_json::Value>,
persistence_data: Option<serde_json::Value>,
) -> Self {
Self {
proceed: false,
branch_values: Some(values),
persistence_data,
..Default::default()
}
}
pub fn sleep(duration: Duration, persistence_data: Option<serde_json::Value>) -> Self {
Self {
proceed: false,
sleep_for: Some(duration),
persistence_data,
..Default::default()
}
}
pub fn wait_for_event(
event_name: impl Into<String>,
event_key: impl Into<String>,
as_of: DateTime<Utc>,
) -> Self {
Self {
proceed: false,
event_name: Some(event_name.into()),
event_key: Some(event_key.into()),
event_as_of: Some(as_of),
..Default::default()
}
}
pub fn poll_endpoint(config: PollEndpointConfig) -> Self {
Self {
proceed: false,
poll_endpoint: Some(config),
..Default::default()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn next_proceeds_with_no_data() {
let result = ExecutionResult::next();
assert!(result.proceed);
assert!(result.outcome_value.is_none());
assert!(result.sleep_for.is_none());
assert!(result.persistence_data.is_none());
assert!(result.event_name.is_none());
assert!(result.branch_values.is_none());
assert!(result.poll_endpoint.is_none());
}
#[test]
fn outcome_proceeds_with_value() {
let result = ExecutionResult::outcome(serde_json::json!(42));
assert!(result.proceed);
assert_eq!(result.outcome_value, Some(serde_json::json!(42)));
}
#[test]
fn persist_does_not_proceed() {
let data = serde_json::json!({"counter": 5});
let result = ExecutionResult::persist(data.clone());
assert!(!result.proceed);
assert_eq!(result.persistence_data, Some(data));
}
#[test]
fn branch_creates_child_values() {
let values = vec![
serde_json::json!(1),
serde_json::json!(2),
serde_json::json!(3),
];
let result = ExecutionResult::branch(values.clone(), None);
assert!(!result.proceed);
assert_eq!(result.branch_values, Some(values));
}
#[test]
fn sleep_sets_duration() {
let result = ExecutionResult::sleep(Duration::from_secs(30), None);
assert!(!result.proceed);
assert_eq!(result.sleep_for, Some(Duration::from_secs(30)));
}
#[test]
fn wait_for_event_sets_event_fields() {
let now = Utc::now();
let result = ExecutionResult::wait_for_event("order.completed", "order-123", now);
assert!(!result.proceed);
assert_eq!(result.event_name.as_deref(), Some("order.completed"));
assert_eq!(result.event_key.as_deref(), Some("order-123"));
assert_eq!(result.event_as_of, Some(now));
}
#[test]
fn poll_endpoint_sets_config() {
use super::super::poll_config::*;
use std::collections::HashMap;
let config = PollEndpointConfig {
url: "https://api.example.com/status".into(),
method: HttpMethod::Get,
headers: HashMap::new(),
body: None,
interval: Duration::from_secs(10),
timeout: Duration::from_secs(300),
condition: PollCondition::StatusCode(200),
};
let result = ExecutionResult::poll_endpoint(config.clone());
assert!(!result.proceed);
assert_eq!(result.poll_endpoint, Some(config));
}
#[test]
fn serde_round_trip() {
let result =
ExecutionResult::sleep(Duration::from_secs(30), Some(serde_json::json!({"x": 1})));
let json = serde_json::to_string(&result).unwrap();
let deserialized: ExecutionResult = serde_json::from_str(&json).unwrap();
assert_eq!(result.proceed, deserialized.proceed);
assert_eq!(result.sleep_for, deserialized.sleep_for);
assert_eq!(result.persistence_data, deserialized.persistence_data);
}
}