1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45//! This module defines a framework for using the crate::expectations module in
6//! asynchronous situations, where you wish you detect the satisfiability of the
7//! expectations at some undetermined point in the future.
8//!
9//! An `ExpectationFuture` implements `Future` and will complete when the
10//! underlying state satisfies the predicate. Failure can be detected by wrapping
11//! the future in a timeout, as is implemented by the method `when_satisfied`.
12//!
13//! To use `ExpectationFuture`s, you must implement `ExpectableState` for the
14//! type of state you wish to track, which defines how the state will update and
15//! notify tasks that are waiting on state changes.
16//!
17//! A common pattern is to await the expectation of a given state, and then
18//! check further predicate expectations to determine success or failure at that
19//! point in time.
20//!
21//! e.g.
22//!
23//! ```ignore
24//! // Wait for the action to have completed one way or the other
25//! let state = state.when_satisfied(action_complete, timeout).await?;
26//! // Then check that the action completed successfully
27//! action_success.satisfied(state)
28//! ```
29#![cfg(target_os = "fuchsia")]
30use anyhow::{format_err, Error};
31use fuchsia_async::{DurationExt, TimeoutExt};
32use fuchsia_sync::{MappedRwLockWriteGuard, RwLock, RwLockWriteGuard};
33use futures::future::BoxFuture;
34use futures::FutureExt;
35use slab::Slab;
36use std::future::Future;
37use std::pin::Pin;
38use std::sync::Arc;
39use std::task;
40use std::task::Poll;
4142use crate::expectation::Predicate;
4344/// Future that completes once a Predicate is satisfied for the `T::State` type
45/// where `T` is some type that allows monitoring of State updates
46#[must_use = "futures do nothing unless polled"]
47pub struct ExpectationFuture<T: ExpectableState> {
48 state: T,
49 expectation: Predicate<T::State>,
50 waker_key: Option<usize>,
51}
5253impl<T: ExpectableState> ExpectationFuture<T> {
54fn new(state: T, expectation: Predicate<T::State>) -> ExpectationFuture<T> {
55 ExpectationFuture { state, expectation, waker_key: None }
56 }
5758fn clear_waker(&mut self) {
59if let Some(key) = self.waker_key {
60self.state.remove_task(key);
61self.waker_key = None;
62 }
63 }
6465fn store_task(&mut self, cx: &mut task::Context<'_>) {
66let key = self.state.store_task(cx);
67self.waker_key = Some(key);
68 }
69}
7071impl<T: ExpectableState> std::marker::Unpin for ExpectationFuture<T> {}
7273impl<T: ExpectableState> Future for ExpectationFuture<T> {
74type Output = T::State;
7576fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
77self.clear_waker();
78let state = self.state.read();
79if self.expectation.satisfied(&state) {
80 Poll::Ready(state)
81 } else {
82self.store_task(cx);
83 Poll::Pending
84 }
85 }
86}
8788/// Trait for objects that allow futures to trigger based on state changes
89///
90/// This trait will commonly be used via the `ExpectableStateExt` extension
91/// trait which provides the convenient `when_satisfied` function.
92///
93/// You can implement this trait for your own types which implement their own
94/// state tracking and notification of futures, or you can use the
95/// `ExpectationHarness` struct in this module which provides a ready to use
96/// implementation.
97pub trait ExpectableState: Clone {
98/// Type of current state we are tracking
99type State: 'static;
100101/// Register a task as needing waking when state changes
102fn store_task(&mut self, cx: &mut task::Context<'_>) -> usize;
103104/// Remove a task from being tracked. Called by `ExpectationFuture` when
105 /// polled.
106fn remove_task(&mut self, key: usize);
107108/// Notify all pending tasks that state has changed
109fn notify_state_changed(&self);
110111/// Read a snapshot of the current State
112fn read(&self) -> Self::State;
113}
114115pub trait ExpectableStateExt: ExpectableState + Sized {
116/// Convenience method for awaiting expectations on the underlying state
117 /// Provides a simple syntax for asynchronously awaiting expectations:
118 ///
119 /// ```ignore
120 /// // Wait for the action to have completed one way or the other
121 /// let state = state.when_satisfied(action_complete, timeout).await?;
122 /// ```
123fn when_satisfied(
124&self,
125 expectation: Predicate<Self::State>,
126 timeout: zx::MonotonicDuration,
127 ) -> BoxFuture<'_, Result<Self::State, Error>>;
128}
129130impl<T: ExpectableState + Sized> ExpectableStateExt for T
131where
132T: Send + Sync + 'static,
133 T::State: Send + Sync + 'static,
134{
135fn when_satisfied(
136&self,
137 expectation: Predicate<T::State>,
138 timeout: zx::MonotonicDuration,
139 ) -> BoxFuture<'_, Result<Self::State, Error>> {
140let state = self.clone();
141let exp = expectation.clone();
142 ExpectationFuture::new(self.clone(), expectation)
143 .map(|s| Ok(s))
144 .on_timeout(timeout.after_now(), move || {
145let state = state.read();
146let result = exp.assert_satisfied(&state);
147 result.map(|_| state).map_err(|err| {
148format_err!("Timed out waiting for expectation, last result:\n{:?}", err)
149 })
150 })
151 .boxed()
152 }
153}
154155/// Inner state for the `Expectable` helper type
156pub struct ExpectableInner<S, A> {
157// Current state
158pub state: S,
159160// Pending Tasks
161tasks: Slab<task::Waker>,
162163// Auxillary shared data
164pub aux: A,
165}
166167/// `Expectable<S,A>` is an easy way to build an implementation of `ExpectableState` to await upon.
168/// The Aux type `A` is commonly used to hold a FIDL Proxy to drive the behavior under test.
169pub type Expectable<S, A> = Arc<RwLock<ExpectableInner<S, A>>>;
170171pub fn expectable<S, A>(state: S, aux: A) -> Expectable<S, A> {
172 Arc::new(RwLock::new(ExpectableInner { state, tasks: Slab::new(), aux }))
173}
174175impl<S: Clone + 'static, A> ExpectableState for Expectable<S, A> {
176type State = S;
177178/// Register a task as needing waking when state changes
179fn store_task(&mut self, cx: &mut task::Context<'_>) -> usize {
180self.write().tasks.insert(cx.waker().clone())
181 }
182183/// Remove a task from being tracked
184fn remove_task(&mut self, key: usize) {
185let mut harness = self.write();
186if harness.tasks.contains(key) {
187 drop(harness.tasks.remove(key));
188 }
189 }
190191/// Notify all pending tasks that state has changed
192fn notify_state_changed(&self) {
193for task in &RwLock::read(self).tasks {
194 task.1.wake_by_ref();
195 }
196self.write().tasks.clear()
197 }
198199fn read(&self) -> Self::State {
200 RwLock::read(self).state.clone()
201 }
202}
203204/// A trait to provide convenience methods on Expectable types held within wrapping harnesses
205pub trait ExpectableExt<S, A> {
206/// Mutable access the auxilliary data
207fn aux(&self) -> MappedRwLockWriteGuard<'_, A>;
208209/// Mutable access to the state
210fn write_state(&self) -> MappedRwLockWriteGuard<'_, S>;
211}
212213// All `Expectable<S,A>` provide these methods, and thus so do any types implementing `Deref` whose
214// targets are `Expectable<S,A>`
215impl<S, A> ExpectableExt<S, A> for Expectable<S, A> {
216fn aux(&self) -> MappedRwLockWriteGuard<'_, A> {
217 RwLockWriteGuard::map(self.write(), |harness| &mut harness.aux)
218 }
219220fn write_state(&self) -> MappedRwLockWriteGuard<'_, S> {
221 RwLockWriteGuard::map(self.write(), |harness| &mut harness.state)
222 }
223}