Skip to main content

torrust_tracker_deployer_lib/domain/environment/state/
destroyed.rs

1//! Destroyed State
2//!
3//! Terminal state - Environment has been destroyed
4//!
5//! All infrastructure resources have been released and the environment no longer
6//! exists. This is the final state in the lifecycle.
7//!
8//! **No Valid Transitions:** This is a terminal state.
9
10use serde::{Deserialize, Serialize};
11
12use crate::domain::environment::state::{AnyEnvironmentState, StateTypeError};
13use crate::domain::environment::Environment;
14
15/// Terminal state - Environment has been destroyed
16///
17/// All infrastructure resources have been released and the environment no longer
18/// exists. This is the final state in the lifecycle.
19///
20/// **No Valid Transitions:** This is a terminal state.
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22pub struct Destroyed;
23
24// Type Erasure: Typed → Runtime conversion (into_any)
25impl Environment<Destroyed> {
26    /// Converts typed `Environment<Destroyed>` into type-erased `AnyEnvironmentState`
27    #[must_use]
28    pub fn into_any(self) -> AnyEnvironmentState {
29        AnyEnvironmentState::Destroyed(self)
30    }
31}
32
33// Type Restoration: Runtime → Typed conversion (try_into_destroyed)
34impl AnyEnvironmentState {
35    /// Attempts to convert `AnyEnvironmentState` to `Environment<Destroyed>`
36    ///
37    /// # Errors
38    ///
39    /// Returns `StateTypeError::UnexpectedState` if the environment is not in `Destroyed` state.
40    pub fn try_into_destroyed(self) -> Result<Environment<Destroyed>, StateTypeError> {
41        match self {
42            Self::Destroyed(env) => Ok(env),
43            other => Err(StateTypeError::UnexpectedState {
44                expected: "destroyed",
45                actual: other.state_name().to_string(),
46            }),
47        }
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn it_should_create_destroyed_state() {
57        let state = Destroyed;
58        assert_eq!(state, Destroyed);
59    }
60
61    mod conversion_tests {
62        use super::*;
63        use crate::adapters::ssh::SshCredentials;
64        use crate::domain::environment::name::EnvironmentName;
65        use crate::domain::provider::{LxdConfig, ProviderConfig};
66        use crate::domain::ProfileName;
67        use crate::shared::Username;
68        use std::path::PathBuf;
69
70        fn default_lxd_provider_config(env_name: &EnvironmentName) -> ProviderConfig {
71            ProviderConfig::Lxd(LxdConfig {
72                profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
73            })
74        }
75
76        fn create_test_ssh_credentials() -> SshCredentials {
77            let username = Username::new("test-user".to_string()).unwrap();
78            SshCredentials::new(
79                PathBuf::from("/tmp/test_key"),
80                PathBuf::from("/tmp/test_key.pub"),
81                username,
82            )
83        }
84
85        fn create_test_environment_destroyed() -> Environment<Destroyed> {
86            let name = EnvironmentName::new("test-env".to_string()).unwrap();
87            let ssh_creds = create_test_ssh_credentials();
88            Environment::new(
89                name.clone(),
90                default_lxd_provider_config(&name),
91                ssh_creds,
92                22,
93                chrono::Utc::now(),
94            )
95            .destroy()
96        }
97
98        #[test]
99        fn it_should_convert_destroyed_environment_into_any() {
100            let env = create_test_environment_destroyed();
101            let any_env = env.into_any();
102            assert!(matches!(any_env, AnyEnvironmentState::Destroyed(_)));
103        }
104
105        #[test]
106        fn it_should_convert_any_to_destroyed_successfully() {
107            let env = create_test_environment_destroyed();
108            let any_env = env.into_any();
109            let result = any_env.try_into_destroyed();
110            assert!(result.is_ok());
111        }
112    }
113}