Skip to main content

swf_core/models/
extension.rs

1use crate::models::task::*;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5/// Represents the definition of an extension
6#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
7pub struct ExtensionDefinition {
8    /// Gets/sets the type of task to extend
9    pub extend: String,
10
11    /// Gets/sets a runtime expression, if any, used to determine whether or not the extension should apply in the specified context
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub when: Option<String>,
14
15    /// Gets/sets a name/definition list, if any, of the tasks to execute before the extended task
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub before: Option<Vec<HashMap<String, TaskDefinition>>>,
18
19    /// Gets/sets a name/definition list, if any, of the tasks to execute after the extended task
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub after: Option<Vec<HashMap<String, TaskDefinition>>>,
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn test_extension_deserialize_with_before() {
30        let json = r#"{
31            "extend": "call",
32            "when": "${ .shouldExtend }",
33            "before": [{"preTask": {"set": {"preKey": "preValue"}}}]
34        }"#;
35        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
36        assert_eq!(ext.extend, "call");
37        assert_eq!(ext.when, Some("${ .shouldExtend }".to_string()));
38        assert!(ext.before.is_some());
39        assert!(ext.after.is_none());
40    }
41
42    #[test]
43    fn test_extension_deserialize_with_after() {
44        let json = r#"{
45            "extend": "set",
46            "after": [{"postTask": {"set": {"postKey": "postValue"}}}]
47        }"#;
48        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
49        assert_eq!(ext.extend, "set");
50        assert!(ext.before.is_none());
51        assert!(ext.after.is_some());
52    }
53
54    #[test]
55    fn test_extension_deserialize_extend_all() {
56        let json = r#"{
57            "extend": "all",
58            "before": [{"log": {"set": {"logMsg": "before"}}}],
59            "after": [{"logAfter": {"set": {"logMsg": "after"}}}]
60        }"#;
61        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
62        assert_eq!(ext.extend, "all");
63        assert!(ext.before.is_some());
64        assert!(ext.after.is_some());
65    }
66
67    #[test]
68    fn test_extension_roundtrip() {
69        let json = r#"{
70            "extend": "call",
71            "when": "${ .enabled }",
72            "before": [{"preTask": {"set": {"key": "val"}}}]
73        }"#;
74        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
75        let serialized = serde_json::to_string(&ext).unwrap();
76        let deserialized: ExtensionDefinition = serde_json::from_str(&serialized).unwrap();
77        assert_eq!(ext, deserialized);
78    }
79
80    #[test]
81    fn test_extension_minimal() {
82        let json = r#"{"extend": "for"}"#;
83        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
84        assert_eq!(ext.extend, "for");
85        assert!(ext.when.is_none());
86        assert!(ext.before.is_none());
87        assert!(ext.after.is_none());
88    }
89
90    // Additional tests matching Go SDK's extension_test.go patterns
91
92    #[test]
93    fn test_extension_with_call_http_before() {
94        // Matches Go SDK's TestExtension_UnmarshalJSON - extension with HTTP call task in before
95        let json = r#"{
96            "extend": "call",
97            "when": "${condition}",
98            "before": [
99                {"task1": {"call": "http", "with": {"method": "GET", "endpoint": {"uri": "http://example.com"}}}}
100            ]
101        }"#;
102        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
103        assert_eq!(ext.extend, "call");
104        assert_eq!(ext.when, Some("${condition}".to_string()));
105        assert!(ext.before.is_some());
106        let before = ext.before.unwrap();
107        assert_eq!(before.len(), 1);
108        assert!(before[0].contains_key("task1"));
109    }
110
111    #[test]
112    fn test_extension_with_before_and_after() {
113        // Matches Go SDK's TestExtension_MarshalJSON pattern with both before and after
114        let json = r#"{
115            "extend": "call",
116            "when": "${condition}",
117            "before": [
118                {"task1": {"set": {"key1": "value1"}}}
119            ],
120            "after": [
121                {"task2": {"set": {"key2": "value2"}}}
122            ]
123        }"#;
124        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
125        assert_eq!(ext.extend, "call");
126        assert_eq!(ext.when, Some("${condition}".to_string()));
127        assert!(ext.before.is_some());
128        assert!(ext.after.is_some());
129        let before = ext.before.unwrap();
130        let after = ext.after.unwrap();
131        assert_eq!(before.len(), 1);
132        assert_eq!(after.len(), 1);
133    }
134
135    #[test]
136    fn test_extension_roundtrip_with_before_and_after() {
137        let json = r#"{
138            "extend": "call",
139            "when": "${condition}",
140            "before": [
141                {"preTask": {"set": {"preKey": "preValue"}}}
142            ],
143            "after": [
144                {"postTask": {"set": {"postKey": "postValue"}}}
145            ]
146        }"#;
147        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
148        let serialized = serde_json::to_string(&ext).unwrap();
149        let deserialized: ExtensionDefinition = serde_json::from_str(&serialized).unwrap();
150        assert_eq!(ext, deserialized);
151    }
152
153    #[test]
154    fn test_extension_extend_all() {
155        // "extend": "all" means apply to all task types
156        let json = r#"{
157            "extend": "all",
158            "before": [{"log": {"set": {"msg": "before"}}}],
159            "after": [{"logAfter": {"set": {"msg": "after"}}}]
160        }"#;
161        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
162        assert_eq!(ext.extend, "all");
163        assert!(ext.before.is_some());
164        assert!(ext.after.is_some());
165    }
166
167    #[test]
168    fn test_extension_with_multiple_before_tasks() {
169        let json = r#"{
170            "extend": "call",
171            "before": [
172                {"task1": {"set": {"k1": "v1"}}},
173                {"task2": {"set": {"k2": "v2"}}}
174            ]
175        }"#;
176        let ext: ExtensionDefinition = serde_json::from_str(json).unwrap();
177        let before = ext.before.unwrap();
178        assert_eq!(before.len(), 2);
179    }
180}