blob: 1591383bfe11f55d043e610e68ab408f70edfc76 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use async::{self, TimeoutExt};
use fidl_wlantap;
use futures::prelude::*;
use futures::channel::mpsc;
use std::sync::Arc;
use wlantap_client::Wlantap;
use zx::{self, prelude::*};
use futures::task::Context;
type EventStream = fidl_wlantap::WlantapPhyEventStream;
pub struct TestHelper {
_wlantap: Wlantap,
proxy: Arc<fidl_wlantap::WlantapPhyProxy>,
event_stream: Option<EventStream>,
}
struct TestHelperFuture<F: Future, H>
where H: FnMut(fidl_wlantap::WlantapPhyEvent) -> ()
{
event_stream: Option<EventStream>,
event_handler: H,
main_future: F,
}
impl<F: Future, H> Future for TestHelperFuture<F, H>
where H: FnMut(fidl_wlantap::WlantapPhyEvent) -> ()
{
type Item = (F::Item, EventStream);
type Error = (F::Error, EventStream);
fn poll(&mut self, cx: &mut Context) -> Poll<(F::Item, EventStream), (F::Error, EventStream)> {
match self.main_future.poll(cx) {
Err(e) => Err((e, self.event_stream.take().unwrap())),
Ok(Async::Ready(item)) => Ok(Async::Ready((item, self.event_stream.take().unwrap()))),
Ok(Async::Pending) => {
let stream = self.event_stream.as_mut().unwrap();
loop {
match stream.poll_next(cx) {
Err(e) => panic!("WlantapPhy event stream returned an error: {:?}", e),
Ok(Async::Ready(None)) => panic!("Unexpected end of the WlantapPhy event stream"),
Ok(Async::Ready(Some(event))) => (self.event_handler)(event),
Ok(Async::Pending) => return Ok(Async::Pending),
}
}
}
}
}
}
impl TestHelper {
pub fn begin_test(exec: &mut async::Executor,
config: fidl_wlantap::WlantapPhyConfig) -> Self {
let wlantap = Wlantap::open().expect("Failed to open wlantapctl");
let proxy = wlantap.create_phy(config).expect("Failed to create wlantap PHY");
let event_stream = Some(proxy.take_event_stream());
let mut helper = TestHelper {
_wlantap: wlantap,
proxy: Arc::new(proxy),
event_stream
};
helper.wait_for_wlanmac_start(exec);
helper
}
fn wait_for_wlanmac_start(&mut self, exec: &mut async::Executor) {
let (mut sender, receiver) = mpsc::channel::<()>(1);
self.run(exec, 2.seconds(), "receive a WlanmacStart event",
move |event| {
match event {
fidl_wlantap::WlantapPhyEvent::WlanmacStart{ .. } => {
sender.try_send(()).unwrap();
},
_ => {}
}
},
receiver.next()
).unwrap();
}
pub fn proxy(&self) -> Arc<fidl_wlantap::WlantapPhyProxy> {
self.proxy.clone()
}
pub fn run<F: Future, H>(&mut self, exec: &mut async::Executor, timeout: zx::Duration,
context: &str, event_handler: H, future: F)
-> Result<F::Item, F::Error>
where H: FnMut(fidl_wlantap::WlantapPhyEvent) -> ()
{
let res = exec.run_singlethreaded(
TestHelperFuture{
event_stream: Some(self.event_stream.take().unwrap()),
event_handler,
main_future: future
}
.on_timeout(timeout.after_now(),
|| panic!("Did not complete in time: {}", context)).unwrap());
match res {
Ok((item, stream)) => {
self.event_stream = Some(stream);
Ok(item)
},
Err((err, stream)) => {
self.event_stream = Some(stream);
Err(err)
}
}
}
}
pub struct RetryWithBackoff {
deadline: zx::Time,
prev_delay: zx::Duration,
delay: zx::Duration,
}
impl RetryWithBackoff {
pub fn new(timeout: zx::Duration) -> Self {
RetryWithBackoff {
deadline: timeout.after_now(),
prev_delay: 0.millis(),
delay: 1.millis(),
}
}
pub fn sleep_unless_timed_out(&mut self) -> bool {
if 0.millis().after_now() > self.deadline {
false
} else {
::std::cmp::min(self.delay.after_now(), self.deadline).sleep();
let new_delay = self.prev_delay + self.delay;
self.prev_delay = self.delay;
self.delay = new_delay;
true
}
}
}