fuchsia_driver_test/
lib.rs1use 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
21pub 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 pub fn new() -> Self {
35 Self::default()
36 }
37
38 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 async fn driver_test_realm_manifest_setup(
53 &self,
54 manifest_url: &str,
55 options: Options,
56 ) -> Result<&Self>;
57 async fn driver_test_realm_setup(&self) -> Result<&Self>;
60
61 async fn driver_test_realm_add_dtr_exposes<'a>(
68 &self,
69 dtr_exposes: &'a [ftest::Capability],
70 ) -> Result<&Self>;
71
72 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 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 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 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 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 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 async fn driver_test_realm_start(&self, args: fdt::RealmArgs) -> Result<()>;
263
264 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}