Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test timeouts #2798

Open
clarfonthey opened this issue Oct 30, 2019 · 9 comments
Open

Test timeouts #2798

clarfonthey opened this issue Oct 30, 2019 · 9 comments
Labels
A-test Proposals relating to testing.

Comments

@clarfonthey
Copy link
Contributor

clarfonthey commented Oct 30, 2019

It would be really nice if Rust had some kind of built-in timeout functionality, e.g.:

panic_after(Duration::from_millis(100), || {
    do_a_thing()
}

The API could be something different, maybe, and maybe there'd be a way to integrate it with the thread API instead of the test API. But either way, it would be nice to have to import an external crate to have some sort of maximum runtime for tests, to avoid infinite loops destroying the test runtime.

@shepmaster
Copy link
Member

I'd expect anything here to mostly happen in custom test frameworks. There's also the problem that you can't kill a thread, so anything either has to be cooperative or allow zombie threads.

@Lokathor
Copy link
Contributor

I know you can terminate a thread on windows. Do linux and mac lack that ability?

@MikailBag
Copy link

Linux supports it via tgkill(2) (AFAIK ok, but no cleanup) or pthread_cancel(3) (as far as I heard on rust-lang zulip, pthread_cancel can trigger Rust UB).

@clarfonthey
Copy link
Contributor Author

Honestly, zombie threads are better than living threads in an infinite loop. They can be reaped when the process exits in the case of tests, at least.

@canndrew
Copy link
Contributor

I'd expect anything here to mostly happen in custom test frameworks.

The default test framework that ships with rust should support this though. It's a small but necessary feature.

I think the timeout should be passed to the #[test] attribute as an argument. eg.

#[test(timeout = "200ms")]
fn my_cool_test() {}

or

#[test(timeout = Duration::new(1, 0))]
fn my_cool_test() {}

@shepmaster
Copy link
Member

shepmaster commented Nov 12, 2019

It's a small but necessary feature

I'll argue about necessary as we've lived without it for 4+ years and it can be written as a helper method today:

use std::{sync::mpsc, thread, time::Duration};

#[test]
fn oops() {
    panic_after(Duration::from_millis(100), || {
        thread::sleep(Duration::from_millis(200));
    })
}

fn panic_after<T, F>(d: Duration, f: F) -> T
where
    T: Send + 'static,
    F: FnOnce() -> T,
    F: Send + 'static,
{
    let (done_tx, done_rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        let val = f();
        done_tx.send(()).expect("Unable to send completion signal");
        val
    });

    match done_rx.recv_timeout(d) {
        Ok(_) => handle.join().expect("Thread panicked"),
        Err(_) => panic!("Thread took too long"),
    }
}

Nice to have? Certainly.

@sasa-tomic
Copy link

I'll argue about necessary as we've lived without it for 4+ years and it can be written as a helper method today

While it's possible to have the test timeout reduced this way, it's not possible to increase the test timeout over the hard-coded 120s value.

For our project (and surely for some other projects as well), we have some long-running tests for which 120s in some cases isn't enough. We need something like

#[test(timeout = Duration::new(300, 0))]
fn my_cool_test() {}

And this can't be done with the helper method IIUC.

@Yoga07
Copy link

Yoga07 commented Dec 22, 2020

Just in case somebody is interested in this: ntest crate has the #[timeout(_)] attr that can timeout tests and panic accordingly.

@rukai
Copy link

rukai commented Nov 9, 2021

While it's possible to have the test timeout reduced this way, it's not possible to increase the test timeout over the hard-coded 120s value.

This is the first result on google for "rust test timeout" so I need to point out that there is no hard-coded 120s timeout.
The linked code is a nightly only feature and it must be enabled via cargo test -- -Z --ensure-time.
I even verified that tests will still pass after sleeping for 400s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-test Proposals relating to testing.
Projects
None yet
Development

No branches or pull requests

9 participants