wash_cli/common/
stop_cmd.rs

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    /// Enumerates multiple options of the `stop component` subcommand to ensure API doesn't
65    /// change between versions. This test will fail if the subcommand
66    /// changes syntax, ordering of required elements, or flags.
67    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    /// Enumerates multiple options of the `stop component` subcommand to ensure API doesn't
118    /// change between versions. This test will fail if the subcommand
119    /// changes syntax, ordering of required elements, or flags.
120    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    /// Enumerates multiple options of the `stop host` subcommand to ensure API doesn't
171    /// change between versions. This test will fail if the subcommand
172    /// changes syntax, ordering of required elements, or flags.
173    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}