docker_wrapper/compose/
stop.rs1use super::{execute_compose_command, ComposeCommand, ComposeConfig, ComposeOutput};
4use crate::error::Result;
5use async_trait::async_trait;
6use std::time::Duration;
7
8#[derive(Debug, Clone, Default)]
10pub struct ComposeStopCommand {
11 config: ComposeConfig,
12 services: Vec<String>,
13 timeout: Option<Duration>,
14}
15
16impl ComposeStopCommand {
17 #[must_use]
19 pub fn new() -> Self {
20 Self::default()
21 }
22
23 #[must_use]
25 pub fn with_config(config: ComposeConfig) -> Self {
26 Self {
27 config,
28 ..Default::default()
29 }
30 }
31
32 #[must_use]
34 pub fn service(mut self, service: impl Into<String>) -> Self {
35 self.services.push(service.into());
36 self
37 }
38
39 #[must_use]
41 pub fn timeout(mut self, timeout: Duration) -> Self {
42 self.timeout = Some(timeout);
43 self
44 }
45
46 pub async fn run(&self) -> Result<ComposeOutput> {
52 self.execute().await
53 }
54}
55
56#[async_trait]
57impl ComposeCommand for ComposeStopCommand {
58 type Output = ComposeOutput;
59
60 fn subcommand(&self) -> &'static str {
61 "stop"
62 }
63
64 fn build_args(&self) -> Vec<String> {
65 let mut args = Vec::new();
66 if let Some(timeout) = self.timeout {
67 args.push("--timeout".to_string());
68 args.push(timeout.as_secs().to_string());
69 }
70 args.extend(self.services.clone());
71 args
72 }
73
74 async fn execute(&self) -> Result<Self::Output> {
75 execute_compose_command(&self.config, self.subcommand(), self.build_args()).await
76 }
77
78 fn config(&self) -> &ComposeConfig {
79 &self.config
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_compose_stop_basic() {
89 let cmd = ComposeStopCommand::new();
90 assert_eq!(cmd.subcommand(), "stop");
91 assert_eq!(cmd.build_args(), Vec::<String>::new());
92 }
93
94 #[test]
95 fn test_compose_stop_with_services() {
96 let cmd = ComposeStopCommand::new().service("web").service("worker");
97
98 let args = cmd.build_args();
99 assert_eq!(args, vec!["web", "worker"]);
100 }
101
102 #[test]
103 fn test_compose_stop_with_timeout() {
104 let cmd = ComposeStopCommand::new()
105 .timeout(Duration::from_secs(10))
106 .service("db");
107
108 let args = cmd.build_args();
109 assert_eq!(args, vec!["--timeout", "10", "db"]);
110 }
111
112 #[test]
113 fn test_compose_stop_with_config() {
114 let config = ComposeConfig::new()
115 .file("compose.yml")
116 .project_name("webapp");
117
118 let cmd = ComposeStopCommand::with_config(config)
119 .timeout(Duration::from_secs(5))
120 .service("redis")
121 .service("postgres");
122
123 assert_eq!(cmd.config().project_name, Some("webapp".to_string()));
124 let args = cmd.build_args();
125 assert_eq!(args, vec!["--timeout", "5", "redis", "postgres"]);
126 }
127
128 #[test]
129 fn test_compose_stop_zero_timeout() {
130 let cmd = ComposeStopCommand::new()
131 .timeout(Duration::from_secs(0))
132 .service("app");
133
134 let args = cmd.build_args();
135 assert_eq!(args, vec!["--timeout", "0", "app"]);
136 }
137
138 #[test]
139 fn test_compose_stop_long_timeout() {
140 let cmd = ComposeStopCommand::new()
141 .timeout(Duration::from_secs(300))
142 .service("slow-service");
143
144 let args = cmd.build_args();
145 assert_eq!(args, vec!["--timeout", "300", "slow-service"]);
146 }
147
148 #[test]
149 fn test_compose_stop_all_services() {
150 let cmd = ComposeStopCommand::new().timeout(Duration::from_secs(30));
152
153 let args = cmd.build_args();
154 assert_eq!(args, vec!["--timeout", "30"]);
155 }
156}