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