docker_wrapper/command/
compose_pause.rs

1//! Docker Compose pause command implementation using unified trait pattern.
2
3use super::{CommandExecutor, ComposeCommand, ComposeConfig, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Docker Compose pause command builder
8#[derive(Debug, Clone)]
9pub struct ComposePauseCommand {
10    /// Base command executor
11    pub executor: CommandExecutor,
12    /// Base compose configuration
13    pub config: ComposeConfig,
14    /// Services to pause (empty for all)
15    pub services: Vec<String>,
16}
17
18/// Result from compose pause command
19#[derive(Debug, Clone)]
20pub struct ComposePauseResult {
21    /// Raw stdout output
22    pub stdout: String,
23    /// Raw stderr output
24    pub stderr: String,
25    /// Success status
26    pub success: bool,
27    /// Services that were paused
28    pub services: Vec<String>,
29}
30
31impl ComposePauseCommand {
32    /// Create a new compose pause command
33    #[must_use]
34    pub fn new() -> Self {
35        Self {
36            executor: CommandExecutor::new(),
37            config: ComposeConfig::new(),
38            services: Vec::new(),
39        }
40    }
41
42    /// Add a service to pause
43    #[must_use]
44    pub fn service(mut self, service: impl Into<String>) -> Self {
45        self.services.push(service.into());
46        self
47    }
48
49    /// Add multiple services to pause
50    #[must_use]
51    pub fn services<I, S>(mut self, services: I) -> Self
52    where
53        I: IntoIterator<Item = S>,
54        S: Into<String>,
55    {
56        self.services.extend(services.into_iter().map(Into::into));
57        self
58    }
59}
60
61impl Default for ComposePauseCommand {
62    fn default() -> Self {
63        Self::new()
64    }
65}
66
67#[async_trait]
68impl DockerCommand for ComposePauseCommand {
69    type Output = ComposePauseResult;
70
71    fn get_executor(&self) -> &CommandExecutor {
72        &self.executor
73    }
74
75    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
76        &mut self.executor
77    }
78
79    fn build_command_args(&self) -> Vec<String> {
80        // Use the ComposeCommand implementation explicitly
81        <Self as ComposeCommand>::build_command_args(self)
82    }
83
84    async fn execute(&self) -> Result<Self::Output> {
85        let args = <Self as ComposeCommand>::build_command_args(self);
86        let output = self.execute_command(args).await?;
87
88        Ok(ComposePauseResult {
89            stdout: output.stdout,
90            stderr: output.stderr,
91            success: output.success,
92            services: self.services.clone(),
93        })
94    }
95}
96
97impl ComposeCommand for ComposePauseCommand {
98    fn get_config(&self) -> &ComposeConfig {
99        &self.config
100    }
101
102    fn get_config_mut(&mut self) -> &mut ComposeConfig {
103        &mut self.config
104    }
105
106    fn subcommand(&self) -> &'static str {
107        "pause"
108    }
109
110    fn build_subcommand_args(&self) -> Vec<String> {
111        // Pause command just takes service names
112        self.services.clone()
113    }
114}
115
116impl ComposePauseResult {
117    /// Check if the command was successful
118    #[must_use]
119    pub fn success(&self) -> bool {
120        self.success
121    }
122
123    /// Get the services that were paused
124    #[must_use]
125    pub fn services(&self) -> &[String] {
126        &self.services
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn test_compose_pause_basic() {
136        let cmd = ComposePauseCommand::new();
137        let args = cmd.build_subcommand_args();
138        assert!(args.is_empty());
139
140        let full_args = ComposeCommand::build_command_args(&cmd);
141        assert_eq!(full_args[0], "compose");
142        assert!(full_args.contains(&"pause".to_string()));
143    }
144
145    #[test]
146    fn test_compose_pause_with_services() {
147        let cmd = ComposePauseCommand::new().service("web").service("worker");
148        let args = cmd.build_subcommand_args();
149        assert_eq!(args, vec!["web", "worker"]);
150    }
151
152    #[test]
153    fn test_compose_pause_single_service() {
154        let cmd = ComposePauseCommand::new().service("database");
155        let args = cmd.build_subcommand_args();
156        assert_eq!(args, vec!["database"]);
157    }
158
159    #[test]
160    fn test_compose_pause_with_services_method() {
161        let cmd = ComposePauseCommand::new().services(vec!["cache", "queue"]);
162        let args = cmd.build_subcommand_args();
163        assert_eq!(args, vec!["cache", "queue"]);
164    }
165
166    #[test]
167    fn test_compose_config_integration() {
168        let cmd = ComposePauseCommand::new()
169            .file("docker-compose.yml")
170            .project_name("myapp")
171            .service("web");
172
173        let args = ComposeCommand::build_command_args(&cmd);
174        assert!(args.contains(&"--file".to_string()));
175        assert!(args.contains(&"docker-compose.yml".to_string()));
176        assert!(args.contains(&"--project-name".to_string()));
177        assert!(args.contains(&"myapp".to_string()));
178        assert!(args.contains(&"web".to_string()));
179    }
180}