Skip to main content

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 fidl_fuchsia_component_test as ftest;
8use fidl_fuchsia_driver_test as fdt;
9use fidl_fuchsia_io as fio;
10use fuchsia_component_test::{Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route};
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("fuchsia.driver.framework.NodeManager"))
139                .capability(Capability::protocol_by_name(
140                    "fuchsia.driver.registrar.DriverRegistrar",
141                ))
142                .capability(Capability::protocol_by_name("fuchsia.driver.test.Realm"))
143                .from(&driver_realm)
144                .to(Ref::parent()),
145        )
146        .await?;
147        // LINT.ThenChange(/sdk/lib/driver_test_realm/realm_builder/cpp/builder.cc)
148        Ok(&self)
149    }
150
151    async fn driver_test_realm_setup(&self) -> Result<&Self> {
152        self.driver_test_realm_manifest_setup(DRIVER_TEST_REALM_URL, Options::default()).await
153    }
154
155    async fn driver_test_realm_add_dtr_exposes<'a>(
156        &self,
157        dtr_exposes: &'a [ftest::Capability],
158    ) -> Result<&Self> {
159        let mut decl = self.get_component_decl(COMPONENT_NAME).await?;
160        for expose in dtr_exposes {
161            let name = match expose {
162                fidl_fuchsia_component_test::Capability::Protocol(p) => p.name.as_ref(),
163                fidl_fuchsia_component_test::Capability::Directory(d) => d.name.as_ref(),
164                fidl_fuchsia_component_test::Capability::Storage(s) => s.name.as_ref(),
165                fidl_fuchsia_component_test::Capability::Service(s) => s.name.as_ref(),
166                fidl_fuchsia_component_test::Capability::EventStream(e) => e.name.as_ref(),
167                fidl_fuchsia_component_test::Capability::Config(c) => c.name.as_ref(),
168                fidl_fuchsia_component_test::Capability::Dictionary(d) => d.name.as_ref(),
169                _ => None,
170            };
171            let expose_parsed = name
172                .expect("No name found in capability.")
173                .parse::<cm_types::Name>()
174                .expect("Not a valid capability name");
175
176            push_box(
177                &mut decl.exposes,
178                cm_rust::ExposeDecl::Service(cm_rust::ExposeServiceDecl {
179                    source: cm_rust::ExposeSource::Collection(
180                        "realm_builder".parse::<cm_types::Name>().unwrap(),
181                    ),
182                    source_name: expose_parsed.clone(),
183                    source_dictionary: Default::default(),
184                    target_name: expose_parsed.clone(),
185                    target: cm_rust::ExposeTarget::Parent,
186                    availability: cm_rust::Availability::Required,
187                }),
188            );
189        }
190        self.replace_component_decl(COMPONENT_NAME, decl).await?;
191
192        for expose in dtr_exposes {
193            // Add the route through the realm builder.
194            self.add_route(
195                Route::new()
196                    .capability(expose.clone())
197                    .from(Ref::child(COMPONENT_NAME))
198                    .to(Ref::parent()),
199            )
200            .await?;
201        }
202
203        Ok(&self)
204    }
205
206    async fn driver_test_realm_add_dtr_offers<'a>(
207        &self,
208        dtr_offers: &'a [ftest::Capability],
209        from: Ref,
210    ) -> Result<&Self> {
211        let mut decl = self.get_component_decl(COMPONENT_NAME).await?;
212        for offer in dtr_offers {
213            let name = match offer {
214                fidl_fuchsia_component_test::Capability::Protocol(p) => p.name.as_ref(),
215                fidl_fuchsia_component_test::Capability::Directory(d) => d.name.as_ref(),
216                fidl_fuchsia_component_test::Capability::Storage(s) => s.name.as_ref(),
217                fidl_fuchsia_component_test::Capability::Service(s) => s.name.as_ref(),
218                fidl_fuchsia_component_test::Capability::EventStream(e) => e.name.as_ref(),
219                fidl_fuchsia_component_test::Capability::Config(c) => c.name.as_ref(),
220                fidl_fuchsia_component_test::Capability::Dictionary(d) => d.name.as_ref(),
221                _ => None,
222            };
223            let offer_parsed = name
224                .expect("No name found in capability.")
225                .parse::<cm_types::Name>()
226                .expect("Not a valid capability name");
227
228            push_box(
229                &mut decl.offers,
230                cm_rust::offer::OfferDecl::Protocol(cm_rust::offer::OfferProtocolDecl {
231                    source: cm_rust::offer::OfferSource::Parent,
232                    source_name: offer_parsed.clone(),
233                    source_dictionary: Default::default(),
234                    target_name: offer_parsed.clone(),
235                    target: cm_rust::offer::OfferTarget::Collection(
236                        "realm_builder".parse::<cm_types::Name>().unwrap(),
237                    ),
238                    dependency_type: cm_rust::DependencyType::Strong,
239                    availability: cm_rust::Availability::Required,
240                }),
241            );
242        }
243        self.replace_component_decl(COMPONENT_NAME, decl).await?;
244
245        for offer in dtr_offers {
246            // Add the route through the realm builder.
247            self.add_route(
248                Route::new()
249                    .capability(offer.clone())
250                    .from(from.clone())
251                    .to(Ref::child(COMPONENT_NAME)),
252            )
253            .await?;
254        }
255
256        Ok(&self)
257    }
258}
259
260#[async_trait::async_trait]
261pub trait DriverTestRealmInstance {
262    /// Connect to the DriverTestRealm in this Instance and call Start with `args`.
263    async fn driver_test_realm_start(&self, args: fdt::RealmArgs) -> Result<()>;
264
265    /// Connect to the /dev/ directory hosted by  DriverTestRealm in this Instance.
266    fn driver_test_realm_connect_to_dev(&self) -> Result<fio::DirectoryProxy>;
267}
268
269#[async_trait::async_trait]
270impl DriverTestRealmInstance for RealmInstance {
271    async fn driver_test_realm_start(&self, args: fdt::RealmArgs) -> Result<()> {
272        let config: fdt::RealmProxy = self.root.connect_to_protocol_at_exposed_dir()?;
273        let () = config
274            .start(args)
275            .await
276            .context("DriverTestRealm Start failed")?
277            .map_err(zx::Status::from_raw)
278            .context("DriverTestRealm Start failed")?;
279        Ok(())
280    }
281
282    fn driver_test_realm_connect_to_dev(&self) -> Result<fio::DirectoryProxy> {
283        fuchsia_fs::directory::open_directory_async(
284            self.root.get_exposed_dir(),
285            "dev-topological",
286            fio::Flags::empty(),
287        )
288        .map_err(Into::into)
289    }
290}