pub struct OomTest { /* private fields */ }Expand description
A test helper that checks that some code handles OOM correctly.
OomTest will only work correctly when OomTestAllocator is configured as
the global allocator.
OomTest does not support reentrancy, so you cannot run an OomTest within
an OomTest.
§Example
use std::time::Duration;
use wasmtime::Result;
use wasmtime_fuzzing::oom::{OomTest, OomTestAllocator};
#[global_allocator]
static GLOBAL_ALLOCATOR: OomTestAllocator = OomTestAllocator::new();
#[test]
fn my_oom_test() -> Result<()> {
OomTest::new()
.max_iters(1_000_000)
.max_duration(Duration::from_secs(5))
.allow_alloc_after_oom(true)
.test(|| {
todo!("insert code here that should handle OOM here...")
})
}Use test_with_reuse when you also want to check that some context is still
usable after the OOM, e.g. that nothing was left half-registered in state
that is shared with an Engine:
use wasmtime::Result;
use wasmtime_fuzzing::oom::OomTest;
#[test]
fn my_oom_reuse_test() -> Result<()> {
OomTest::new().test_with_reuse(
|| todo!("create the context that is reused after the OOM..."),
|context| todo!("insert code here that should handle OOM here..."),
|context| todo!("check that `context` is still usable..."),
)
}Implementations§
Source§impl OomTest
impl OomTest
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new OOM test.
By default there is no iteration or time limit, tests will be executed until the pass (or fail).
Sourcepub fn max_iters(&mut self, max_iters: u32) -> &mut Self
pub fn max_iters(&mut self, max_iters: u32) -> &mut Self
Configure the maximum number of times to run an OOM test.
Sourcepub fn max_duration(&mut self, max_duration: Duration) -> &mut Self
pub fn max_duration(&mut self, max_duration: Duration) -> &mut Self
Configure the maximum duration of time to run an OOM text.
Sourcepub fn allow_alloc_after_oom(&mut self, allow: bool) -> &mut Self
pub fn allow_alloc_after_oom(&mut self, allow: bool) -> &mut Self
Configure whether to allow allocation attempts after an OOM has already been injected.
The default is false.
Sourcepub fn alloc_succeeds_after_oom(&mut self, succeeds: bool) -> &mut Self
pub fn alloc_succeeds_after_oom(&mut self, succeeds: bool) -> &mut Self
Configure whether allocations after an OOM (assuming
allow_alloc_after_oom(true)) will succeed or will always return null.
The default is false.
Sourcepub fn allow_missed_oom_errors(&mut self, allow: bool) -> &mut Self
pub fn allow_missed_oom_errors(&mut self, allow: bool) -> &mut Self
Configure whether to allow a test to pass if it does not return
Err(OutOfMemory) when a synthetic OOM was injected (perhaps because it
is exercising logic that is robust to OOM).
The default is false.
Sourcepub fn seed(&mut self, seed: u64) -> &mut Self
pub fn seed(&mut self, seed: u64) -> &mut Self
Configure the seed for the RNG used in fuzz mode.
The default is 0.
Sourcepub fn test(&self, test_func: impl Fn() -> Result<()>) -> Result<()>
pub fn test(&self, test_func: impl Fn() -> Result<()>) -> Result<()>
Repeatedly run the given test function, injecting OOMs at different times and checking that it correctly handles them.
The test function should not use threads, or else allocations may not be tracked correctly and OOM injection may be incorrect.
The test function should return an Err(_) if and only if it encounters
an OOM.
Returns early once the test function returns Ok(()) before an OOM has
been injected.
Sourcepub async fn test_async(
&self,
test_func: impl AsyncFn() -> Result<()>,
) -> Result<()>
pub async fn test_async( &self, test_func: impl AsyncFn() -> Result<()>, ) -> Result<()>
The same as test but async.
Sourcepub fn test_with_reuse<T>(
&self,
make_context: impl Fn() -> Result<T>,
test_func: impl Fn(&mut T) -> Result<()>,
post_oom_func: impl Fn(T) -> Result<()>,
) -> Result<()>
pub fn test_with_reuse<T>( &self, make_context: impl Fn() -> Result<T>, test_func: impl Fn(&mut T) -> Result<()>, post_oom_func: impl Fn(T) -> Result<()>, ) -> Result<()>
The same as test, but additionally exercising context that is reused
after the OOM is triggered.
Each iteration runs three phases in sequence:
-
make_contextcreates the context that is shared between the two phases that follow. It is called afresh every iteration, so that each iteration begins from identical state. -
test_funcis the main OOM test, and is the only phase into which OOMs are injected. It is otherwise the same as the function given totest. -
post_oom_funcchecks that we recovered from the OOM correctly and that we can still interact with the context afterwards, e.g. that nothing was left half-registered in shared state, rather than properly cleaned up, when the OOM happened.
OOMs are never injected into make_context or post_oom_func and
neither’s allocations are counted. An Err(_) returned from either is a
test failure.
Sourcepub async fn test_with_reuse_async<T>(
&self,
make_context: impl AsyncFn() -> Result<T>,
test_func: impl AsyncFn(&mut T) -> Result<()>,
post_oom_func: impl AsyncFn(T) -> Result<()>,
) -> Result<()>
pub async fn test_with_reuse_async<T>( &self, make_context: impl AsyncFn() -> Result<T>, test_func: impl AsyncFn(&mut T) -> Result<()>, post_oom_func: impl AsyncFn(T) -> Result<()>, ) -> Result<()>
The same as test_with_reuse but async.
Sourcepub fn fuzz(&self, test_func: impl Fn() -> Result<()>) -> Result<()>
pub fn fuzz(&self, test_func: impl Fn() -> Result<()>) -> Result<()>
Similar to test but instead of exhaustively injecting OOMs on every
allocation, randomly chooses which allocation to OOM each iteration.
Requires max_iters to be set.
Sourcepub async fn fuzz_async(
&self,
test_func: impl AsyncFn() -> Result<()>,
) -> Result<()>
pub async fn fuzz_async( &self, test_func: impl AsyncFn() -> Result<()>, ) -> Result<()>
The same as fuzz but async.
Auto Trait Implementations§
impl Freeze for OomTest
impl RefUnwindSafe for OomTest
impl Send for OomTest
impl Sync for OomTest
impl Unpin for OomTest
impl UnsafeUnpin for OomTest
impl UnwindSafe for OomTest
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
§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