use crate::{DetectionOpts, RunsDetection};
use fidl_fuchsia_diagnostics_test::{
DetectControllerRequest, DetectControllerRequestStream, TestCaseControllerRequest,
TestCaseControllerRequestStream,
};
use futures::lock::Mutex;
use futures::StreamExt;
use std::sync::Arc;
pub(crate) async fn run_test_service(
mut stream: DetectControllerRequestStream,
detection_runner: Arc<Mutex<impl RunsDetection>>,
) {
while let Some(Ok(request)) = stream.next().await {
match request {
DetectControllerRequest::EnterTestMode { test_controller, responder } => {
let mut detection_runner = detection_runner.lock().await;
let _: Result<_, _> = responder.send();
run_test_case_service(test_controller.into_stream(), &mut *detection_runner).await;
}
}
}
}
async fn run_test_case_service(
mut stream: TestCaseControllerRequestStream,
detection_runner: &mut impl RunsDetection,
) {
while let Some(Ok(request)) = stream.next().await {
let TestCaseControllerRequest::RunDefaultCycle { responder } = request;
detection_runner.run_detection(DetectionOpts { cpu_test: true }).await;
let _: Result<_, _> = responder.send();
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::Stats;
use fidl_fuchsia_diagnostics_test::{
DetectControllerMarker, DetectControllerProxy, TestCaseControllerMarker,
};
use fuchsia_async::{Scope, TestExecutor};
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
struct TestDetectionRunner {
run_sender: UnboundedSender<()>,
stats: Stats,
}
impl TestDetectionRunner {
fn create() -> (Arc<Mutex<Self>>, UnboundedReceiver<()>) {
let (run_sender, run_receiver) = mpsc::unbounded();
(Arc::new(Mutex::new(Self { run_sender, stats: Stats::default() })), run_receiver)
}
}
impl RunsDetection for TestDetectionRunner {
async fn run_detection(&mut self, _opts: DetectionOpts) {
self.run_sender.unbounded_send(()).unwrap();
}
fn stats(&self) -> &Stats {
&self.stats
}
}
trait CountsMessages {
async fn expect_n_messages(&mut self, n: usize);
}
impl CountsMessages for UnboundedReceiver<()> {
async fn expect_n_messages(&mut self, n: usize) {
for _ in 0..n {
assert_eq!(self.next().await, Some(()));
}
assert!(self.try_next().is_err());
}
}
fn get_controller_proxy(
scope: &Scope,
detection_runner: Arc<Mutex<impl RunsDetection + Send + 'static>>,
) -> DetectControllerProxy {
let (client_end, server_end) =
fidl::endpoints::create_endpoints::<DetectControllerMarker>();
scope.spawn(run_test_service(server_end.into_stream(), detection_runner));
client_end.into_proxy()
}
#[fuchsia::test(allow_stalls = false)]
async fn exercise_server() {
let (detection_runner, mut run_receiver) = TestDetectionRunner::create();
let scope = Scope::new();
let controller_proxy = get_controller_proxy(&scope, detection_runner);
let (test_case_proxy, first_test_case_server_end) =
fidl::endpoints::create_proxy::<TestCaseControllerMarker>();
controller_proxy.enter_test_mode(first_test_case_server_end).await.unwrap();
run_receiver.expect_n_messages(0).await;
test_case_proxy.run_default_cycle().await.unwrap();
run_receiver.expect_n_messages(1).await;
test_case_proxy.run_default_cycle().await.unwrap();
run_receiver.expect_n_messages(1).await;
std::mem::drop(test_case_proxy);
std::mem::drop(controller_proxy);
scope.await;
}
#[fuchsia::test(allow_stalls = false)]
async fn ensure_non_overlapping_sessions() {
let (detection_runner, mut run_receiver) = TestDetectionRunner::create();
let scope = Scope::new();
let controller_proxy = get_controller_proxy(&scope, detection_runner);
let (first_test_case_proxy, first_test_case_server_end) =
fidl::endpoints::create_proxy::<TestCaseControllerMarker>();
controller_proxy.enter_test_mode(first_test_case_server_end).await.unwrap();
let controller_proxy_clone = controller_proxy.clone();
scope.spawn(async move {
let (second_test_case_proxy, second_test_case_server_end) =
fidl::endpoints::create_proxy::<TestCaseControllerMarker>();
controller_proxy_clone.enter_test_mode(second_test_case_server_end).await.unwrap();
second_test_case_proxy.run_default_cycle().await.unwrap();
});
let _ = TestExecutor::poll_until_stalled(std::future::pending::<()>()).await;
run_receiver.expect_n_messages(0).await;
std::mem::drop(first_test_case_proxy);
run_receiver.expect_n_messages(1).await;
std::mem::drop(controller_proxy);
scope.await;
}
#[fuchsia::test(allow_stalls = false)]
async fn ensure_non_overlapping_connections() {
let (detection_runner, mut run_receiver) = TestDetectionRunner::create();
let scope = Scope::new();
let controller_proxy = get_controller_proxy(&scope, detection_runner.clone());
let (first_test_case_proxy, first_test_case_server_end) =
fidl::endpoints::create_proxy::<TestCaseControllerMarker>();
let second_controller_proxy = get_controller_proxy(&scope, detection_runner);
controller_proxy.enter_test_mode(first_test_case_server_end).await.unwrap();
run_receiver.expect_n_messages(0).await;
first_test_case_proxy.run_default_cycle().await.unwrap();
run_receiver.expect_n_messages(1).await;
scope.spawn(async move {
let (second_test_case_proxy, second_test_case_server_end) =
fidl::endpoints::create_proxy::<TestCaseControllerMarker>();
second_controller_proxy.enter_test_mode(second_test_case_server_end).await.unwrap();
second_test_case_proxy.run_default_cycle().await.unwrap();
});
let _ = TestExecutor::poll_until_stalled(std::future::pending::<()>()).await;
run_receiver.expect_n_messages(0).await;
std::mem::drop(first_test_case_proxy);
run_receiver.expect_n_messages(1).await;
std::mem::drop(controller_proxy);
scope.await;
}
}