proptest-rs / proptest

Hypothesis-like property testing for Rust
Apache License 2.0
1.69k stars 158 forks source link

Proptest fails when running when combining fork and ignore #328

Open jonathanberthias opened 1 year ago

jonathanberthias commented 1 year ago

When I ignore a test and want to run it forked, I get the following error: Child process crashed or timed out before the first test started running; giving up.

Here is a test function to reproduce:

proptest!(
    #![proptest_config(ProptestConfig {
        fork: true,
        .. ProptestConfig::default()
    })]

    #[ignore]
    #[test]
    fn simple(i: u32) {
        prop_assert!(i < 100)
    }
);

Output from cargo test -- --ignored simple:

running 1 test
proptest: FileFailurePersistence::SourceParallel set, but failed to find lib.rs or main.rs
thread 'simple' panicked at 'Test failed normally in child process.
Test failed: assertion failed: i < 100 at tests/integration_tests.rs:248.
minimal failing input: i = 100
    successes: 0
    local rejects: 0
    global rejects: 0
', /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/proptest-1.2.0/src/test_runner/runner.rs:489:31
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

running 1 test
proptest: FileFailurePersistence::SourceParallel set, but failed to find lib.rs or main.rs
thread 'simple' panicked at 'Test failed normally in child process.
Test failed: failed in other process.
minimal failing input: i = 100
    successes: 0
    local rejects: 0
    global rejects: 0
', /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/proptest-1.2.0/src/test_runner/runner.rs:489:31
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'simple' panicked at 'Test aborted: Child process crashed or timed out before the first test started running; giving up.
    successes: 0
    local rejects: 0
    global rejects: 0
', tests/integration_tests.rs:239:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Note that with a more complex strategy, I do not even get the correct (double?) output, only the error message.

Everything works fine without the fork option, and it also works without the #[ignore] attribute.

matthew-russo commented 1 year ago

edit: i'm a fool and didn't read the issue well enough. I can repro this locally.

thanks for the report. will try to dig in to this in the next couple days. its not clear if this is a bug with forking or just unintuitive output

matthew-russo commented 1 year ago

some quick observations that make me think this is just unintuitive output. running this test as not ignored and forked results in the same output

╰─⠠⠵ cat src/main.rs
fn main() {
    println!("Hello, world!");
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod test {
    use super::*;
    use proptest::prelude::*;

    proptest!(
        #![proptest_config(ProptestConfig {
            fork: true,
            .. ProptestConfig::default()
        })]

        #[test]
        fn simple(i: u32) {
            prop_assert!(i < 100)
        }
    );
}
╰─⠠⠵ cargo test
warning: unused import: `super::*`
  --> src/main.rs:11:9
   |
11 |     use super::*;
   |         ^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: function `add` is never used
 --> src/main.rs:5:4
  |
5 | fn add(a: i32, b: i32) -> i32 {
  |    ^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: `proptest-playground` (bin "proptest-playground" test) generated 2 warnings (run `cargo fix --bin "proptest-playground" --tests` to apply 1 suggestion)
    Finished test [unoptimized + debuginfo] target(s) in 0.02s
     Running unittests src/main.rs (target/debug/deps/proptest_playground-218334ce47af1ed3)

running 1 test
test test::simple ... FAILED

failures:

---- test::simple stdout ----

running 1 test
thread 'test::simple' panicked at 'Test failed normally in child process.
Test failed: assertion failed: i < 100 at src/main.rs:22.
minimal failing input: i = 100
        successes: 0
        local rejects: 0
        global rejects: 0
', /Users/matthewrusso/.cargo/registry/src/github.com-1ecc6299db9ec823/proptest-1.2.0/src/test_runner/runner.rs:489:31
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

running 1 test
thread 'test::simple' panicked at 'Test failed normally in child process.
Test failed: failed in other process.
minimal failing input: i = 100
        successes: 0
        local rejects: 0
        global rejects: 0
', /Users/matthewrusso/.cargo/registry/src/github.com-1ecc6299db9ec823/proptest-1.2.0/src/test_runner/runner.rs:489:31
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'test::simple' panicked at 'Test aborted: Child process crashed or timed out before the first test started running; giving up.
        successes: 0
        local rejects: 0
        global rejects: 0
', src/main.rs:14:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    test::simple

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

error: test failed, to rerun pass `--bin proptest-playground`
matthew-russo commented 1 year ago

without looking at the code at all, if i had to guess, the double output is from the child process printing the failure, the parent process replaying that failure and then printing it again, as well as the error about the child processing failing.

if this is the case we could probably make it a bit more intuitive by: