atlas_local/client/
stop_deployment.rs1use bollard::query_parameters::StopContainerOptions;
2
3use crate::{
4 client::Client,
5 docker::{DockerInspectContainer, DockerStopContainer},
6};
7
8use super::GetDeploymentError;
9
10#[derive(Debug, thiserror::Error)]
11pub enum StopDeploymentError {
12 #[error("Failed to stop container: {0}")]
13 ContainerStop(String),
14 #[error("Failed to get deployment: {0}")]
15 GetDeployment(#[from] GetDeploymentError),
16}
17
18impl<D: DockerStopContainer + DockerInspectContainer> Client<D> {
19 pub async fn stop_deployment(&self, name: &str) -> Result<(), StopDeploymentError> {
21 let deployment = self.get_deployment(name).await?;
24 let container_id = deployment.container_id.as_str();
25
26 self.docker
28 .stop_container(container_id, None::<StopContainerOptions>)
29 .await
30 .map_err(|e| StopDeploymentError::ContainerStop(e.to_string()))?;
31
32 Ok(())
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use bollard::{
40 errors::Error as BollardError, query_parameters::InspectContainerOptions,
41 secret::ContainerInspectResponse,
42 };
43 use mockall::mock;
44
45 mock! {
46 Docker {}
47
48 impl DockerStopContainer for Docker {
49 async fn stop_container(
50 &self,
51 container_id: &str,
52 options: Option<StopContainerOptions>,
53 ) -> Result<(), BollardError>;
54 }
55
56 impl DockerInspectContainer for Docker {
57 async fn inspect_container(
58 &self,
59 container_id: &str,
60 options: Option<InspectContainerOptions>,
61 ) -> Result<ContainerInspectResponse, BollardError>;
62 }
63 }
64
65 fn create_test_container_inspect_response() -> ContainerInspectResponse {
66 use bollard::secret::{ContainerConfig, ContainerState, ContainerStateStatusEnum};
67 use std::collections::HashMap;
68
69 let mut labels = HashMap::new();
70 labels.insert("mongodb-atlas-local".to_string(), "container".to_string());
71 labels.insert("version".to_string(), "8.0.0".to_string());
72 labels.insert("mongodb-type".to_string(), "community".to_string());
73
74 let env_vars = vec!["TOOL=ATLASCLI".to_string()];
75
76 ContainerInspectResponse {
77 id: Some("test_container_id".to_string()),
78 name: Some("/test-deployment".to_string()),
79 config: Some(ContainerConfig {
80 labels: Some(labels),
81 env: Some(env_vars),
82 ..Default::default()
83 }),
84 state: Some(ContainerState {
85 status: Some(ContainerStateStatusEnum::RUNNING),
86 ..Default::default()
87 }),
88 ..Default::default()
89 }
90 }
91
92 #[tokio::test]
93 async fn test_stop_deployment() {
94 let mut mock_docker = MockDocker::new();
96
97 mock_docker
99 .expect_inspect_container()
100 .with(
101 mockall::predicate::eq("test-deployment"),
102 mockall::predicate::eq(None::<InspectContainerOptions>),
103 )
104 .times(1)
105 .returning(move |_, _| Ok(create_test_container_inspect_response()));
106
107 mock_docker
108 .expect_stop_container()
109 .with(
110 mockall::predicate::eq("test_container_id"),
111 mockall::predicate::eq(None::<StopContainerOptions>),
112 )
113 .times(1)
114 .returning(|_, _| Ok(()));
115
116 let client = Client::new(mock_docker);
117
118 let result = client.stop_deployment("test-deployment").await;
120
121 assert!(result.is_ok());
123 }
124
125 #[tokio::test]
126 async fn test_stop_deployment_get_deployment_error() {
127 let mut mock_docker = MockDocker::new();
129
130 mock_docker
132 .expect_inspect_container()
133 .times(1)
134 .returning(|_, _| {
135 Err(BollardError::DockerResponseServerError {
136 status_code: 404,
137 message: "No such container".to_string(),
138 })
139 });
140
141 let client = Client::new(mock_docker);
142
143 let result = client.stop_deployment("nonexistent-deployment").await;
145
146 assert!(result.is_err());
148 assert!(matches!(
149 result.unwrap_err(),
150 StopDeploymentError::GetDeployment(_)
151 ));
152 }
153
154 #[tokio::test]
155 async fn test_stop_deployment_stop_container_error() {
156 let mut mock_docker = MockDocker::new();
158
159 mock_docker
161 .expect_inspect_container()
162 .times(1)
163 .returning(move |_, _| Ok(create_test_container_inspect_response()));
164
165 mock_docker
166 .expect_stop_container()
167 .times(1)
168 .returning(|_, _| {
169 Err(BollardError::DockerResponseServerError {
170 status_code: 500,
171 message: "Internal Server Error".to_string(),
172 })
173 });
174
175 let client = Client::new(mock_docker);
176
177 let result = client.stop_deployment("test-deployment").await;
179
180 assert!(result.is_err());
182 assert!(matches!(
183 result.unwrap_err(),
184 StopDeploymentError::ContainerStop(_)
185 ));
186 }
187}