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