fuchsia_driver_test/
lib.rs

1// Copyright 2021 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 anyhow::{Context as _, Result};
6use cm_rust::push_box;
7use fuchsia_component_test::{Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route};
8use {
9    fidl_fuchsia_component_test as ftest, fidl_fuchsia_driver_test as fdt, fidl_fuchsia_io as fio,
10};
11
12pub const COMPONENT_NAME: &str = "driver_test_realm";
13pub const DRIVER_TEST_REALM_URL: &str = "#meta/driver_test_realm.cm";
14
15#[async_trait::async_trait]
16pub trait DriverTestRealmBuilder {
17    /// Set up the DriverTestRealm component in the RealmBuilder realm.
18    /// This configures proper input/output routing of capabilities.
19    /// This takes a `manifest_url` to use, which is used by tests that need to
20    /// specify a custom driver test realm.
21    async fn driver_test_realm_manifest_setup(&self, manifest_url: &str) -> Result<&Self>;
22    /// Set up the DriverTestRealm component in the RealmBuilder realm.
23    /// This configures proper input/output routing of capabilities.
24    async fn driver_test_realm_setup(&self) -> Result<&Self>;
25
26    /// For use in conjunction with `fuchsia.driver.test.RealmArgs/dtr_exposes` defined in
27    /// `sdk/fidl/fuchsia.driver.test/realm.fidl`.
28    /// Whenever a dtr_exposes is going to be provided to the RealmArgs, the user MUST call this
29    /// function with a reference to the same dtr_exposes vector it intends to use. This will
30    /// setup the necessary expose declarations inside the driver test realm and add the necessary
31    /// realm_builder routes to support it.
32    async fn driver_test_realm_add_dtr_exposes(
33        &self,
34        dtr_exposes: &Vec<ftest::Capability>,
35    ) -> Result<&Self>;
36
37    /// For use in conjunction with `fuchsia.driver.test.RealmArgs/dtr_offers` defined in
38    /// `sdk/fidl/fuchsia.driver.test/realm.fidl`.
39    /// Whenever a dtr_offers is going to be provided to the RealmArgs, the user MUST call this
40    /// function with a reference to the same dtr_offers vector it intends to use. This will
41    /// setup the necessary offers declarations inside the driver test realm and add the necessary
42    /// realm_builder routes to support it.
43    async fn driver_test_realm_add_dtr_offers(
44        &self,
45        dtr_offers: &Vec<ftest::Capability>,
46        from: Ref,
47    ) -> Result<&Self>;
48}
49
50#[async_trait::async_trait]
51impl DriverTestRealmBuilder for RealmBuilder {
52    async fn driver_test_realm_manifest_setup(&self, manifest_url: &str) -> Result<&Self> {
53        let driver_realm =
54            self.add_child(COMPONENT_NAME, manifest_url, ChildOptions::new().eager()).await?;
55
56        // Keep the rust and c++ realm_builders in sync with the driver_test_realm manifest.
57        // LINT.IfChange
58        // Uses from the driver_test_realm manifest.
59        self.add_route(
60            Route::new()
61                .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
62                .capability(Capability::protocol_by_name("fuchsia.inspect.InspectSink"))
63                .capability(Capability::protocol_by_name("fuchsia.diagnostics.ArchiveAccessor"))
64                .capability(Capability::protocol_by_name(
65                    "fuchsia.component.resolution.Resolver-hermetic",
66                ))
67                .capability(Capability::protocol_by_name("fuchsia.pkg.PackageResolver-hermetic"))
68                .capability(Capability::dictionary("diagnostics"))
69                .from(Ref::parent())
70                .to(&driver_realm),
71        )
72        .await?;
73        // Exposes from the the driver_test_realm manifest.
74        self.add_route(
75            Route::new()
76                .capability(Capability::directory("dev-class").rights(fio::R_STAR_DIR))
77                .capability(Capability::directory("dev-topological").rights(fio::R_STAR_DIR))
78                .capability(Capability::protocol_by_name("fuchsia.system.state.Administrator"))
79                .capability(Capability::protocol_by_name("fuchsia.driver.development.Manager"))
80                .capability(Capability::protocol_by_name(
81                    "fuchsia.driver.framework.CompositeNodeManager",
82                ))
83                .capability(Capability::protocol_by_name(
84                    "fuchsia.driver.registrar.DriverRegistrar",
85                ))
86                .capability(Capability::protocol_by_name("fuchsia.driver.test.Realm"))
87                .from(&driver_realm)
88                .to(Ref::parent()),
89        )
90        .await?;
91        // LINT.ThenChange(/sdk/lib/driver_test_realm/realm_builder/cpp/lib.cc)
92        Ok(&self)
93    }
94
95    async fn driver_test_realm_setup(&self) -> Result<&Self> {
96        self.driver_test_realm_manifest_setup(DRIVER_TEST_REALM_URL).await
97    }
98
99    async fn driver_test_realm_add_dtr_exposes(
100        &self,
101        dtr_exposes: &Vec<ftest::Capability>,
102    ) -> Result<&Self> {
103        let mut decl = self.get_component_decl(COMPONENT_NAME).await?;
104        for expose in dtr_exposes {
105            let name = match expose {
106                fidl_fuchsia_component_test::Capability::Protocol(p) => p.name.as_ref(),
107                fidl_fuchsia_component_test::Capability::Directory(d) => d.name.as_ref(),
108                fidl_fuchsia_component_test::Capability::Storage(s) => s.name.as_ref(),
109                fidl_fuchsia_component_test::Capability::Service(s) => s.name.as_ref(),
110                fidl_fuchsia_component_test::Capability::EventStream(e) => e.name.as_ref(),
111                fidl_fuchsia_component_test::Capability::Config(c) => c.name.as_ref(),
112                fidl_fuchsia_component_test::Capability::Dictionary(d) => d.name.as_ref(),
113                _ => None,
114            };
115            let expose_parsed = name
116                .expect("No name found in capability.")
117                .parse::<cm_types::Name>()
118                .expect("Not a valid capability name");
119
120            push_box(
121                &mut decl.exposes,
122                cm_rust::ExposeDecl::Service(cm_rust::ExposeServiceDecl {
123                    source: cm_rust::ExposeSource::Collection(
124                        "realm_builder".parse::<cm_types::Name>().unwrap(),
125                    ),
126                    source_name: expose_parsed.clone(),
127                    source_dictionary: Default::default(),
128                    target_name: expose_parsed.clone(),
129                    target: cm_rust::ExposeTarget::Parent,
130                    availability: cm_rust::Availability::Required,
131                }),
132            );
133        }
134        self.replace_component_decl(COMPONENT_NAME, decl).await?;
135
136        for expose in dtr_exposes {
137            // Add the route through the realm builder.
138            self.add_route(
139                Route::new()
140                    .capability(expose.clone())
141                    .from(Ref::child(COMPONENT_NAME))
142                    .to(Ref::parent()),
143            )
144            .await?;
145        }
146
147        Ok(&self)
148    }
149
150    async fn driver_test_realm_add_dtr_offers(
151        &self,
152        dtr_offers: &Vec<ftest::Capability>,
153        from: Ref,
154    ) -> Result<&Self> {
155        let mut decl = self.get_component_decl(COMPONENT_NAME).await?;
156        for offer in dtr_offers {
157            let name = match offer {
158                fidl_fuchsia_component_test::Capability::Protocol(p) => p.name.as_ref(),
159                fidl_fuchsia_component_test::Capability::Directory(d) => d.name.as_ref(),
160                fidl_fuchsia_component_test::Capability::Storage(s) => s.name.as_ref(),
161                fidl_fuchsia_component_test::Capability::Service(s) => s.name.as_ref(),
162                fidl_fuchsia_component_test::Capability::EventStream(e) => e.name.as_ref(),
163                fidl_fuchsia_component_test::Capability::Config(c) => c.name.as_ref(),
164                fidl_fuchsia_component_test::Capability::Dictionary(d) => d.name.as_ref(),
165                _ => None,
166            };
167            let offer_parsed = name
168                .expect("No name found in capability.")
169                .parse::<cm_types::Name>()
170                .expect("Not a valid capability name");
171
172            push_box(
173                &mut decl.offers,
174                cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
175                    source: cm_rust::OfferSource::Parent,
176                    source_name: offer_parsed.clone(),
177                    source_dictionary: Default::default(),
178                    target_name: offer_parsed.clone(),
179                    target: cm_rust::OfferTarget::Collection(
180                        "realm_builder".parse::<cm_types::Name>().unwrap(),
181                    ),
182                    dependency_type: cm_rust::DependencyType::Strong,
183                    availability: cm_rust::Availability::Required,
184                }),
185            );
186        }
187        self.replace_component_decl(COMPONENT_NAME, decl).await?;
188
189        for offer in dtr_offers {
190            // Add the route through the realm builder.
191            self.add_route(
192                Route::new()
193                    .capability(offer.clone())
194                    .from(from.clone())
195                    .to(Ref::child(COMPONENT_NAME)),
196            )
197            .await?;
198        }
199
200        Ok(&self)
201    }
202}
203
204#[async_trait::async_trait]
205pub trait DriverTestRealmInstance {
206    /// Connect to the DriverTestRealm in this Instance and call Start with `args`.
207    async fn driver_test_realm_start(&self, args: fdt::RealmArgs) -> Result<()>;
208
209    /// Connect to the /dev/ directory hosted by  DriverTestRealm in this Instance.
210    fn driver_test_realm_connect_to_dev(&self) -> Result<fio::DirectoryProxy>;
211}
212
213#[async_trait::async_trait]
214impl DriverTestRealmInstance for RealmInstance {
215    async fn driver_test_realm_start(&self, args: fdt::RealmArgs) -> Result<()> {
216        let config: fdt::RealmProxy = self.root.connect_to_protocol_at_exposed_dir()?;
217        let () = config
218            .start(args)
219            .await
220            .context("DriverTestRealm Start failed")?
221            .map_err(zx_status::Status::from_raw)
222            .context("DriverTestRealm Start failed")?;
223        Ok(())
224    }
225
226    fn driver_test_realm_connect_to_dev(&self) -> Result<fio::DirectoryProxy> {
227        fuchsia_fs::directory::open_directory_async(
228            self.root.get_exposed_dir(),
229            "dev-topological",
230            fio::Flags::empty(),
231        )
232        .map_err(Into::into)
233    }
234}