1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
//! There're some tests that sometimes pass and sometimes fail. We call them "flaky".
//!
//! This crate provides a macro attribute `#[flaky]` that allows you to mark all the flaky tests
//! in your codebase. You then have two options:
//!
//! 1. In default mode, `#[flaky]` will retry a test for a few times and pass it if at least one
//! run has passed.
//! 2. In strict mode, `#[flaky]` will still run test for a few times, but will only pass it
//! if every run has passed.
//!
//! To enable strict mode, set the environment variable `MARK_FLAKY_TESTS_STRICT=true`.
//!
//! To adjust the amount of times a test is retried, set the environment variable
//! `MARK_FLAKY_TESTS_RETRIES` to the desired amount. Default is 3.
//!
//! To use `#[flaky]` with `#[tokio::test]`, enable the `tokio` feature.
//!
//! Tests that return [`ExitCode`] are currently not supported due to std API limitations.
//!
//! [`ExitCode`]: ::std::process::ExitCode
// lint me harder
#![forbid(unsafe_code, non_ascii_idents)]
#![deny(
future_incompatible,
keyword_idents,
noop_method_call,
unused_qualifications,
clippy::wildcard_dependencies,
clippy::empty_line_after_outer_attr
)]
#![warn(clippy::pedantic, missing_docs)]
/// Mark test as flaky.
///
/// See [crate docs][crate] for details.
pub use mark_flaky_tests_macro::flaky;
#[doc(hidden)]
pub mod _priv {
#[cfg(feature = "tokio")]
pub use futures;
/// Defines whether a result is considered a test failure.
pub trait IsFailure {
fn is_failure(&self) -> bool;
}
// Tests returning unit types succeed unless panic.
impl IsFailure for () {
fn is_failure(&self) -> bool {
false
}
}
// Tests returning `Result<T, E>` succeed if result is ok and the inner value succeeds.
impl<T: IsFailure, E> IsFailure for Result<T, E> {
fn is_failure(&self) -> bool {
self.as_ref().map(T::is_failure).unwrap_or(true)
}
}
// Not sure why would you want to make tests that never return, but whatever floats your boat.
impl IsFailure for std::convert::Infallible {
fn is_failure(&self) -> bool {
match *self {}
}
}
// We even can implement this for the never type.
impl IsFailure for Never {
fn is_failure(&self) -> bool {
*self
}
}
// Thanks to the `never-say-never` crate for publishing this trick!
pub trait GetNever {
type Never;
}
impl<R, F: FnOnce() -> R> GetNever for F {
type Never = R;
}
type Never = <fn() -> ! as GetNever>::Never;
}