Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intoduce timeout as a feature #70

Merged
merged 3 commits into from Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 12 additions & 6 deletions serial_test/Cargo.toml
Expand Up @@ -14,28 +14,34 @@ keywords = ["sequential"]
lazy_static = "1.2"
parking_lot = "^0.12"
serial_test_derive = { version = "~0.8.0", path = "../serial_test_derive" }
fslock = {version = "0.2", optional = true}
document-features = {version = "0.2", optional=true}
log = {version = "0.4", optional = true}
futures = {version = "^0.3", default_features = false, features = ["executor"] }
fslock = { version = "0.2", optional = true }
document-features = { version = "0.2", optional = true }
log = { version = "0.4", optional = true }
futures = { version = "^0.3", default_features = false, features = [
"executor",
] }

[dev-dependencies]
itertools = "0.10"
tokio = { version = "^1.17", features = ["macros", "rt"] }

[features]
default = ["logging"]
default = ["logging", "timeout"]

## Switches on debug logging (and requires the `log` package)
logging = ["log"]

## The file_locks feature unlocks the `file_serial`/`file_parallel` macros
file_locks = ["fslock"]

## The `timeout` feature lets tests time out after a certain amount of time
## if not enabled tests will wait indefinetly to be started
Licenser marked this conversation as resolved.
Show resolved Hide resolved
timeout = []

docsrs = ["document-features"]

# docs.rs-specific configuration
[package.metadata.docs.rs]
all-features = true
# defines the configuration attribute `docsrs`
rustdoc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
30 changes: 19 additions & 11 deletions serial_test/src/code_lock.rs
Expand Up @@ -2,9 +2,8 @@ use crate::rwlock::{Locks, MutexGuardWrapper};
use lazy_static::lazy_static;
#[cfg(feature = "logging")]
use log::debug;
use parking_lot::{Mutex, RwLock};
use parking_lot::RwLock;
use std::{
cell::RefCell,
collections::HashMap,
ops::{Deref, DerefMut},
sync::{atomic::AtomicU32, Arc},
Expand Down Expand Up @@ -46,11 +45,14 @@ impl UniqueReentrantMutex {
lazy_static! {
pub(crate) static ref LOCKS: Arc<RwLock<HashMap<String, UniqueReentrantMutex>>> =
Arc::new(RwLock::new(HashMap::new()));
static ref MAX_WAIT: Arc<Mutex<RefCell<Duration>>> =
Arc::new(Mutex::new(RefCell::new(Duration::from_secs(60))));
static ref MUTEX_ID: Arc<AtomicU32> = Arc::new(AtomicU32::new(1));
}

#[cfg(feature = "timeout")]
lazy_static! {
static ref MAX_WAIT: Arc<RwLock<Duration>> = Arc::new(RwLock::new(Duration::from_secs(60)));
}

impl Default for UniqueReentrantMutex {
fn default() -> Self {
Self {
Expand All @@ -67,20 +69,23 @@ impl Default for UniqueReentrantMutex {
///
/// However, sometimes if you've got a *lot* of serial tests it might theoretically not be enough,
/// hence this method.
///
/// This function is only available when the `timeout` feature is enabled.
#[cfg(feature = "timeout")]
pub fn set_max_wait(max_wait: Duration) {
MAX_WAIT.lock().replace(max_wait);
*MAX_WAIT.write() = max_wait;
}

pub(crate) fn wait_duration() -> Duration {
*MAX_WAIT.lock().borrow()
*MAX_WAIT.read()
}

pub(crate) fn check_new_key(name: &str) {
let start = Instant::now();
loop {
#[cfg(feature = "logging")]
#[cfg(all(feature = "logging", feature = "timeout"))]
{
let duration = Instant::now() - start;
let duration = start.elapsed();
debug!("Waiting for '{}' {:?}", name, duration);
}
// Check if a new key is needed. Just need a read lock, which can be done in sync with everyone else
Expand All @@ -105,9 +110,12 @@ pub(crate) fn check_new_key(name: &str) {
// If the try_lock fails, then go around the loop again
// Odds are another test was also locking on the write and has now written the key

let duration = Instant::now() - start;
if duration >= wait_duration() {
panic!("check_new_key timed out!");
#[cfg(feature = "timeout")]
{
let duration = start.elapsed();
if duration > wait_duration() {
panic!("Timeout waiting for '{}' {:?}", name, duration);
}
}
}
}