rustack_ses_core/
config_set.rs1use dashmap::{DashMap, mapref::entry::Entry};
7use rustack_ses_model::{
8 error::{SesError, SesErrorCode},
9 types::EventDestination,
10};
11
12#[derive(Debug, Clone)]
14pub struct ConfigSetRecord {
15 pub name: String,
17 pub event_destinations: Vec<EventDestination>,
19}
20
21#[derive(Debug)]
23pub struct ConfigurationSetStore {
24 config_sets: DashMap<String, ConfigSetRecord>,
26}
27
28impl Default for ConfigurationSetStore {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl ConfigurationSetStore {
35 #[must_use]
37 pub fn new() -> Self {
38 Self {
39 config_sets: DashMap::new(),
40 }
41 }
42
43 pub fn create(&self, name: &str) -> Result<(), SesError> {
49 match self.config_sets.entry(name.to_owned()) {
50 Entry::Occupied(_) => Err(SesError::with_message(
51 SesErrorCode::ConfigurationSetAlreadyExistsException,
52 format!("Configuration set <{name}> already exists."),
53 )),
54 Entry::Vacant(e) => {
55 e.insert(ConfigSetRecord {
56 name: name.to_owned(),
57 event_destinations: Vec::new(),
58 });
59 Ok(())
60 }
61 }
62 }
63
64 pub fn delete(&self, name: &str) -> Result<(), SesError> {
70 self.config_sets.remove(name).ok_or_else(|| {
71 SesError::with_message(
72 SesErrorCode::ConfigurationSetDoesNotExistException,
73 format!("Configuration set <{name}> does not exist."),
74 )
75 })?;
76 Ok(())
77 }
78
79 pub fn describe(&self, name: &str) -> Result<ConfigSetRecord, SesError> {
85 self.config_sets
86 .get(name)
87 .map(|entry| entry.value().clone())
88 .ok_or_else(|| {
89 SesError::with_message(
90 SesErrorCode::ConfigurationSetDoesNotExistException,
91 format!("Configuration set <{name}> does not exist."),
92 )
93 })
94 }
95
96 #[must_use]
98 pub fn list(&self) -> Vec<String> {
99 self.config_sets.iter().map(|e| e.key().clone()).collect()
100 }
101
102 #[must_use]
104 pub fn exists(&self, name: &str) -> bool {
105 self.config_sets.contains_key(name)
106 }
107
108 pub fn add_event_destination(
115 &self,
116 config_set_name: &str,
117 destination: EventDestination,
118 ) -> Result<(), SesError> {
119 let mut entry = self.config_sets.get_mut(config_set_name).ok_or_else(|| {
120 SesError::with_message(
121 SesErrorCode::ConfigurationSetDoesNotExistException,
122 format!("Configuration set <{config_set_name}> does not exist."),
123 )
124 })?;
125 if entry
126 .event_destinations
127 .iter()
128 .any(|d| d.name == destination.name)
129 {
130 return Err(SesError::with_message(
131 SesErrorCode::EventDestinationAlreadyExistsException,
132 format!(
133 "Event destination {} already exists in configuration set {config_set_name}.",
134 destination.name
135 ),
136 ));
137 }
138 entry.event_destinations.push(destination);
139 Ok(())
140 }
141
142 pub fn update_event_destination(
149 &self,
150 config_set_name: &str,
151 destination: EventDestination,
152 ) -> Result<(), SesError> {
153 let mut entry = self.config_sets.get_mut(config_set_name).ok_or_else(|| {
154 SesError::with_message(
155 SesErrorCode::ConfigurationSetDoesNotExistException,
156 format!("Configuration set <{config_set_name}> does not exist."),
157 )
158 })?;
159 let pos = entry
160 .event_destinations
161 .iter()
162 .position(|d| d.name == destination.name)
163 .ok_or_else(|| {
164 SesError::with_message(
165 SesErrorCode::EventDestinationDoesNotExistException,
166 format!("Event destination {} does not exist.", destination.name),
167 )
168 })?;
169 entry.event_destinations[pos] = destination;
170 Ok(())
171 }
172
173 pub fn delete_event_destination(
179 &self,
180 config_set_name: &str,
181 destination_name: &str,
182 ) -> Result<(), SesError> {
183 let mut entry = self.config_sets.get_mut(config_set_name).ok_or_else(|| {
184 SesError::with_message(
185 SesErrorCode::ConfigurationSetDoesNotExistException,
186 format!("Configuration set <{config_set_name}> does not exist."),
187 )
188 })?;
189 entry
190 .event_destinations
191 .retain(|d| d.name != destination_name);
192 Ok(())
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_should_create_config_set() {
202 let store = ConfigurationSetStore::new();
203 assert!(store.create("my-set").is_ok());
204 assert!(store.exists("my-set"));
205 }
206
207 #[test]
208 fn test_should_reject_duplicate_config_set() {
209 let store = ConfigurationSetStore::new();
210 store.create("dup").unwrap_or_default();
211 assert!(store.create("dup").is_err());
212 }
213
214 #[test]
215 fn test_should_delete_config_set() {
216 let store = ConfigurationSetStore::new();
217 store.create("del").unwrap_or_default();
218 assert!(store.delete("del").is_ok());
219 assert!(!store.exists("del"));
220 }
221
222 #[test]
223 fn test_should_return_error_on_delete_nonexistent() {
224 let store = ConfigurationSetStore::new();
225 assert!(store.delete("nope").is_err());
226 }
227
228 #[test]
229 fn test_should_describe_config_set() {
230 let store = ConfigurationSetStore::new();
231 store.create("desc").unwrap_or_default();
232 let record = store.describe("desc");
233 assert!(record.is_ok());
234 assert_eq!(
235 record
236 .unwrap_or_else(|_| ConfigSetRecord {
237 name: String::new(),
238 event_destinations: Vec::new(),
239 })
240 .name,
241 "desc"
242 );
243 }
244
245 #[test]
246 fn test_should_list_config_sets() {
247 let store = ConfigurationSetStore::new();
248 store.create("a").unwrap_or_default();
249 store.create("b").unwrap_or_default();
250 let list = store.list();
251 assert_eq!(list.len(), 2);
252 }
253
254 #[test]
255 fn test_should_add_event_destination() {
256 let store = ConfigurationSetStore::new();
257 store.create("set1").unwrap_or_default();
258 let dest = EventDestination {
259 name: "my-dest".to_owned(),
260 enabled: Some(true),
261 ..EventDestination::default()
262 };
263 assert!(store.add_event_destination("set1", dest).is_ok());
264 let record = store.describe("set1").unwrap_or_else(|_| ConfigSetRecord {
265 name: String::new(),
266 event_destinations: Vec::new(),
267 });
268 assert_eq!(record.event_destinations.len(), 1);
269 }
270
271 #[test]
272 fn test_should_reject_duplicate_event_destination() {
273 let store = ConfigurationSetStore::new();
274 store.create("set2").unwrap_or_default();
275 let dest = EventDestination {
276 name: "dup-dest".to_owned(),
277 ..EventDestination::default()
278 };
279 store
280 .add_event_destination("set2", dest.clone())
281 .unwrap_or_default();
282 assert!(store.add_event_destination("set2", dest).is_err());
283 }
284
285 #[test]
286 fn test_should_delete_event_destination() {
287 let store = ConfigurationSetStore::new();
288 store.create("set3").unwrap_or_default();
289 let dest = EventDestination {
290 name: "del-dest".to_owned(),
291 ..EventDestination::default()
292 };
293 store
294 .add_event_destination("set3", dest)
295 .unwrap_or_default();
296 assert!(store.delete_event_destination("set3", "del-dest").is_ok());
297 let record = store.describe("set3").unwrap_or_else(|_| ConfigSetRecord {
298 name: String::new(),
299 event_destinations: Vec::new(),
300 });
301 assert!(record.event_destinations.is_empty());
302 }
303
304 #[test]
305 fn test_should_update_event_destination() {
306 let store = ConfigurationSetStore::new();
307 store.create("set4").unwrap_or_default();
308 let dest = EventDestination {
309 name: "upd-dest".to_owned(),
310 enabled: Some(false),
311 ..EventDestination::default()
312 };
313 store
314 .add_event_destination("set4", dest)
315 .unwrap_or_default();
316 let updated = EventDestination {
317 name: "upd-dest".to_owned(),
318 enabled: Some(true),
319 ..EventDestination::default()
320 };
321 assert!(store.update_event_destination("set4", updated).is_ok());
322 }
323}