fshost_test_fixture/
mocks.rs1use anyhow::Error;
6use ffeedback::FileReportResults;
7use fidl::prelude::*;
8use fuchsia_component_test::LocalComponentHandles;
9use futures::channel::mpsc::{self};
10use futures::future::BoxFuture;
11use futures::{FutureExt as _, SinkExt as _, StreamExt as _};
12use std::sync::Arc;
13use vfs::directory::entry_container::Directory;
14use vfs::execution_scope::ExecutionScope;
15use vfs::path::Path;
16use vfs::service;
17use {fidl_fuchsia_boot as fboot, fidl_fuchsia_feedback as ffeedback, fidl_fuchsia_io as fio};
18
19const ZBI_TYPE_STORAGE_RAMDISK: u32 = 0x4b534452;
21
22pub async fn new_mocks(
23 netboot: bool,
24 vmo: Option<zx::Vmo>,
25 crash_reports_sink: mpsc::Sender<ffeedback::CrashReport>,
26) -> impl Fn(LocalComponentHandles) -> BoxFuture<'static, Result<(), Error>> + Sync + Send + 'static
27{
28 let vmo = vmo.map(Arc::new);
29 let mock = move |handles: LocalComponentHandles| {
30 let vmo_clone = vmo.clone();
31 run_mocks(handles, netboot, vmo_clone, crash_reports_sink.clone()).boxed()
32 };
33
34 mock
35}
36
37async fn run_mocks(
38 handles: LocalComponentHandles,
39 netboot: bool,
40 vmo: Option<Arc<zx::Vmo>>,
41 crash_reports_sink: mpsc::Sender<ffeedback::CrashReport>,
42) -> Result<(), Error> {
43 let export = vfs::pseudo_directory! {
44 "svc" => vfs::pseudo_directory! {
45 fboot::ArgumentsMarker::PROTOCOL_NAME => service::host(move |stream| {
46 run_boot_args(stream, netboot)
47 }),
48 fboot::ItemsMarker::PROTOCOL_NAME => service::host(move |stream| {
49 let vmo_clone = vmo.clone();
50 run_boot_items(stream, vmo_clone)
51 }),
52 ffeedback::CrashReporterMarker::PROTOCOL_NAME => service::host(move |stream| {
53 run_crash_reporter(stream, crash_reports_sink.clone())
54 }),
55 },
56 };
57
58 let scope = ExecutionScope::new();
59 export.open(
60 scope.clone(),
61 fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::DIRECTORY,
62 Path::dot(),
63 fidl::endpoints::ServerEnd::from(handles.outgoing_dir.into_channel()),
64 );
65 scope.wait().await;
66
67 Ok(())
68}
69
70async fn run_boot_items(mut stream: fboot::ItemsRequestStream, vmo: Option<Arc<zx::Vmo>>) {
74 while let Some(request) = stream.next().await {
75 match request.unwrap() {
76 fboot::ItemsRequest::Get { type_, extra, responder } => {
77 assert_eq!(type_, ZBI_TYPE_STORAGE_RAMDISK);
78 assert_eq!(extra, 0);
79 let response_vmo = vmo.as_ref().map(|vmo| {
80 vmo.create_child(zx::VmoChildOptions::SLICE, 0, vmo.get_size().unwrap())
81 .unwrap()
82 });
83 responder.send(response_vmo, 0).unwrap();
84 }
85 fboot::ItemsRequest::Get2 { type_, extra, responder } => {
86 assert_eq!(type_, ZBI_TYPE_STORAGE_RAMDISK);
87 assert_eq!((*extra.unwrap()).n, 0);
88 responder.send(Ok(Vec::new())).unwrap();
89 }
90 fboot::ItemsRequest::GetBootloaderFile { .. } => {
91 panic!(
92 "unexpectedly called GetBootloaderFile on {}",
93 fboot::ItemsMarker::PROTOCOL_NAME
94 );
95 }
96 }
97 }
98}
99
100async fn run_boot_args(mut stream: fboot::ArgumentsRequestStream, netboot: bool) {
109 while let Some(request) = stream.next().await {
110 match request.unwrap() {
111 fboot::ArgumentsRequest::GetString { key: _, responder } => {
112 responder.send(None).unwrap();
113 }
114 fboot::ArgumentsRequest::GetStrings { keys, responder } => {
115 responder.send(&vec![None; keys.len()]).unwrap();
116 }
117 fboot::ArgumentsRequest::GetBool { key: _, defaultval, responder } => {
118 responder.send(defaultval).unwrap();
119 }
120 fboot::ArgumentsRequest::GetBools { keys, responder } => {
121 let vec: Vec<_> = keys
122 .iter()
123 .map(|bool_pair| {
124 if bool_pair.key == "netsvc.netboot".to_string() && netboot {
125 true
126 } else {
127 bool_pair.defaultval
128 }
129 })
130 .collect();
131 responder.send(&vec).unwrap();
132 }
133 fboot::ArgumentsRequest::Collect { .. } => {
134 panic!("unexpectedly called Collect on {}", fboot::ArgumentsMarker::PROTOCOL_NAME);
136 }
137 }
138 }
139}
140
141async fn run_crash_reporter(
142 mut stream: ffeedback::CrashReporterRequestStream,
143 mut crash_reports_sink: mpsc::Sender<ffeedback::CrashReport>,
144) {
145 while let Some(request) = stream.next().await {
146 match request.unwrap() {
147 ffeedback::CrashReporterRequest::FileReport { report, responder } => {
148 crash_reports_sink.send(report).await.unwrap();
149 responder.send(Ok(&FileReportResults::default())).unwrap();
150 }
151 }
152 }
153}