Skip to main content

atlas_local/client/
get_deployment.rs

1use bollard::query_parameters::InspectContainerOptions;
2
3use crate::{
4    client::Client,
5    docker::{DockerError, DockerInspectContainer},
6    models::{Deployment, IntoDeploymentError},
7};
8
9#[derive(Debug, thiserror::Error)]
10pub enum GetDeploymentError {
11    #[error("Failed to inspect container: {0}")]
12    ContainerInspect(#[from] DockerError),
13    #[error("The container is not a local Atlas deployment: {0}")]
14    IntoDeployment(#[from] IntoDeploymentError),
15}
16
17impl<D: DockerInspectContainer> Client<D> {
18    /// Inspects a container.
19    ///
20    /// # Arguments
21    ///
22    /// * `container_id_or_name` - The ID or name of the container to inspect.
23    pub async fn get_deployment(
24        &self,
25        container_id_or_name: &str,
26    ) -> Result<Deployment, GetDeploymentError> {
27        // Inspect the container to get the deployment details
28        let container_inspect_response = self
29            .docker
30            .inspect_container(container_id_or_name, None::<InspectContainerOptions>)
31            .await?;
32
33        // Convert the container inspect response to a deployment
34        Ok(container_inspect_response.try_into()?)
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use crate::{
42        docker::DockerError,
43        models::{CreationSource, MongodbType, State},
44    };
45    use bollard::models::{
46        ContainerConfig, ContainerInspectResponse, ContainerState, ContainerStateStatusEnum,
47    };
48    use maplit::hashmap;
49    use mockall::mock;
50    use pretty_assertions::assert_eq;
51    use semver::Version;
52
53    mock! {
54        Docker {}
55
56        impl DockerInspectContainer for Docker {
57            async fn inspect_container(
58                &self,
59                container_id: &str,
60                options: Option<InspectContainerOptions>,
61            ) -> Result<ContainerInspectResponse, DockerError>;
62        }
63    }
64
65    #[tokio::test]
66    async fn test_get_deployment() {
67        // Arrange
68        let mut mock_docker = MockDocker::new();
69        let container_inspect_response = ContainerInspectResponse {
70            id: Some("test_container_id".to_string()),
71            name: Some("/test-deployment".to_string()),
72            config: Some(ContainerConfig {
73                labels: Some(hashmap! {
74                    "mongodb-atlas-local".to_string() => "container".to_string(),
75                    "version".to_string() => "8.0.0".to_string(),
76                    "mongodb-type".to_string() => "community".to_string(),
77                }),
78                env: Some(vec!["TOOL=ATLASCLI".to_string()]),
79                ..Default::default()
80            }),
81            state: Some(ContainerState {
82                status: Some(ContainerStateStatusEnum::RUNNING),
83                ..Default::default()
84            }),
85            ..Default::default()
86        };
87
88        // Set up expectations
89        mock_docker
90            .expect_inspect_container()
91            .with(
92                mockall::predicate::eq("test-deployment"),
93                mockall::predicate::eq(None::<InspectContainerOptions>),
94            )
95            .times(1)
96            .returning(move |_, _| Ok(container_inspect_response.clone()));
97
98        let client = Client::new(mock_docker);
99
100        // Act
101        let result = client.get_deployment("test-deployment").await;
102
103        // Assert
104        assert!(result.is_ok());
105
106        assert_eq!(
107            result.unwrap(),
108            Deployment {
109                container_id: "test_container_id".to_string(),
110                name: Some("test-deployment".to_string()),
111                state: State::Running,
112                mongodb_type: MongodbType::Community,
113                mongodb_version: Version::new(8, 0, 0),
114                port_bindings: None,
115                creation_source: Some(CreationSource::AtlasCLI),
116                local_seed_location: None,
117                mongodb_initdb_database: None,
118                mongodb_initdb_root_password_file: None,
119                mongodb_initdb_root_password: None,
120                mongodb_initdb_root_username_file: None,
121                mongodb_initdb_root_username: None,
122                mongodb_load_sample_data: None,
123                voyage_api_key: None,
124                mongot_log_file: None,
125                runner_log_file: None,
126                do_not_track: false,
127                telemetry_base_url: None,
128            }
129        );
130    }
131
132    #[tokio::test]
133    async fn test_get_deployment_container_inspect_error() {
134        // Arrange
135        let mut mock_docker = MockDocker::new();
136
137        // Set up expectations
138        mock_docker
139            .expect_inspect_container()
140            .with(
141                mockall::predicate::eq("nonexistent-deployment"),
142                mockall::predicate::eq(None::<InspectContainerOptions>),
143            )
144            .times(1)
145            .returning(|_, _| Err(DockerError::NotFound));
146
147        let client = Client::new(mock_docker);
148
149        // Act
150        let result = client.get_deployment("nonexistent-deployment").await;
151
152        // Assert
153        assert!(result.is_err());
154        assert!(matches!(
155            result.unwrap_err(),
156            GetDeploymentError::ContainerInspect(_)
157        ));
158    }
159
160    #[tokio::test]
161    async fn test_get_deployment_into_deployment_error() {
162        // Arrange
163        let mut mock_docker = MockDocker::new();
164        let container_inspect_response = ContainerInspectResponse {
165            id: Some("test_container_id".to_string()),
166            name: Some("/test-deployment".to_string()),
167            config: Some(ContainerConfig {
168                labels: None, // Missing labels will cause IntoDeploymentError
169                ..Default::default()
170            }),
171            ..Default::default()
172        };
173
174        // Set up expectations
175        mock_docker
176            .expect_inspect_container()
177            .with(
178                mockall::predicate::eq("invalid-deployment"),
179                mockall::predicate::eq(None::<InspectContainerOptions>),
180            )
181            .times(1)
182            .returning(move |_, _| Ok(container_inspect_response.clone()));
183
184        let client = Client::new(mock_docker);
185
186        // Act
187        let result = client.get_deployment("invalid-deployment").await;
188
189        // Assert
190        assert!(result.is_err());
191        assert!(matches!(
192            result.unwrap_err(),
193            GetDeploymentError::IntoDeployment(_)
194        ));
195    }
196}