torrust_tracker_deployer_lib/domain/environment/state/
running.rs1use serde::{Deserialize, Serialize};
13
14use crate::domain::environment::state::{
15 AnyEnvironmentState, RunFailed, RunFailureContext, StateTypeError,
16};
17use crate::domain::environment::Environment;
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct Running;
29
30impl Environment<Running> {
32 #[must_use]
40 pub fn run_failed(self, context: RunFailureContext) -> Environment<RunFailed> {
41 self.with_state(RunFailed { context })
42 }
43}
44
45impl Environment<Running> {
47 #[must_use]
49 pub fn into_any(self) -> AnyEnvironmentState {
50 AnyEnvironmentState::Running(self)
51 }
52}
53
54impl AnyEnvironmentState {
56 pub fn try_into_running(self) -> Result<Environment<Running>, StateTypeError> {
62 match self {
63 Self::Running(env) => Ok(env),
64 other => Err(StateTypeError::UnexpectedState {
65 expected: "running",
66 actual: other.state_name().to_string(),
67 }),
68 }
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn it_should_create_running_state() {
78 let state = Running;
79 assert_eq!(state, Running);
80 }
81
82 mod conversion_tests {
83 use super::*;
84 use crate::adapters::ssh::SshCredentials;
85 use crate::domain::environment::name::EnvironmentName;
86 use crate::domain::environment::runtime_outputs::ProvisionMethod;
87 use crate::domain::provider::{LxdConfig, ProviderConfig};
88 use crate::domain::ProfileName;
89 use crate::shared::Username;
90 use std::net::{IpAddr, Ipv4Addr};
91 use std::path::PathBuf;
92
93 fn default_lxd_provider_config(env_name: &EnvironmentName) -> ProviderConfig {
94 ProviderConfig::Lxd(LxdConfig {
95 profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
96 })
97 }
98
99 fn create_test_ssh_credentials() -> SshCredentials {
100 let username = Username::new("test-user".to_string()).unwrap();
101 SshCredentials::new(
102 PathBuf::from("/tmp/test_key"),
103 PathBuf::from("/tmp/test_key.pub"),
104 username,
105 )
106 }
107
108 fn create_test_environment_running() -> Environment<Running> {
109 let name = EnvironmentName::new("test-env".to_string()).unwrap();
110 let ssh_creds = create_test_ssh_credentials();
111 Environment::new(
112 name.clone(),
113 default_lxd_provider_config(&name),
114 ssh_creds,
115 22,
116 chrono::Utc::now(),
117 )
118 .start_provisioning()
119 .provisioned(
120 IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)),
121 ProvisionMethod::Provisioned,
122 )
123 .start_configuring()
124 .configured()
125 .start_releasing()
126 .released()
127 .start_running()
128 }
129
130 #[test]
131 fn it_should_convert_running_environment_into_any() {
132 let env = create_test_environment_running();
133 let any_env = env.into_any();
134 assert!(matches!(any_env, AnyEnvironmentState::Running(_)));
135 }
136
137 #[test]
138 fn it_should_convert_any_to_running_successfully() {
139 let env = create_test_environment_running();
140 let any_env = env.into_any();
141 let result = any_env.try_into_running();
142 assert!(result.is_ok());
143 }
144
145 #[test]
146 fn it_should_fail_converting_destroyed_to_running() {
147 let name = EnvironmentName::new("test-env".to_string()).unwrap();
148 let ssh_creds = create_test_ssh_credentials();
149 let env = Environment::new(
150 name.clone(),
151 default_lxd_provider_config(&name),
152 ssh_creds,
153 22,
154 chrono::Utc::now(),
155 )
156 .destroy();
157 let any_env = env.into_any();
158 let result = any_env.try_into_running();
159 assert!(result.is_err());
160 let err = result.unwrap_err();
161 assert!(err.to_string().contains("running"));
162 assert!(err.to_string().contains("destroyed"));
163 }
164 }
165
166 mod transition_tests {
167 use std::time::Duration;
168
169 use chrono::Utc;
170
171 use super::*;
172 use crate::adapters::ssh::SshCredentials;
173 use crate::domain::environment::name::EnvironmentName;
174 use crate::domain::environment::runtime_outputs::ProvisionMethod;
175 use crate::domain::environment::state::{BaseFailureContext, Destroyed, RunStep};
176 use crate::domain::environment::TraceId;
177 use crate::domain::provider::{LxdConfig, ProviderConfig};
178 use crate::domain::ProfileName;
179 use crate::shared::error::ErrorKind;
180 use crate::shared::Username;
181 use std::net::{IpAddr, Ipv4Addr};
182 use std::path::PathBuf;
183
184 fn default_lxd_provider_config(env_name: &EnvironmentName) -> ProviderConfig {
185 ProviderConfig::Lxd(LxdConfig {
186 profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
187 })
188 }
189
190 fn create_test_environment() -> Environment<Running> {
191 let env_name = EnvironmentName::new("test-state".to_string()).unwrap();
192 let ssh_username = Username::new("torrust".to_string()).unwrap();
193 let ssh_credentials = SshCredentials::new(
194 PathBuf::from("test_key"),
195 PathBuf::from("test_key.pub"),
196 ssh_username,
197 );
198 Environment::new(
199 env_name.clone(),
200 default_lxd_provider_config(&env_name),
201 ssh_credentials,
202 22,
203 chrono::Utc::now(),
204 )
205 .start_provisioning()
206 .provisioned(
207 IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)),
208 ProvisionMethod::Provisioned,
209 )
210 .start_configuring()
211 .configured()
212 .start_releasing()
213 .released()
214 .start_running()
215 }
216
217 fn create_test_failure_context() -> RunFailureContext {
218 let now = Utc::now();
219 RunFailureContext {
220 failed_step: RunStep::StartServices,
221 error_kind: ErrorKind::InfrastructureOperation,
222 base: BaseFailureContext {
223 error_summary: "application_crash".to_string(),
224 failed_at: now,
225 execution_started_at: now,
226 execution_duration: Duration::from_secs(5),
227 trace_id: TraceId::new(),
228 trace_file_path: None,
229 },
230 }
231 }
232
233 #[test]
234 fn it_should_transition_from_running_to_run_failed() {
235 let env = create_test_environment();
236 let context = create_test_failure_context();
237 let env = env.run_failed(context);
238
239 assert_eq!(env.state().context.failed_step, RunStep::StartServices);
240 assert_eq!(env.name().as_str(), "test-state");
241 }
242
243 #[test]
244 fn it_should_transition_to_destroyed_from_running() {
245 let env = create_test_environment();
246 let env = env.destroy();
247
248 assert_eq!(*env.state(), Destroyed);
249 assert_eq!(env.name().as_str(), "test-state");
250 }
251 }
252}