docker_wrapper/command/compose/
wait.rs1use crate::command::{CommandExecutor, ComposeCommand, ComposeConfig, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
10pub struct ComposeWaitCommand {
11 pub executor: CommandExecutor,
13 pub config: ComposeConfig,
15 pub services: Vec<String>,
17 pub timeout: Option<Duration>,
19 pub wait_for_healthy: bool,
21}
22
23#[derive(Debug, Clone)]
25pub struct ComposeWaitResult {
26 pub stdout: String,
28 pub stderr: String,
30 pub success: bool,
32 pub services: Vec<String>,
34 pub all_ready: bool,
36}
37
38impl ComposeWaitCommand {
39 #[must_use]
41 pub fn new() -> Self {
42 Self {
43 executor: CommandExecutor::new(),
44 config: ComposeConfig::new(),
45 services: Vec::new(),
46 timeout: None,
47 wait_for_healthy: false,
48 }
49 }
50
51 #[must_use]
53 pub fn service(mut self, service: impl Into<String>) -> Self {
54 self.services.push(service.into());
55 self
56 }
57
58 #[must_use]
60 pub fn services<I, S>(mut self, services: I) -> Self
61 where
62 I: IntoIterator<Item = S>,
63 S: Into<String>,
64 {
65 self.services.extend(services.into_iter().map(Into::into));
66 self
67 }
68
69 #[must_use]
71 pub fn timeout(mut self, timeout: Duration) -> Self {
72 self.timeout = Some(timeout);
73 self
74 }
75
76 #[must_use]
78 pub fn wait_for_healthy(mut self) -> Self {
79 self.wait_for_healthy = true;
80 self
81 }
82}
83
84impl Default for ComposeWaitCommand {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90#[async_trait]
91impl DockerCommand for ComposeWaitCommand {
92 type Output = ComposeWaitResult;
93
94 fn get_executor(&self) -> &CommandExecutor {
95 &self.executor
96 }
97
98 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
99 &mut self.executor
100 }
101
102 fn build_command_args(&self) -> Vec<String> {
103 <Self as ComposeCommand>::build_command_args(self)
104 }
105
106 async fn execute(&self) -> Result<Self::Output> {
107 let args = <Self as ComposeCommand>::build_command_args(self);
108 let output = self.execute_command(args).await?;
109
110 Ok(ComposeWaitResult {
111 stdout: output.stdout,
112 stderr: output.stderr,
113 success: output.success,
114 services: self.services.clone(),
115 all_ready: output.success,
116 })
117 }
118}
119
120impl ComposeCommand for ComposeWaitCommand {
121 fn get_config(&self) -> &ComposeConfig {
122 &self.config
123 }
124
125 fn get_config_mut(&mut self) -> &mut ComposeConfig {
126 &mut self.config
127 }
128
129 fn subcommand(&self) -> &'static str {
130 "wait"
131 }
132
133 fn build_subcommand_args(&self) -> Vec<String> {
134 let mut args = Vec::new();
135
136 if let Some(timeout) = self.timeout {
137 args.push("--timeout".to_string());
138 args.push(timeout.as_secs().to_string());
139 }
140
141 if self.wait_for_healthy {
142 args.push("--wait-for-healthy".to_string());
143 }
144
145 args.extend(self.services.clone());
146 args
147 }
148}
149
150impl ComposeWaitResult {
151 #[must_use]
153 pub fn success(&self) -> bool {
154 self.success
155 }
156
157 #[must_use]
159 pub fn services(&self) -> &[String] {
160 &self.services
161 }
162
163 #[must_use]
165 pub fn all_ready(&self) -> bool {
166 self.all_ready
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_compose_wait_basic() {
176 let cmd = ComposeWaitCommand::new();
177 let args = cmd.build_subcommand_args();
178 assert!(args.is_empty());
179
180 let full_args = ComposeCommand::build_command_args(&cmd);
181 assert_eq!(full_args[0], "compose");
182 assert!(full_args.contains(&"wait".to_string()));
183 }
184
185 #[test]
186 fn test_compose_wait_with_options() {
187 let cmd = ComposeWaitCommand::new()
188 .timeout(Duration::from_secs(30))
189 .wait_for_healthy()
190 .services(vec!["web", "db"]);
191
192 let args = cmd.build_subcommand_args();
193 assert!(args.contains(&"--timeout".to_string()));
194 assert!(args.contains(&"30".to_string()));
195 assert!(args.contains(&"--wait-for-healthy".to_string()));
196 assert!(args.contains(&"web".to_string()));
197 assert!(args.contains(&"db".to_string()));
198 }
199}