docker_wrapper/command/
compose_unpause.rs

1//! Docker Compose unpause 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 unpause command builder
8#[derive(Debug, Clone)]
9pub struct ComposeUnpauseCommand {
10    /// Base command executor
11    pub executor: CommandExecutor,
12    /// Base compose configuration
13    pub config: ComposeConfig,
14    /// Services to unpause (empty for all)
15    pub services: Vec<String>,
16}
17
18/// Result from compose unpause command
19#[derive(Debug, Clone)]
20pub struct ComposeUnpauseResult {
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 unpaused
28    pub services: Vec<String>,
29}
30
31impl ComposeUnpauseCommand {
32    /// Create a new compose unpause 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 unpause
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 unpause
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 ComposeUnpauseCommand {
62    fn default() -> Self {
63        Self::new()
64    }
65}
66
67#[async_trait]
68impl DockerCommand for ComposeUnpauseCommand {
69    type Output = ComposeUnpauseResult;
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(ComposeUnpauseResult {
89            stdout: output.stdout,
90            stderr: output.stderr,
91            success: output.success,
92            services: self.services.clone(),
93        })
94    }
95}
96
97impl ComposeCommand for ComposeUnpauseCommand {
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        "unpause"
108    }
109
110    fn build_subcommand_args(&self) -> Vec<String> {
111        // Unpause command just takes service names
112        self.services.clone()
113    }
114}
115
116impl ComposeUnpauseResult {
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 unpaused
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_unpause_basic() {
136        let cmd = ComposeUnpauseCommand::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(&"unpause".to_string()));
143    }
144
145    #[test]
146    fn test_compose_unpause_with_services() {
147        let cmd = ComposeUnpauseCommand::new()
148            .service("web")
149            .service("worker");
150        let args = cmd.build_subcommand_args();
151        assert_eq!(args, vec!["web", "worker"]);
152    }
153
154    #[test]
155    fn test_compose_unpause_single_service() {
156        let cmd = ComposeUnpauseCommand::new().service("database");
157        let args = cmd.build_subcommand_args();
158        assert_eq!(args, vec!["database"]);
159    }
160
161    #[test]
162    fn test_compose_unpause_with_services_method() {
163        let cmd = ComposeUnpauseCommand::new().services(vec!["cache", "queue"]);
164        let args = cmd.build_subcommand_args();
165        assert_eq!(args, vec!["cache", "queue"]);
166    }
167
168    #[test]
169    fn test_compose_config_integration() {
170        let cmd = ComposeUnpauseCommand::new()
171            .file("docker-compose.yml")
172            .project_name("myapp")
173            .service("web");
174
175        let args = ComposeCommand::build_command_args(&cmd);
176        assert!(args.contains(&"--file".to_string()));
177        assert!(args.contains(&"docker-compose.yml".to_string()));
178        assert!(args.contains(&"--project-name".to_string()));
179        assert!(args.contains(&"myapp".to_string()));
180        assert!(args.contains(&"web".to_string()));
181    }
182}