1use anyhow::{Ok, Result};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5use crate::{
6 common::{HelperSource, Source},
7 Formalize,
8};
9
10#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
11pub struct Condition {
12 #[serde(default, alias = "Name", alias = "NAME")]
13 pub name: Option<String>,
14 #[serde(default, alias = "Command", alias = "COMMAND")]
15 pub command: Option<String>,
16 #[serde(default, alias = "Interval", alias = "INTERVAL")]
17 pub interval: Option<u32>,
18 #[serde(
19 default,
20 rename = "source",
21 alias = "Source",
22 alias = "SOURCE",
23 skip_serializing
24 )]
25 source_helper: Option<HelperSource>,
26 #[serde(default, skip_deserializing)]
27 pub source: Option<Source>,
28 #[serde(alias = "Description", alias = "DESCRIPTION")]
29 pub description: Option<String>,
30 #[serde(alias = "Environment", alias = "ENVIRONMENT")]
31 pub environment: Option<Vec<String>>,
32}
33
34impl Formalize for Condition {
35 fn formalize(&mut self) -> Result<()> {
36 if let Some(source_helper) = &self.source_helper {
37 self.source = Some(source_helper.to_owned().into());
38 }
39
40 let has_command = self.command.is_some();
41 let has_interval = self.interval.is_some();
42 let has_source = self.source.is_some();
43
44 if has_source && (has_command || has_interval) {
45 return Err(anyhow::anyhow!(
46 "Condition must have Command and Interval or Source defined, not both"
47 ));
48 } else if has_command && !has_interval {
49 return Err(anyhow::anyhow!(
50 "Condition has Command defined but is missing Interval"
51 ));
52 } else if !has_command && has_interval {
53 return Err(anyhow::anyhow!(
54 "Condition has Interval defined but is missing Command"
55 ));
56 }
57 Ok(())
58 }
59}
60
61pub type Conditions = HashMap<String, Condition>;
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::parse_sdl;
67
68 #[test]
69 fn conditions_are_mapped_correctly() {
70 let sdl = r#"
71 name: test-scenario
72 description: some-description
73 conditions:
74 condition-1:
75 command: executable/path.sh
76 interval: 30
77 condition-2:
78 source: digital-library-package
79 "#;
80 let conditions = parse_sdl(sdl).unwrap().conditions;
81 insta::with_settings!({sort_maps => true}, {
82 insta::assert_yaml_snapshot!(conditions);
83 });
84 }
85
86 #[test]
87 fn handles_metrics_with_conditions_correctly() {
88 let sdl = r#"
89 name: test-scenario
90 description: some-description
91 conditions:
92 condition-1:
93 command: executable/path.sh
94 interval: 30
95 description: This is a description for condition 1
96 condition-2:
97 source: digital-library-package
98 description: This is a description for condition 2
99 metrics:
100 metric-1:
101 type: MANUAL
102 artifact: true
103 max-score: 10
104 metric-2:
105 type: CONDITIONAL
106 max-score: 10
107 condition: condition-2
108 "#;
109 let conditions = parse_sdl(sdl).unwrap().conditions;
110 insta::with_settings!({sort_maps => true}, {
111 insta::assert_yaml_snapshot!(conditions);
112 });
113 }
114
115 #[test]
116 #[should_panic(expected = "Condition \"condition-3\" not found under Scenario Conditions")]
117 fn identifies_missing_condition() {
118 let sdl = r#"
119 name: test-scenario
120 description: some-description
121 conditions:
122 condition-1:
123 command: executable/path.sh
124 interval: 30
125 description: This is a description for condition 1
126 condition-2:
127 source: digital-library-package
128 description: This is a description for condition 2
129 metrics:
130 metric-1:
131 type: MANUAL
132 artifact: true
133 max-score: 10
134 metric-2:
135 type: CONDITIONAL
136 max-score: 10
137 condition: condition-3
138 "#;
139 parse_sdl(sdl).unwrap();
140 }
141
142 #[test]
143 fn command_condition_is_parsed() {
144 let sdl = r#"
145 command: executable/path.sh
146 interval: 30
147
148 "#;
149 let condition = serde_yaml::from_str::<Condition>(sdl).unwrap();
150 insta::assert_debug_snapshot!(condition);
151 }
152
153 #[test]
154 fn library_condition_is_parsed() {
155 let sdl = r#"
156 source: digital-library-package
157
158 "#;
159 let condition = serde_yaml::from_str::<Condition>(sdl).unwrap();
160 insta::assert_debug_snapshot!(condition);
161 }
162}