wfe_core/models/
execution_result.rs1use std::time::Duration;
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use super::poll_config::PollEndpointConfig;
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9pub struct ExecutionResult {
10 pub proceed: bool,
12 pub outcome_value: Option<serde_json::Value>,
14 #[serde(default, with = "super::option_duration_millis")]
16 pub sleep_for: Option<Duration>,
17 pub persistence_data: Option<serde_json::Value>,
19 pub event_name: Option<String>,
21 pub event_key: Option<String>,
23 pub event_as_of: Option<DateTime<Utc>>,
25 pub branch_values: Option<Vec<serde_json::Value>>,
27 pub poll_endpoint: Option<PollEndpointConfig>,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub output_data: Option<serde_json::Value>,
32}
33
34impl ExecutionResult {
35 pub fn next() -> Self {
37 Self {
38 proceed: true,
39 ..Default::default()
40 }
41 }
42
43 pub fn outcome(value: impl Into<serde_json::Value>) -> Self {
45 Self {
46 proceed: true,
47 outcome_value: Some(value.into()),
48 ..Default::default()
49 }
50 }
51
52 pub fn persist(data: serde_json::Value) -> Self {
54 Self {
55 proceed: false,
56 persistence_data: Some(data),
57 ..Default::default()
58 }
59 }
60
61 pub fn branch(values: Vec<serde_json::Value>, persistence_data: Option<serde_json::Value>) -> Self {
63 Self {
64 proceed: false,
65 branch_values: Some(values),
66 persistence_data,
67 ..Default::default()
68 }
69 }
70
71 pub fn sleep(duration: Duration, persistence_data: Option<serde_json::Value>) -> Self {
73 Self {
74 proceed: false,
75 sleep_for: Some(duration),
76 persistence_data,
77 ..Default::default()
78 }
79 }
80
81 pub fn wait_for_event(
83 event_name: impl Into<String>,
84 event_key: impl Into<String>,
85 as_of: DateTime<Utc>,
86 ) -> Self {
87 Self {
88 proceed: false,
89 event_name: Some(event_name.into()),
90 event_key: Some(event_key.into()),
91 event_as_of: Some(as_of),
92 ..Default::default()
93 }
94 }
95
96 pub fn poll_endpoint(config: PollEndpointConfig) -> Self {
98 Self {
99 proceed: false,
100 poll_endpoint: Some(config),
101 ..Default::default()
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use pretty_assertions::assert_eq;
110
111 #[test]
112 fn next_proceeds_with_no_data() {
113 let result = ExecutionResult::next();
114 assert!(result.proceed);
115 assert!(result.outcome_value.is_none());
116 assert!(result.sleep_for.is_none());
117 assert!(result.persistence_data.is_none());
118 assert!(result.event_name.is_none());
119 assert!(result.branch_values.is_none());
120 assert!(result.poll_endpoint.is_none());
121 }
122
123 #[test]
124 fn outcome_proceeds_with_value() {
125 let result = ExecutionResult::outcome(serde_json::json!(42));
126 assert!(result.proceed);
127 assert_eq!(result.outcome_value, Some(serde_json::json!(42)));
128 }
129
130 #[test]
131 fn persist_does_not_proceed() {
132 let data = serde_json::json!({"counter": 5});
133 let result = ExecutionResult::persist(data.clone());
134 assert!(!result.proceed);
135 assert_eq!(result.persistence_data, Some(data));
136 }
137
138 #[test]
139 fn branch_creates_child_values() {
140 let values = vec![serde_json::json!(1), serde_json::json!(2), serde_json::json!(3)];
141 let result = ExecutionResult::branch(values.clone(), None);
142 assert!(!result.proceed);
143 assert_eq!(result.branch_values, Some(values));
144 }
145
146 #[test]
147 fn sleep_sets_duration() {
148 let result = ExecutionResult::sleep(Duration::from_secs(30), None);
149 assert!(!result.proceed);
150 assert_eq!(result.sleep_for, Some(Duration::from_secs(30)));
151 }
152
153 #[test]
154 fn wait_for_event_sets_event_fields() {
155 let now = Utc::now();
156 let result = ExecutionResult::wait_for_event("order.completed", "order-123", now);
157 assert!(!result.proceed);
158 assert_eq!(result.event_name.as_deref(), Some("order.completed"));
159 assert_eq!(result.event_key.as_deref(), Some("order-123"));
160 assert_eq!(result.event_as_of, Some(now));
161 }
162
163 #[test]
164 fn poll_endpoint_sets_config() {
165 use super::super::poll_config::*;
166 use std::collections::HashMap;
167
168 let config = PollEndpointConfig {
169 url: "https://api.example.com/status".into(),
170 method: HttpMethod::Get,
171 headers: HashMap::new(),
172 body: None,
173 interval: Duration::from_secs(10),
174 timeout: Duration::from_secs(300),
175 condition: PollCondition::StatusCode(200),
176 };
177 let result = ExecutionResult::poll_endpoint(config.clone());
178 assert!(!result.proceed);
179 assert_eq!(result.poll_endpoint, Some(config));
180 }
181
182 #[test]
183 fn serde_round_trip() {
184 let result = ExecutionResult::sleep(Duration::from_secs(30), Some(serde_json::json!({"x": 1})));
185 let json = serde_json::to_string(&result).unwrap();
186 let deserialized: ExecutionResult = serde_json::from_str(&json).unwrap();
187 assert_eq!(result.proceed, deserialized.proceed);
188 assert_eq!(result.sleep_for, deserialized.sleep_for);
189 assert_eq!(result.persistence_data, deserialized.persistence_data);
190 }
191}