fuchsia_driver_test/
lib.rs1use 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
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("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 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 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 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 async fn driver_test_realm_start(&self, args: fdt::RealmArgs) -> Result<()>;
264
265 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}