fshost_test_fixture/
mocks.rsuse anyhow::Error;
use ffeedback::FileReportResults;
use fidl::prelude::*;
use fuchsia_component_test::LocalComponentHandles;
use futures::channel::mpsc::{self};
use futures::future::BoxFuture;
use futures::{FutureExt as _, SinkExt as _, StreamExt as _};
use std::sync::Arc;
use vfs::directory::entry_container::Directory;
use vfs::execution_scope::ExecutionScope;
use vfs::path::Path;
use vfs::service;
use {fidl_fuchsia_boot as fboot, fidl_fuchsia_feedback as ffeedback, fidl_fuchsia_io as fio};
const ZBI_TYPE_STORAGE_RAMDISK: u32 = 0x4b534452;
pub async fn new_mocks(
netboot: bool,
vmo: Option<zx::Vmo>,
crash_reports_sink: mpsc::Sender<ffeedback::CrashReport>,
) -> impl Fn(LocalComponentHandles) -> BoxFuture<'static, Result<(), Error>> + Sync + Send + 'static
{
let vmo = vmo.map(Arc::new);
let mock = move |handles: LocalComponentHandles| {
let vmo_clone = vmo.clone();
run_mocks(handles, netboot, vmo_clone, crash_reports_sink.clone()).boxed()
};
mock
}
async fn run_mocks(
handles: LocalComponentHandles,
netboot: bool,
vmo: Option<Arc<zx::Vmo>>,
crash_reports_sink: mpsc::Sender<ffeedback::CrashReport>,
) -> Result<(), Error> {
let export = vfs::pseudo_directory! {
"svc" => vfs::pseudo_directory! {
fboot::ArgumentsMarker::PROTOCOL_NAME => service::host(move |stream| {
run_boot_args(stream, netboot)
}),
fboot::ItemsMarker::PROTOCOL_NAME => service::host(move |stream| {
let vmo_clone = vmo.clone();
run_boot_items(stream, vmo_clone)
}),
ffeedback::CrashReporterMarker::PROTOCOL_NAME => service::host(move |stream| {
run_crash_reporter(stream, crash_reports_sink.clone())
}),
},
};
let scope = ExecutionScope::new();
export.open(
scope.clone(),
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::DIRECTORY,
Path::dot(),
fidl::endpoints::ServerEnd::from(handles.outgoing_dir.into_channel()),
);
scope.wait().await;
Ok(())
}
async fn run_boot_items(mut stream: fboot::ItemsRequestStream, vmo: Option<Arc<zx::Vmo>>) {
while let Some(request) = stream.next().await {
match request.unwrap() {
fboot::ItemsRequest::Get { type_, extra, responder } => {
assert_eq!(type_, ZBI_TYPE_STORAGE_RAMDISK);
assert_eq!(extra, 0);
let response_vmo = vmo.as_ref().map(|vmo| {
vmo.create_child(zx::VmoChildOptions::SLICE, 0, vmo.get_size().unwrap())
.unwrap()
});
responder.send(response_vmo, 0).unwrap();
}
fboot::ItemsRequest::Get2 { type_, extra, responder } => {
assert_eq!(type_, ZBI_TYPE_STORAGE_RAMDISK);
assert_eq!((*extra.unwrap()).n, 0);
responder.send(Ok(Vec::new())).unwrap();
}
fboot::ItemsRequest::GetBootloaderFile { .. } => {
panic!(
"unexpectedly called GetBootloaderFile on {}",
fboot::ItemsMarker::PROTOCOL_NAME
);
}
}
}
}
async fn run_boot_args(mut stream: fboot::ArgumentsRequestStream, netboot: bool) {
while let Some(request) = stream.next().await {
match request.unwrap() {
fboot::ArgumentsRequest::GetString { key: _, responder } => {
responder.send(None).unwrap();
}
fboot::ArgumentsRequest::GetStrings { keys, responder } => {
responder.send(&vec![None; keys.len()]).unwrap();
}
fboot::ArgumentsRequest::GetBool { key: _, defaultval, responder } => {
responder.send(defaultval).unwrap();
}
fboot::ArgumentsRequest::GetBools { keys, responder } => {
let vec: Vec<_> = keys
.iter()
.map(|bool_pair| {
if bool_pair.key == "netsvc.netboot".to_string() && netboot {
true
} else {
bool_pair.defaultval
}
})
.collect();
responder.send(&vec).unwrap();
}
fboot::ArgumentsRequest::Collect { .. } => {
panic!("unexpectedly called Collect on {}", fboot::ArgumentsMarker::PROTOCOL_NAME);
}
}
}
}
async fn run_crash_reporter(
mut stream: ffeedback::CrashReporterRequestStream,
mut crash_reports_sink: mpsc::Sender<ffeedback::CrashReport>,
) {
while let Some(request) = stream.next().await {
match request.unwrap() {
ffeedback::CrashReporterRequest::FileReport { report, responder } => {
crash_reports_sink.send(report).await.unwrap();
responder.send(Ok(&FileReportResults::default())).unwrap();
}
}
}
}