pub struct MockExecutor { /* private fields */ }Expand description
Executor for running tests with mocked environment
For test cases which don’t actually wait for anything in the real world.
This is the executor.
It implements Spawn and ToplevelBlockOn
It will usually be used as part of a MockRuntime.
To run futures, call ToplevelBlockOn::block_on
§Restricted environment
Tests run with this executor must not attempt to block on anything “outside”: every future that anything awaits must (eventually) be woken directly by some other task in the same test case.
(By directly we mean that the Waker::wake call is made
by that waking future, before that future itself awaits anything.)
§Panics
The executor will panic
if the toplevel future (passed to block_on)
doesn’t complete (without externally blocking),
but instead waits for something.
The executor will malfunction or panic if reentered.
(Eg, if block_on is reentered.)
Implementations§
Source§impl MockExecutor
impl MockExecutor
Sourcepub fn with_scheduling(scheduling: SchedulingPolicy) -> Self
pub fn with_scheduling(scheduling: SchedulingPolicy) -> Self
Make a MockExecutor with a specific SchedulingPolicy
Source§impl MockExecutor
impl MockExecutor
Sourcepub fn spawn_identified(
&self,
desc: impl Display,
fut: impl Future<Output = ()> + Send + 'static,
) -> impl Debug + Clone + Send + 'static
pub fn spawn_identified( &self, desc: impl Display, fut: impl Future<Output = ()> + Send + 'static, ) -> impl Debug + Clone + Send + 'static
Spawn a task and return something to identify it
desc should Display as some kind of short string (ideally without spaces)
and will be used in the Debug impl and trace log messages from MockExecutor.
The returned value is an opaque task identifier which is very cheap to clone
and which can be used by the caller in debug logging,
if it’s desired to correlate with the debug output from MockExecutor.
Most callers will want to ignore it.
This method is infallible. (The MockExecutor cannot be shut down.)
Sourcepub fn spawn_join<T: Debug + Send + 'static>(
&self,
desc: impl Display,
fut: impl Future<Output = T> + Send + 'static,
) -> impl Future<Output = T>
pub fn spawn_join<T: Debug + Send + 'static>( &self, desc: impl Display, fut: impl Future<Output = T> + Send + 'static, ) -> impl Future<Output = T>
Spawn a task and return its output for further usage
desc should Display as some kind of short string (ideally without spaces)
and will be used in the Debug impl and trace log messages from MockExecutor.
Source§impl MockExecutor
impl MockExecutor
Sourcepub fn progress_until_stalled(&self) -> impl Future<Output = ()>
pub fn progress_until_stalled(&self) -> impl Future<Output = ()>
Run tasks in the current executor until every other task is waiting
§Panics
Might malfunction or panic if more than one such call is running at once.
(Ie, you must .await or drop the returned Future
before calling this method again.)
Must be called and awaited within a future being run by self.
Source§impl MockExecutor
impl MockExecutor
Sourcepub fn subthread_spawn<T: Send + 'static>(
&self,
desc: impl Display,
call: impl FnOnce() -> T + Send + 'static,
) -> impl Future<Output = Result<T, Box<dyn Any + Send>>> + Unpin + Send + Sync + 'static
pub fn subthread_spawn<T: Send + 'static>( &self, desc: impl Display, call: impl FnOnce() -> T + Send + 'static, ) -> impl Future<Output = Result<T, Box<dyn Any + Send>>> + Unpin + Send + Sync + 'static
Spawn a “Subthread”, for processing in a sync context
call will be run on a separate thread, called a “Subthread”.
But it will not run simultaneously with the executor, nor with other Subthreads. So Subthreads are somewhat like coroutines.
call must be capable of making progress without waiting for any other Subthreads.
call may wait for async futures, using
subthread_block_on_future.
Subthreads may be used for cpubound activity,
or synchronous IO (such as large volumes of disk activity),
provided that the synchronous code will reliably make progress,
without waiting (directly or indirectly) for any async task or Subthread -
except via subthread_block_on_future.
§Subthreads vs raw std::thread threads
Programs using MockExecutor may use std::thread threads directly.
However, this is not recommended. There are severe limitations:
- Only a Subthread can re-enter the async context from sync code:
this must be done with
using
subthread_block_on_future. (Re-entering the executor withblock_onis not allowed.) - If async tasks want to suspend waiting for synchronous code,
the synchronous code must run on a Subthread.
This allows the
MockExecutorto know when that synchronous code is still making progress. (This is needed forprogress_until_stalledand the facilities which use it, such asMockRuntime::advance_until_stalled.) - Subthreads never run in parallel -
they only run as scheduled deterministically by the
MockExecutor. So using Subthreads eliminates a source of test nonndeterminism. (Execution order is still varied due to explicitly varying the scheduling policy.)
§Panics, abuse, and malfunctions
If call panics and unwinds, spawn_subthread yields Err.
The application code should to do something about it if this happens,
typically, logging errors, tearing things down, or failing a test case.
If the executor doesn’t run, the subthread will not run either, and will remain stuck. (So, typically, if the thread supposed to run the executor panics, for example because a future or the executor itself panics, all the subthreads will become stuck - effectively, they’ll be leaked.)
spawn_subthread panics if OS thread spawning fails.
(Like std::thread::spawn() does.)
MockExecutors will malfunction or panic if
any executor invocation method (eg block_on) is called on a Subthread.
Sourcepub fn subthread_block_on_future<T: Send + 'static>(
&self,
fut: impl Future<Output = T>,
) -> T
pub fn subthread_block_on_future<T: Send + 'static>( &self, fut: impl Future<Output = T>, ) -> T
Call an async Future from a Subthread
Blocks the Subthread, and arranges to run async tasks,
including fut, until fut completes.
fut is polled on the executor thread, not on the Subthread.
(We may change that in the future, allowing passing a non-Send future.)
§Panics, abuse, and malfunctions
subthread_block_on_future will malfunction or panic
if called on a thread that isn’t a Subthread from the same MockExecutor
(ie a thread made with spawn_subthread).
If fut itself panics, the executor will panic.
If the executor isn’t running, subthread_block_on_future will hang indefinitely.
See spawn_subthread.
Source§impl MockExecutor
impl MockExecutor
Sourcepub fn n_tasks(&self) -> usize
pub fn n_tasks(&self) -> usize
Return the number of tasks running in this executor
One possible use is for a test case to check that task(s) that ought to have exited, have indeed done so.
In the usual case, the answer will be at least 1,
because it counts the future passed to
block_on
(perhaps via MockRuntime::test_with_various).
Source§impl MockExecutor
impl MockExecutor
Sourcepub fn debug_dump(&self)
pub fn debug_dump(&self)
Dump the executor’s state including backtraces of waiting tasks, to stderr
This is considerably more extensive than simply
MockExecutor as Debug.
(This is a convenience method, which wraps
MockExecutor::as_debug_dump().
§Backtrace salience (possible spurious traces)
Summary
The technique used to capture backtraces when futures sleep is not 100% exact. It will usually show all the actual sleeping sites, but it might also show other backtraces which were part of the implementation of some complex relevant future.
Details
When a future’s implementation wants to sleep,
it needs to record the Waker (from the Context)
so that the “other end” can call .wake() on it later,
when the future should be woken.
Since Context.waker() gives &Waker, borrowed from the Context,
the future must clone the Waker,
and it must do so in within the poll() call.
A future which is waiting in a select! will typically
show multiple traces, one for each branch.
But,
if a future sleeps on one thing, and then when polled again later,
sleeps on something different, without waking up in between,
both backtrace locations will be shown.
And,
a complicated future contraption might clone the Waker more times.
So not every backtrace will necessarily be informative.
§Panics
Panics on write errors.
Sourcepub fn as_debug_dump(&self) -> DebugDump<'_>
pub fn as_debug_dump(&self) -> DebugDump<'_>
Dump the executor’s state including backtraces of waiting tasks
This is considerably more extensive than simply
MockExecutor as Debug.
Returns an object for formatting with Debug.
To simply print the dump to stderr (eg in a test),
use .debug_dump().
Backtrace salience (possible spurious traces) -
see .debug_dump().
Trait Implementations§
Source§impl Blocking for MockExecutor
impl Blocking for MockExecutor
Source§type ThreadHandle<T: Send + 'static> = Pin<Box<dyn Future<Output = T>>>
type ThreadHandle<T: Send + 'static> = Pin<Box<dyn Future<Output = T>>>
spawn_blocking Read moreSource§fn spawn_blocking<F, T>(&self, f: F) -> Self::ThreadHandle<T>
fn spawn_blocking<F, T>(&self, f: F) -> Self::ThreadHandle<T>
Source§fn reenter_block_on<F>(&self, future: F) -> F::Output
fn reenter_block_on<F>(&self, future: F) -> F::Output
Blocking::spawn_blocking Read moreSource§impl Clone for MockExecutor
impl Clone for MockExecutor
Source§fn clone(&self) -> MockExecutor
fn clone(&self) -> MockExecutor
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for MockExecutor
impl Debug for MockExecutor
Source§impl Default for MockExecutor
impl Default for MockExecutor
Source§fn default() -> MockExecutor
fn default() -> MockExecutor
Source§impl Spawn for MockExecutor
impl Spawn for MockExecutor
Source§impl ToplevelBlockOn for MockExecutor
impl ToplevelBlockOn for MockExecutor
Auto Trait Implementations§
impl Freeze for MockExecutor
impl RefUnwindSafe for MockExecutor
impl Send for MockExecutor
impl Sync for MockExecutor
impl Unpin for MockExecutor
impl UnwindSafe for MockExecutor
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<Sp> SpawnExt for Sp
impl<Sp> SpawnExt for Sp
Source§fn spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError>
fn spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError>
() to
completion. Read moreSource§fn spawn_with_handle<Fut>(
&self,
future: Fut,
) -> Result<RemoteHandle<<Fut as Future>::Output>, SpawnError>
fn spawn_with_handle<Fut>( &self, future: Fut, ) -> Result<RemoteHandle<<Fut as Future>::Output>, SpawnError>
Source§impl<T> WithSubscriber for T
impl<T> WithSubscriber for T
Source§fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
Source§fn with_current_subscriber(self) -> WithDispatch<Self>
fn with_current_subscriber(self) -> WithDispatch<Self>
impl<T> ErasedDestructor for Twhere
T: 'static,
Layout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...) attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 8 bytes