1use anyhow::Result;
2
3use wash_lib::cli::stop::{handle_stop_component, handle_stop_provider, stop_host, StopCommand};
4use wash_lib::cli::{CommandOutput, OutputKind};
5
6use crate::appearance::spinner::Spinner;
7
8pub async fn handle_command(
9 command: StopCommand,
10 output_kind: OutputKind,
11) -> Result<CommandOutput> {
12 let sp: Spinner = Spinner::new(&output_kind)?;
13 let out: CommandOutput = match command {
14 StopCommand::Component(cmd) => {
15 let component_id = &cmd.component_id.to_string();
16 sp.update_spinner_message(format!(" Stopping component {component_id} ... "));
17 handle_stop_component(cmd).await?
18 }
19 StopCommand::Provider(cmd) => {
20 let provider_id = &cmd.provider_id.to_string();
21 sp.update_spinner_message(format!(" Stopping provider {provider_id} ... "));
22 handle_stop_provider(cmd).await?
23 }
24 StopCommand::Host(cmd) => {
25 let host_id = &cmd.host_id.to_string();
26 sp.update_spinner_message(format!(" Stopping host {host_id} ... "));
27 stop_host(cmd).await?
28 }
29 };
30
31 Ok(out)
32}
33
34#[cfg(test)]
35mod test {
36 use crate::ctl::CtlCliCommand;
37
38 use super::*;
39 use clap::Parser;
40 use wash_lib::cli::stop::{StopComponentCommand, StopHostCommand, StopProviderCommand};
41
42 #[derive(Parser)]
43 struct Cmd {
44 #[clap(subcommand)]
45 command: CtlCliCommand,
46 }
47
48 const CTL_HOST: &str = "127.0.0.1";
49 const CTL_PORT: &str = "4222";
50 const DEFAULT_LATTICE: &str = "default";
51
52 const COMPONENT_ID: &str = "MDPDJEYIAK6MACO67PRFGOSSLODBISK4SCEYDY3HEOY4P5CVJN6UCWUK";
53 const HOST_ID: &str = "NCE7YHGI42RWEKBRDJZWXBEJJCFNE5YIWYMSTLGHQBEGFY55BKJ3EG3G";
54 const PROVIDER_ID: &str = "VBKTSBG2WKP6RJWLQ5O7RDVIIB4LMW6U5R67A7QMIDBZDGZWYTUE3TSI";
55 const CONTEXT_PATH: &str = "/tmp/fake/context";
56 const CTL_JWT: &str = "not-a-jwt";
57 const CTL_SEED: &str = "not-a-seed";
58 const CTL_CREDSFILE: &str = "/tmp/fake/credsfile";
59 const JS_DOMAIN: &str = "js";
60 const TIMEOUT_MS: u64 = 2001;
61 const HOST_TIMEOUT_MS: u64 = 3001;
62
63 #[test]
64 fn test_stop_component_cmd_comprehensive() -> Result<()> {
68 let stop_component_all: Cmd = Parser::try_parse_from([
69 "ctl",
70 "stop",
71 "component",
72 "--host-id",
73 HOST_ID,
74 COMPONENT_ID,
75 "--lattice",
76 DEFAULT_LATTICE,
77 "--ctl-host",
78 CTL_HOST,
79 "--ctl-port",
80 CTL_PORT,
81 "--ctl-jwt",
82 CTL_JWT,
83 "--ctl-seed",
84 CTL_SEED,
85 "--ctl-credsfile",
86 CTL_CREDSFILE,
87 "--timeout-ms",
88 &TIMEOUT_MS.to_string(),
89 "--context",
90 CONTEXT_PATH,
91 "--js-domain",
92 JS_DOMAIN,
93 "--skip-wait",
94 ])?;
95
96 match stop_component_all.command {
97 CtlCliCommand::Stop(StopCommand::Component(StopComponentCommand {
98 opts,
99 host_id,
100 component_id,
101 skip_wait,
102 })) => {
103 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
104 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
105 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
106 assert!(skip_wait);
107 assert_eq!(host_id.unwrap(), HOST_ID);
108 assert_eq!(component_id.to_string(), COMPONENT_ID);
109 }
110 cmd => panic!("stop component constructed incorrect command {cmd:?}"),
111 }
112
113 Ok(())
114 }
115
116 #[test]
117 fn test_stop_provider_cmd_comprehensive() -> Result<()> {
121 let stop_provider_all: Cmd = Parser::try_parse_from([
122 "ctl",
123 "stop",
124 "provider",
125 "--host-id",
126 HOST_ID,
127 PROVIDER_ID,
128 "--ctl-host",
129 CTL_HOST,
130 "--ctl-port",
131 CTL_PORT,
132 "--ctl-jwt",
133 CTL_JWT,
134 "--ctl-seed",
135 CTL_SEED,
136 "--ctl-credsfile",
137 CTL_CREDSFILE,
138 "--js-domain",
139 JS_DOMAIN,
140 "--lattice",
141 DEFAULT_LATTICE,
142 "--timeout-ms",
143 &TIMEOUT_MS.to_string(),
144 "--context",
145 CONTEXT_PATH,
146 "--skip-wait",
147 ])?;
148 match stop_provider_all.command {
149 CtlCliCommand::Stop(StopCommand::Provider(StopProviderCommand {
150 opts,
151 host_id,
152 provider_id,
153 skip_wait,
154 })) => {
155 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
156 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
157 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
158 assert_eq!(opts.timeout_ms, 2001);
159 assert_eq!(host_id.unwrap(), HOST_ID);
160 assert_eq!(provider_id.to_string(), PROVIDER_ID);
161 assert!(skip_wait);
162 }
163 cmd => panic!("stop provider constructed incorrect command {cmd:?}"),
164 }
165
166 Ok(())
167 }
168
169 #[test]
170 fn test_stop_host_cmd_comprehensive() -> Result<()> {
174 let stop_host_all: Cmd = Parser::try_parse_from([
175 "ctl",
176 "stop",
177 "host",
178 HOST_ID,
179 "--ctl-host",
180 CTL_HOST,
181 "--ctl-port",
182 CTL_PORT,
183 "--ctl-jwt",
184 CTL_JWT,
185 "--ctl-seed",
186 CTL_SEED,
187 "--ctl-credsfile",
188 CTL_CREDSFILE,
189 "--js-domain",
190 JS_DOMAIN,
191 "--lattice",
192 DEFAULT_LATTICE,
193 "--timeout-ms",
194 &TIMEOUT_MS.to_string(),
195 "--context",
196 CONTEXT_PATH,
197 "--host-timeout",
198 &HOST_TIMEOUT_MS.to_string(),
199 ])?;
200 match stop_host_all.command {
201 CtlCliCommand::Stop(StopCommand::Host(StopHostCommand {
202 opts,
203 host_id,
204 host_shutdown_timeout,
205 ..
206 })) => {
207 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
208 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
209 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
210 assert_eq!(opts.timeout_ms, TIMEOUT_MS);
211 assert_eq!(host_shutdown_timeout, HOST_TIMEOUT_MS);
212 assert_eq!(host_id.to_string(), HOST_ID);
213 assert_eq!(host_id.to_string(), HOST_ID,);
214 }
215 cmd => panic!("stop host constructed incorrect command {cmd:?}"),
216 }
217
218 Ok(())
219 }
220}