component_debug/cli/
destroy.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::cli::format::format_destroy_error;
6use crate::lifecycle::destroy_instance_in_collection;
7use crate::query::get_cml_moniker_from_query;
8use anyhow::{format_err, Result};
9use fidl_fuchsia_sys2 as fsys;
10
11pub async fn destroy_cmd<W: std::io::Write>(
12    query: String,
13    lifecycle_controller: fsys::LifecycleControllerProxy,
14    realm_query: fsys::RealmQueryProxy,
15    mut writer: W,
16) -> Result<()> {
17    let moniker = get_cml_moniker_from_query(&query, &realm_query).await?;
18
19    writeln!(writer, "Moniker: {}", moniker)?;
20    writeln!(writer, "Destroying component instance...")?;
21
22    let parent = moniker
23        .parent()
24        .ok_or_else(|| format_err!("Error: {} does not reference a dynamic instance", moniker))?;
25    let leaf = moniker
26        .leaf()
27        .ok_or_else(|| format_err!("Error: {} does not reference a dynamic instance", moniker))?;
28    let child_name = leaf.name();
29    let collection = leaf
30        .collection()
31        .ok_or_else(|| format_err!("Error: {} does not reference a dynamic instance", moniker))?;
32
33    destroy_instance_in_collection(&lifecycle_controller, &parent, collection, child_name)
34        .await
35        .map_err(|e| format_destroy_error(&moniker, e))?;
36
37    writeln!(writer, "Destroyed component instance!")?;
38    Ok(())
39}
40
41#[cfg(test)]
42mod test {
43    use super::*;
44    use crate::test_utils::serve_realm_query_instances;
45    use fidl::endpoints::create_proxy_and_stream;
46    use futures::TryStreamExt;
47    use moniker::Moniker;
48
49    fn setup_fake_lifecycle_controller(
50        expected_moniker: &'static str,
51        expected_collection: &'static str,
52        expected_name: &'static str,
53    ) -> fsys::LifecycleControllerProxy {
54        let (lifecycle_controller, mut stream) =
55            create_proxy_and_stream::<fsys::LifecycleControllerMarker>();
56        fuchsia_async::Task::local(async move {
57            let req = stream.try_next().await.unwrap().unwrap();
58            match req {
59                fsys::LifecycleControllerRequest::DestroyInstance {
60                    parent_moniker,
61                    child,
62                    responder,
63                } => {
64                    assert_eq!(
65                        Moniker::parse_str(expected_moniker),
66                        Moniker::parse_str(&parent_moniker)
67                    );
68                    assert_eq!(expected_collection, child.collection.unwrap());
69                    assert_eq!(expected_name, child.name);
70                    responder.send(Ok(())).unwrap();
71                }
72                _ => panic!("Unexpected Lifecycle Controller request"),
73            }
74        })
75        .detach();
76        lifecycle_controller
77    }
78
79    #[fuchsia_async::run_singlethreaded(test)]
80    async fn test_success() -> Result<()> {
81        let mut output = Vec::new();
82        let lifecycle_controller =
83            setup_fake_lifecycle_controller("/core", "ffx-laboratory", "test");
84        let realm_query = serve_realm_query_instances(vec![fsys::Instance {
85            moniker: Some("/core/ffx-laboratory:test".to_string()),
86            url: Some("fuchsia-pkg://fuchsia.com/test#meta/test.cml".to_string()),
87            instance_id: None,
88            resolved_info: None,
89            ..Default::default()
90        }]);
91        let response =
92            destroy_cmd("test".to_string(), lifecycle_controller, realm_query, &mut output).await;
93        response.unwrap();
94        Ok(())
95    }
96}