tikv / fail-rs

Fail points for rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fail_point! does nothing unless a FailScenario exists

sourcefrog opened this issue · comments

Perhaps I'm doing something wrong, but I have code that looks very similar to the examples, and I can't get it to panic or otherwise respond to failpoints in the environment:

The full code is in https://github.com/sourcefrog/fail-repro

main.rs is

use fail::fail_point;

fn main() {
    println!("Has failpoints: {}", fail::has_failpoints());
    println!(
        "FAILPOINTS is {:?}",
        std::env::var("FAILPOINTS").unwrap_or_default()
    );
    fail_point!("main");
    println!("Failpoint passed");
}

When I run this:

$ FAILPOINTS=main=panic cargo +1.61 r --features fail/failpoints
    Updating crates.io index
...
     Running `target/debug/fail-repro`
Has failpoints: true
FAILPOINTS is "main=panic"
Failpoint passed

$ FAILPOINTS=main=print cargo +1.61 r --features fail/failpoints
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/fail-repro`
Has failpoints: true
FAILPOINTS is "main=print"
Failpoint passed

In case this was broken by a later Cargo change, I tried it on both 1.76 and 1.63 and they both show the same behavior.

This is on x86_64 Linux.

Looking at the code, I think the problem is that the environment variable is only read by the FailScenario constructor, so binaries that just directly have failpoints won't ever fail.

I guess I would have expected that you could just embed fail_point! and then exercise it interactively or from tests that call the binary, by setting $FAILPOINTS: at least, the docs somewhat give this impression.

Maybe the macro could lazily load the environment variable? I got the idea that FailScenario was a convenience for test code.

At least, maybe this could be more clear in the docs. But, perhaps the division of responsibility between them could be reconsidered...

The reason I hit this is that I want to exercise failpoints in code run as a subprocess of a test. I thought setting the variable would do it, but it seems that the code under test needs to do FailScenario::setup from its main function for them to have any effect. With that added, my reproduction case passes.

It seems like it would be better to separate

  1. Run a test using failpoints, holding a mutex to prevent any other changes to global failpoint configuration, and allowing the test to reconfigure failpoints
  2. Prepare code-under-test to respond to failpoints set in the environment or by tests: ideally this would be implicit by just using fail_point!