pub struct MockSleepProvider {
state: Arc<Mutex<SleepSchedule>>,
}
Expand description
A dummy SleepProvider
instance for testing.
The MockSleepProvider ignores the current time, and instead keeps
its own view of the current Instant
and SystemTime
. You
can advance them in-step by calling advance()
, and you can simulate
jumps in the system clock by calling jump()
.
This is not for production use.
§Deprecated
This mock time facility has some limitations, notably lack of support for tasks, and a confusing API for controlling the mock time.
New test cases should probably use MockRuntime
which incorporates MockSimpletimeProvider
.
Comparison of MockSleepProvider
with SimpleMockTimeProvider
:
-
SimpleMockTimeProvider
does not support, or expect the use of,block_advance
et al. Instead, the advancement of simulated time is typically done automatically in cooperation with the executor, usingMockRuntime
’sadvance_*
methods. -
Consequently,
SimpleMockTimeProvider
can be used in test cases that spawn tasks and perform sleeps in them. -
And, consequently,
SimpleMockTimeProvider
does not need non-test code to contain calls which are solely related to getting the time mocking to work right. -
SimpleMockTimeProvider
gives correct sleeping locations withMockExecutor
‘s dump of sleeping tasks’ stack traces. -
Conversely, to use
SimpleMockTimeProvider
in all but the most simple test cases, coordination with the executor is required. This coordination is provided by the integratedMockRuntime
;SimpleMockTimeProvider
is of limited usefulness by itself.
§Examples
Suppose you’ve written a function that relies on making a connection to the network and possibly timing out:
use tor_rtcompat::{Runtime,SleepProviderExt};
use std::{net::SocketAddr, io::Result, time::Duration, io::Error};
use futures::io::AsyncWriteExt;
async fn say_hi(runtime: impl Runtime, addr: &SocketAddr) -> Result<()> {
let delay = Duration::new(5,0);
runtime.timeout(delay, async {
let mut conn = runtime.connect(addr).await?;
conn.write_all(b"Hello world!\r\n").await?;
conn.close().await?;
Ok::<_,Error>(())
}).await??;
Ok(())
}
But how should you test this function?
You might try connecting to a well-known website to test the connection case, and to a well-known black hole to test the timeout case… but that’s a bit undesirable. Your tests might be running in a container with no internet access; and even if they aren’t, it isn’t so great for your tests to rely on the actual state of the internet. Similarly, if you make your timeout too long, your tests might block for a long time; but if your timeout is too short, the tests might fail on a slow machine or on a slow network.
Or, you could solve both of these problems by using tor-rtmock
to replace the internet and the passage of time. (Here we’re only
replacing the internet.)
use tor_rtmock::{MockSleepRuntime,MockNetRuntime,net::MockNetwork};
use tor_rtcompat::{NetStreamProvider,NetStreamListener};
use futures::io::AsyncReadExt;
use std::net::SocketAddr;
use futures::StreamExt as _;
tor_rtcompat::test_with_all_runtimes!(|rt| async move {
let addr1 = "198.51.100.7".parse().unwrap();
let addr2 = "198.51.100.99".parse().unwrap();
let sockaddr: SocketAddr = "198.51.100.99:101".parse().unwrap();
// Make a runtime that pretends that we are at the first address...
let fake_internet = MockNetwork::new();
let rt1 = fake_internet.builder().add_address(addr1).runtime(rt.clone());
// ...and one that pretends we're listening at the second address.
let rt2 = fake_internet.builder().add_address(addr2).runtime(rt);
let listener = rt2.listen(&sockaddr).await.unwrap();
let mut incoming_stream = listener.incoming();
// Now we can test our function!
let (result1,output) = futures::join!(
say_hi(rt1, &sockaddr),
async {
let (mut conn,addr) = incoming_stream.next().await.unwrap().unwrap();
assert_eq!(addr.ip(), addr1);
let mut output = Vec::new();
conn.read_to_end(&mut output).await.unwrap();
output
});
assert!(result1.is_ok());
assert_eq!(&output[..], b"Hello world!\r\n");
});
Fields§
§state: Arc<Mutex<SleepSchedule>>
The shared backend for this MockSleepProvider and its futures.
Implementations§
Source§impl MockSleepProvider
impl MockSleepProvider
Sourcepub fn new(wallclock: SystemTime) -> Self
pub fn new(wallclock: SystemTime) -> Self
Create a new MockSleepProvider, starting at a given wall-clock time.
Sourcepub async fn advance(&self, dur: Duration)
pub async fn advance(&self, dur: Duration)
Advance the simulated timeline forward by dur
.
Calling this function will wake any pending futures as appropriate, and yield to the scheduler so they get a chance to run.
§Limitations
This function advances time in one big step. We might instead want to advance in small steps and make sure that each step’s futures can get run before the ones scheduled to run after it.
Sourcepub(crate) fn advance_noyield(&self, dur: Duration)
pub(crate) fn advance_noyield(&self, dur: Duration)
Advance the simulated timeline forward by dur
.
Calling this function will wake any pending futures as
appropriate, but not yield to the scheduler. Mostly you
should call advance
instead.
Sourcepub fn jump_to(&self, new_wallclock: SystemTime)
pub fn jump_to(&self, new_wallclock: SystemTime)
Simulate a discontinuity in the system clock, by jumping to
new_wallclock
.
§Panics
Panics if we have already panicked while holding the lock on the internal timer state, and the lock is poisoned.
Sourcepub(crate) fn time_until_next_timeout(&self) -> Option<Duration>
pub(crate) fn time_until_next_timeout(&self) -> Option<Duration>
Return the amount of virtual time until the next timeout should elapse.
If there are no more timeouts, return None. If the next timeout should elapse right now, return Some(0).
Sourcepub(crate) fn should_advance(&mut self) -> bool
pub(crate) fn should_advance(&mut self) -> bool
Return true if a WaitFor
driving this sleep provider should advance time in order for
futures blocked on sleeping to make progress.
NOTE: This function has side-effects; if it returns true, the caller is expected to do an advance before calling it again.
Sourcepub(crate) fn register_waitfor_waker(&mut self, waker: Waker)
pub(crate) fn register_waitfor_waker(&mut self, waker: Waker)
Register a Waker
to be woken up when an advance in time is required to make progress.
This is used by WaitFor
.
Sourcepub(crate) fn clear_waitfor_waker(&mut self)
pub(crate) fn clear_waitfor_waker(&mut self)
Remove a previously registered Waker
registered with register_waitfor_waker()
.
Sourcepub(crate) fn has_waitfor_waker(&self) -> bool
pub(crate) fn has_waitfor_waker(&self) -> bool
Returns true if a Waker
has been registered with register_waitfor_waker()
.
This is used to ensure that you don’t have two concurrent WaitFor
s running.
Trait Implementations§
Source§impl Clone for MockSleepProvider
impl Clone for MockSleepProvider
Source§fn clone(&self) -> MockSleepProvider
fn clone(&self) -> MockSleepProvider
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl CoarseTimeProvider for MockSleepProvider
impl CoarseTimeProvider for MockSleepProvider
Source§fn now_coarse(&self) -> CoarseInstant
fn now_coarse(&self) -> CoarseInstant
CoarseTimeProvider
’s view of the current instant. Read moreSource§impl Debug for MockSleepProvider
impl Debug for MockSleepProvider
Source§impl Default for MockSleepProvider
impl Default for MockSleepProvider
Source§impl SleepProvider for MockSleepProvider
impl SleepProvider for MockSleepProvider
Source§type SleepFuture = Sleeping
type SleepFuture = Sleeping
SleepProvider::sleep()
Source§fn sleep(&self, duration: Duration) -> Self::SleepFuture
fn sleep(&self, duration: Duration) -> Self::SleepFuture
duration
has
elapsed.Source§fn block_advance<T: Into<String>>(&self, reason: T)
fn block_advance<T: Into<String>>(&self, reason: T)
Source§fn release_advance<T: Into<String>>(&self, reason: T)
fn release_advance<T: Into<String>>(&self, reason: T)
block_advance
no
longer exists, and it’s fine to move time forward if nothing else is blocking advances. Read moreSource§fn allow_one_advance(&self, dur: Duration)
fn allow_one_advance(&self, dur: Duration)
block_advance
API has been used. Read moreSource§fn wallclock(&self) -> SystemTime
fn wallclock(&self) -> SystemTime
Auto Trait Implementations§
impl Freeze for MockSleepProvider
impl RefUnwindSafe for MockSleepProvider
impl Send for MockSleepProvider
impl Sync for MockSleepProvider
impl Unpin for MockSleepProvider
impl UnwindSafe for MockSleepProvider
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,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> 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 more§impl<T> SleepProviderExt for Twhere
T: SleepProvider,
impl<T> SleepProviderExt for Twhere
T: SleepProvider,
§fn timeout<F>(
&self,
duration: Duration,
future: F,
) -> Timeout<F, Self::SleepFuture> ⓘwhere
F: Future,
fn timeout<F>(
&self,
duration: Duration,
future: F,
) -> Timeout<F, Self::SleepFuture> ⓘwhere
F: Future,
§fn sleep_until_wallclock(
&self,
when: SystemTime,
) -> SleepUntilWallclock<'_, Self>
fn sleep_until_wallclock( &self, when: SystemTime, ) -> SleepUntilWallclock<'_, Self>
when
or later, trying to
recover from clock jumps. Read more