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