Description
Tests by default capture their output of stdout/stderr using a libstd-private API, and these handles used to capture output are inherited by spawned threads of each test. This inheriting behavior interacts poorly for programs which have something akin to a global thread pool. Any test may spawn a thread added to the global thread pool and then that global thread's output is permanently fused to the original test that spawned it.
This ends up resulting in confusing situations such as rayon-rs/rayon#1066 where test panic messages are entirely swallowed by default and not displayed at all. A smaller (contrived) example of this is:
use std::sync::{Condvar, Mutex};
use std::thread::JoinHandle;
static LOCK: Mutex<Option<JoinHandle<()>>> = Mutex::new(None);
static COND: Condvar = Condvar::new();
#[test]
fn foo() {
*LOCK.lock().unwrap() = Some(std::thread::spawn(|| {
panic!("this message will not be seen");
}));
COND.notify_one();
}
#[test]
fn bar() {
let lock = LOCK.lock().unwrap();
let mut lock = COND.wait_while(lock, |state| state.is_none()).unwrap();
if let Err(e) = lock.take().unwrap().join() {
std::panic::resume_unwind(e);
}
}
where here the foo
test spawns some work which is then "resumed" in bar
, but the panic message isn't actually displayed anywhere:
$ cargo test
Finished test [unoptimized + debuginfo] target(s) in 0.01s
Running unittests src/main.rs (target/debug/deps/wat-fc5370c265a065b8)
running 2 tests
test foo ... ok
test bar ... FAILED
failures:
failures:
bar
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--bin wat`
I'm not sure that there's really an easy fix for this, so this is probably more of a "shouting into the void" style of issue, but figured I might as well open it after taking the time to investigate it anyway.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status