component_debug/cli/
create.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_create_error;
6use crate::lifecycle::create_instance_in_collection;
7use anyhow::{format_err, Result};
8use fuchsia_url::AbsoluteComponentUrl;
9use moniker::Moniker;
10use {fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_sys2 as fsys};
11
12pub async fn create_cmd<W: std::io::Write>(
13    url: AbsoluteComponentUrl,
14    moniker: Moniker,
15    config_overrides: Vec<fdecl::ConfigOverride>,
16    lifecycle_controller: fsys::LifecycleControllerProxy,
17    mut writer: W,
18) -> Result<()> {
19    let parent = moniker
20        .parent()
21        .ok_or_else(|| format_err!("Error: {} does not reference a dynamic instance", moniker))?;
22    let leaf = moniker
23        .leaf()
24        .ok_or_else(|| format_err!("Error: {} does not reference a dynamic instance", moniker))?;
25    let child_name = leaf.name();
26    let collection = leaf
27        .collection()
28        .ok_or_else(|| format_err!("Error: {} does not reference a dynamic instance", moniker))?;
29
30    writeln!(writer, "URL: {}", url)?;
31    writeln!(writer, "Moniker: {}", moniker)?;
32    writeln!(writer, "Creating component instance...")?;
33
34    create_instance_in_collection(
35        &lifecycle_controller,
36        &parent,
37        collection,
38        child_name,
39        &url,
40        config_overrides,
41        None,
42    )
43    .await
44    .map_err(|e| format_create_error(&moniker, &parent, collection, e))?;
45
46    writeln!(writer, "Created component instance!")?;
47    Ok(())
48}
49
50#[cfg(test)]
51mod test {
52    use super::*;
53    use fidl::endpoints::create_proxy_and_stream;
54    use futures::TryStreamExt;
55
56    fn setup_fake_lifecycle_controller(
57        expected_moniker: &'static str,
58        expected_collection: &'static str,
59        expected_name: &'static str,
60        expected_url: &'static str,
61    ) -> fsys::LifecycleControllerProxy {
62        let (lifecycle_controller, mut stream) =
63            create_proxy_and_stream::<fsys::LifecycleControllerMarker>();
64        fuchsia_async::Task::local(async move {
65            let req = stream.try_next().await.unwrap().unwrap();
66            match req {
67                fsys::LifecycleControllerRequest::CreateInstance {
68                    parent_moniker,
69                    collection,
70                    decl,
71                    responder,
72                    ..
73                } => {
74                    assert_eq!(
75                        Moniker::parse_str(expected_moniker),
76                        Moniker::parse_str(&parent_moniker)
77                    );
78                    assert_eq!(expected_collection, collection.name);
79                    assert_eq!(expected_name, decl.name.unwrap());
80                    assert_eq!(expected_url, decl.url.unwrap());
81                    responder.send(Ok(())).unwrap();
82                }
83                _ => panic!("Unexpected Lifecycle Controller request"),
84            }
85        })
86        .detach();
87        lifecycle_controller
88    }
89
90    #[fuchsia_async::run_singlethreaded(test)]
91    async fn test_success() -> Result<()> {
92        let mut output = Vec::new();
93        let lifecycle_controller = setup_fake_lifecycle_controller(
94            "core",
95            "ffx-laboratory",
96            "test",
97            "fuchsia-pkg://fuchsia.com/test#meta/test.cm",
98        );
99        let response = create_cmd(
100            "fuchsia-pkg://fuchsia.com/test#meta/test.cm".try_into().unwrap(),
101            "core/ffx-laboratory:test".try_into().unwrap(),
102            vec![],
103            lifecycle_controller,
104            &mut output,
105        )
106        .await;
107        response.unwrap();
108        Ok(())
109    }
110}