fakecloud_cloudformation/
state.rs1use chrono::{DateTime, Utc};
2use parking_lot::RwLock;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::sync::Arc;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct StackResource {
9 pub logical_id: String,
10 pub physical_id: String,
11 pub resource_type: String,
12 pub status: String,
13 pub service_token: Option<String>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Stack {
19 pub name: String,
20 pub stack_id: String,
21 pub template: String,
22 pub status: String,
23 pub resources: Vec<StackResource>,
24 pub parameters: HashMap<String, String>,
25 pub tags: HashMap<String, String>,
26 pub created_at: DateTime<Utc>,
27 pub updated_at: Option<DateTime<Utc>>,
28 pub description: Option<String>,
29 pub notification_arns: Vec<String>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct CloudFormationState {
34 pub account_id: String,
35 pub region: String,
36 #[serde(default)]
37 pub stacks: HashMap<String, Stack>,
38}
39
40impl CloudFormationState {
41 pub fn new(account_id: &str, region: &str) -> Self {
42 Self {
43 account_id: account_id.to_string(),
44 region: region.to_string(),
45 stacks: HashMap::new(),
46 }
47 }
48
49 pub fn reset(&mut self) {
50 self.stacks.clear();
51 }
52}
53
54pub type SharedCloudFormationState =
55 Arc<RwLock<fakecloud_core::multi_account::MultiAccountState<CloudFormationState>>>;
56
57impl fakecloud_core::multi_account::AccountState for CloudFormationState {
58 fn new_for_account(account_id: &str, region: &str, _endpoint: &str) -> Self {
59 Self::new(account_id, region)
60 }
61}
62
63pub const CLOUDFORMATION_SNAPSHOT_SCHEMA_VERSION: u32 = 2;
64
65#[derive(Debug, Serialize, Deserialize)]
66pub struct CloudFormationSnapshot {
67 pub schema_version: u32,
68 #[serde(default)]
69 pub accounts: Option<fakecloud_core::multi_account::MultiAccountState<CloudFormationState>>,
70 #[serde(default)]
71 pub state: Option<CloudFormationState>,
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn new_initializes_empty() {
80 let state = CloudFormationState::new("123456789012", "us-east-1");
81 assert_eq!(state.account_id, "123456789012");
82 assert_eq!(state.region, "us-east-1");
83 assert!(state.stacks.is_empty());
84 }
85
86 #[test]
87 fn reset_clears_stacks() {
88 let mut state = CloudFormationState::new("123456789012", "us-east-1");
89 state.stacks.insert(
90 "s1".to_string(),
91 Stack {
92 name: "s1".to_string(),
93 stack_id: "id".to_string(),
94 template: "{}".to_string(),
95 status: "CREATE_COMPLETE".to_string(),
96 resources: vec![],
97 parameters: HashMap::new(),
98 tags: HashMap::new(),
99 created_at: Utc::now(),
100 updated_at: None,
101 description: None,
102 notification_arns: vec![],
103 },
104 );
105 state.reset();
106 assert!(state.stacks.is_empty());
107 }
108}