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