Skip to content

Commit 0c259bb

Browse files
committed
revert FailScenario
Signed-off-by: Xintao <[email protected]>
1 parent 18eafb7 commit 0c259bb

File tree

1 file changed

+78
-58
lines changed

1 file changed

+78
-58
lines changed

src/lib.rs

+78-58
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@
2828
//! I/O panic:
2929
//!
3030
//! ```rust
31-
//! use fail::fail_point;
31+
//! use fail::{fail_point, FailScenario};
3232
//!
3333
//! fn do_fallible_work() {
3434
//! fail_point!("read-dir");
3535
//! let _dir: Vec<_> = std::fs::read_dir(".").unwrap().collect();
3636
//! // ... do some work on the directory ...
3737
//! }
3838
//!
39-
//! fail::setup();
39+
//! let scenario = FailScenario::setup();
4040
//! do_fallible_work();
41-
//! fail::teardown();
41+
//! scenario.teardown();
4242
//! println!("done");
4343
//! ```
4444
//!
@@ -116,7 +116,9 @@
116116
//! Here's a example to show the process:
117117
//!
118118
//! ```rust
119-
//! fail::setup();
119+
//! use fail::FailScenario;
120+
//!
121+
//! let _scenario = FailScenario::setup();
120122
//! fail::cfg("p1", "sleep(100)").unwrap();
121123
//! println!("Global registry: {:?}", fail::list());
122124
//! {
@@ -165,7 +167,7 @@
165167
//! function we used earlier to return a `Result`:
166168
//!
167169
//! ```rust
168-
//! use fail::fail_point;
170+
//! use fail::{fail_point, FailScenario};
169171
//! use std::io;
170172
//!
171173
//! fn do_fallible_work() -> io::Result<()> {
@@ -176,9 +178,9 @@
176178
//! }
177179
//!
178180
//! fn main() -> io::Result<()> {
179-
//! fail::setup();
181+
//! let scenario = FailScenario::setup();
180182
//! do_fallible_work()?;
181-
//! fail::teardown();
183+
//! scenario.teardown();
182184
//! println!("done");
183185
//! Ok(())
184186
//! }
@@ -264,6 +266,7 @@ use std::env::VarError;
264266
use std::fmt::Debug;
265267
use std::str::FromStr;
266268
use std::sync::atomic::{AtomicUsize, Ordering};
269+
use std::sync::MutexGuard;
267270
use std::sync::{Arc, Condvar, Mutex, RwLock, TryLockError};
268271
use std::time::{Duration, Instant};
269272
use std::{env, thread};
@@ -588,63 +591,80 @@ impl FailPointRegistry {
588591
lazy_static::lazy_static! {
589592
static ref REGISTRY_GROUP: RwLock<HashMap<thread::ThreadId, Arc<RwLock<Registry>>>> = Default::default();
590593
static ref REGISTRY_GLOBAL: FailPointRegistry = Default::default();
594+
static ref SCENARIO: Mutex<&'static FailPointRegistry> = Mutex::new(&REGISTRY_GLOBAL);
591595
}
592596

593-
/// Set up the global fail points registry.
594-
///
595-
/// Configures global fail points specified in the `FAILPOINTS` environment variable.
596-
/// It does not otherwise change any existing fail point configuration.
597-
///
598-
/// The format of `FAILPOINTS` is `failpoint=actions;...`, where
599-
/// `failpoint` is the name of the fail point. For more information
600-
/// about fail point actions see the [`cfg`](fn.cfg.html) function and
601-
/// the [`fail_point`](macro.fail_point.html) macro.
602-
///
603-
/// `FAILPOINTS` may configure fail points that are not actually defined. In
604-
/// this case the configuration has no effect.
605-
///
606-
/// This function should generally be called prior to running a test with fail
607-
/// points, and afterward paired with [`teardown`](fn.teardown.html).
608-
///
609-
/// # Panics
610-
///
611-
/// Panics if an action is not formatted correctly.
612-
pub fn setup() {
613-
let mut registry = REGISTRY_GLOBAL.registry.write().unwrap();
614-
cleanup(&mut registry);
615-
616-
let failpoints = match env::var("FAILPOINTS") {
617-
Ok(s) => s,
618-
Err(VarError::NotPresent) => return,
619-
Err(e) => panic!("invalid failpoints: {:?}", e),
620-
};
621-
for mut cfg in failpoints.trim().split(';') {
622-
cfg = cfg.trim();
623-
if cfg.is_empty() {
624-
continue;
625-
}
626-
let (name, order) = partition(cfg, '=');
627-
match order {
628-
None => panic!("invalid failpoint: {:?}", cfg),
629-
Some(order) => {
630-
if let Err(e) = set(&mut registry, name.to_owned(), order) {
631-
panic!("unable to configure failpoint \"{}\": {}", name, e);
597+
/// Test scenario with configured fail points.
598+
#[derive(Debug)]
599+
pub struct FailScenario<'a> {
600+
scenario_guard: MutexGuard<'a, &'static FailPointRegistry>,
601+
}
602+
603+
impl<'a> FailScenario<'a> {
604+
/// Set up the global fail points registry.
605+
///
606+
/// Configures global fail points specified in the `FAILPOINTS` environment variable.
607+
/// It does not otherwise change any existing fail point configuration.
608+
///
609+
/// The format of `FAILPOINTS` is `failpoint=actions;...`, where
610+
/// `failpoint` is the name of the fail point. For more information
611+
/// about fail point actions see the [`cfg`](fn.cfg.html) function and
612+
/// the [`fail_point`](macro.fail_point.html) macro.
613+
///
614+
/// `FAILPOINTS` may configure fail points that are not actually defined. In
615+
/// this case the configuration has no effect.
616+
///
617+
/// This function should generally be called prior to running a test with fail
618+
/// points, and afterward paired with [`teardown`](fn.teardown.html).
619+
///
620+
/// # Panics
621+
///
622+
/// Panics if an action is not formatted correctly.
623+
pub fn setup() -> Self {
624+
let scenario_guard = SCENARIO.lock().unwrap_or_else(|e| e.into_inner());
625+
let mut registry = scenario_guard.registry.write().unwrap();
626+
cleanup(&mut registry);
627+
628+
let failpoints = match env::var("FAILPOINTS") {
629+
Ok(s) => s,
630+
Err(VarError::NotPresent) => return Self { scenario_guard },
631+
Err(e) => panic!("invalid failpoints: {:?}", e),
632+
};
633+
for mut cfg in failpoints.trim().split(';') {
634+
cfg = cfg.trim();
635+
if cfg.is_empty() {
636+
continue;
637+
}
638+
let (name, order) = partition(cfg, '=');
639+
match order {
640+
None => panic!("invalid failpoint: {:?}", cfg),
641+
Some(order) => {
642+
if let Err(e) = set(&mut registry, name.to_owned(), order) {
643+
panic!("unable to configure failpoint \"{}\": {}", name, e);
644+
}
632645
}
633646
}
634647
}
648+
Self { scenario_guard }
649+
}
650+
651+
/// Tear down the global fail points registry.
652+
///
653+
/// Clears the configuration of global fail points. Any paused fail
654+
/// points will be notified before they are deactivated.
655+
///
656+
/// This function should generally be called after running a test with fail points.
657+
/// Calling `teardown` without previously calling `setup` results in a no-op.
658+
pub fn teardown(self) {
659+
drop(self);
635660
}
636661
}
637662

638-
/// Tear down the global fail points registry.
639-
///
640-
/// Clears the configuration of global fail points. Any paused fail
641-
/// points will be notified before they are deactivated.
642-
///
643-
/// This function should generally be called after running a test with fail points.
644-
/// Calling `teardown` without previously calling `setup` results in a no-op.
645-
pub fn teardown() {
646-
let mut registry = REGISTRY_GLOBAL.registry.write().unwrap();
647-
cleanup(&mut registry);
663+
impl<'a> Drop for FailScenario<'a> {
664+
fn drop(&mut self) {
665+
let mut registry = self.scenario_guard.registry.write().unwrap();
666+
cleanup(&mut registry);
667+
}
648668
}
649669

650670
/// Clean all registered fail points.
@@ -1099,7 +1119,7 @@ mod tests {
10991119
"FAILPOINTS",
11001120
"setup_and_teardown1=return;setup_and_teardown2=pause;",
11011121
);
1102-
setup();
1122+
let scenario = FailScenario::setup();
11031123

11041124
let group = FailPointRegistry::new();
11051125
let handler = thread::spawn(move || {
@@ -1130,7 +1150,7 @@ mod tests {
11301150
});
11311151
assert!(rx.recv_timeout(Duration::from_millis(500)).is_err());
11321152

1133-
teardown();
1153+
scenario.teardown();
11341154
assert_eq!(rx.recv_timeout(Duration::from_millis(500)).unwrap(), 0);
11351155
assert_eq!(f1(), 0);
11361156
}

0 commit comments

Comments
 (0)