use fidl_fuchsia_update_verify as fidl;
use fuchsia_async::Task;
use futures::{future, FutureExt as _, StreamExt as _};
use std::sync::Arc;
pub trait Hook: Send + Sync {
fn verify(
&self,
options: fidl::VerifyOptions,
) -> future::BoxFuture<'static, fidl::VerifierVerifyResult>;
}
impl<F> Hook for F
where
F: Fn(fidl::VerifyOptions) -> fidl::VerifierVerifyResult + Send + Sync,
{
fn verify(
&self,
options: fidl::VerifyOptions,
) -> future::BoxFuture<'static, fidl::VerifierVerifyResult> {
future::ready(self(options)).boxed()
}
}
pub struct MockVerifierService {
call_hook: Box<dyn Hook>,
}
impl MockVerifierService {
pub fn new(hook: impl Hook + 'static) -> Self {
Self { call_hook: Box::new(hook) }
}
pub fn spawn_blobfs_verifier_service(self: Arc<Self>) -> (fidl::BlobfsVerifierProxy, Task<()>) {
let (proxy, stream) =
::fidl::endpoints::create_proxy_and_stream::<fidl::BlobfsVerifierMarker>();
let task = Task::spawn(self.run_blobfs_verifier_service(stream));
(proxy, task)
}
pub fn spawn_netstack_verifier_service(
self: Arc<Self>,
) -> (fidl::NetstackVerifierProxy, Task<()>) {
let (proxy, stream) =
::fidl::endpoints::create_proxy_and_stream::<fidl::NetstackVerifierMarker>();
let task = Task::spawn(self.run_netstack_verifier_service(stream));
(proxy, task)
}
pub async fn run_blobfs_verifier_service(
self: Arc<Self>,
stream: fidl::BlobfsVerifierRequestStream,
) {
let Self { call_hook } = &*self;
stream
.for_each(|request| match request.expect("received verifier request") {
fidl::BlobfsVerifierRequest::Verify { options, responder } => call_hook
.verify(options)
.map(|res| responder.send(res).expect("sent verifier response")),
})
.await
}
pub async fn run_netstack_verifier_service(
self: Arc<Self>,
stream: fidl::NetstackVerifierRequestStream,
) {
let Self { call_hook } = &*self;
stream
.for_each(|request| match request.expect("received verifier request") {
fidl::NetstackVerifierRequest::Verify { options, responder } => call_hook
.verify(options)
.map(|res| responder.send(res).expect("sent verifier response")),
})
.await
}
pub fn spawn_healthcheck_service(self: Arc<Self>) -> (fidl::VerifierProxy, Task<()>) {
let (proxy, stream) = ::fidl::endpoints::create_proxy_and_stream::<fidl::VerifierMarker>();
let task = Task::spawn(self.run_healthcheck_service(stream));
(proxy, task)
}
pub async fn run_healthcheck_service(self: Arc<Self>, stream: fidl::VerifierRequestStream) {
let Self { call_hook } = &*self;
stream
.for_each(|request| match request.expect("received verifier request") {
fidl::VerifierRequest::Verify { options, responder } => call_hook
.verify(options)
.map(|res| responder.send(res).expect("sent verifier response")),
})
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use fidl_fuchsia_update_verify::VerifyError;
use fuchsia_async as fasync;
use std::sync::atomic::{AtomicU32, Ordering};
#[fasync::run_singlethreaded(test)]
async fn test_mock_verifier() {
let mock = Arc::new(MockVerifierService::new(|_| Ok(())));
let (proxy, _server) = mock.spawn_healthcheck_service();
let verify_result = proxy.verify(&Default::default()).await.expect("made fidl call");
assert_eq!(verify_result, Ok(()));
}
#[fasync::run_singlethreaded(test)]
async fn test_mock_verifier_fails() {
let mock = Arc::new(MockVerifierService::new(|_| Err(VerifyError::Internal)));
let (proxy, _server) = mock.spawn_healthcheck_service();
let verify_result = proxy.verify(&Default::default()).await.expect("made fidl call");
assert_eq!(verify_result, Err(VerifyError::Internal));
}
#[fasync::run_singlethreaded(test)]
async fn test_mock_verifier_with_external_state() {
let called = Arc::new(AtomicU32::new(0));
let called_clone = Arc::clone(&called);
let mock = Arc::new(MockVerifierService::new(move |_| {
called_clone.fetch_add(1, Ordering::SeqCst);
Ok(())
}));
let (proxy, _server) = mock.spawn_healthcheck_service();
let verify_result = proxy.verify(&Default::default()).await.expect("made fidl call");
assert_eq!(verify_result, Ok(()));
assert_eq!(called.load(Ordering::SeqCst), 1);
}
}