Skip to main content

atlas_local/client/
unpause_deployment.rs

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