Skip to content

Commit

Permalink
Merge pull request #70 from tremor-rs/no-timeout
Browse files Browse the repository at this point in the history
Intoduce timeout as a feature
  • Loading branch information
palfrey committed Jul 1, 2022
2 parents 714def9 + e517367 commit 1ff7071
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 22 deletions.
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 indefinitely to be started
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"]
36 changes: 24 additions & 12 deletions serial_test/src/code_lock.rs
Expand Up @@ -2,13 +2,14 @@ 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;
#[cfg(feature = "timeout")]
use std::time::Instant;
use std::{
cell::RefCell,
collections::HashMap,
ops::{Deref, DerefMut},
sync::{atomic::AtomicU32, Arc},
time::{Duration, Instant},
time::Duration,
};

pub(crate) struct UniqueReentrantMutex {
Expand Down Expand Up @@ -46,11 +47,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 +71,25 @@ 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;
}

#[cfg(feature = "timeout")]
pub(crate) fn wait_duration() -> Duration {
*MAX_WAIT.lock().borrow()
*MAX_WAIT.read()
}

pub(crate) fn check_new_key(name: &str) {
#[cfg(feature = "timeout")]
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 +114,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);
}
}
}
}
1 change: 1 addition & 0 deletions serial_test/src/lib.rs
Expand Up @@ -63,6 +63,7 @@ mod parallel_file_lock;
#[cfg(feature = "file_locks")]
mod serial_file_lock;

#[cfg(feature = "timeout")]
pub use code_lock::set_max_wait;
pub use parallel_code_lock::{
local_async_parallel_core, local_async_parallel_core_with_return, local_parallel_core,
Expand Down
9 changes: 5 additions & 4 deletions serial_test/src/serial_code_lock.rs
Expand Up @@ -53,13 +53,14 @@ pub async fn local_async_serial_core(name: &str, fut: impl std::future::Future<O
#[allow(clippy::print_stdout)]
mod tests {
use super::local_serial_core;
use crate::code_lock::{check_new_key, wait_duration, LOCKS};
use crate::code_lock::{check_new_key, LOCKS};
use itertools::Itertools;
use parking_lot::RwLock;
use std::{
ops::Deref,
sync::{Arc, Barrier},
thread,
time::Duration,
};

#[test]
Expand All @@ -79,12 +80,12 @@ mod tests {
check_new_key("foo");
{
let unlock = local_locks
.try_read_recursive_for(wait_duration())
.try_read_recursive_for(Duration::from_secs(1))
.expect("read lock didn't work");
let mutex = unlock.deref().get("foo").unwrap();

let mut ptr_guard = local_ptrs
.try_write_for(wait_duration())
.try_write_for(Duration::from_secs(1))
.expect("write lock didn't work");
ptr_guard.push(mutex.id);
}
Expand All @@ -96,7 +97,7 @@ mod tests {
thread.join().expect("thread join worked");
}
let ptrs_read_lock = ptrs
.try_read_recursive_for(wait_duration())
.try_read_recursive_for(Duration::from_secs(1))
.expect("ptrs read work");
assert_eq!(ptrs_read_lock.len(), count);
println!("{:?}", ptrs_read_lock);
Expand Down

0 comments on commit 1ff7071

Please sign in to comment.