How to set the go timeout flag on "Go test"

Solution 1:

Use a valid time.ParseDuration input. For example,

$ go test -timeout 300ms

$ go test -timeout 99999s

Command go

Testing flags

-timeout t

If a test runs longer than t, panic.

Package flag

Duration flags accept any input valid for time.ParseDuration.

Package time

func ParseDuration

func ParseDuration(s string) (Duration, error)

ParseDuration parses a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".

Solution 2:

If you need this for just one test that you want to easily fail when it times out there is a neat way of just using timeout channels.

If I suspect a test will time out and I still want it to fail is to work with a timeout channel.

So imagine you have code where you suspect that some goroutines will deadlock and you want to make sure your test fails on that.

For that I run the actual test in a goroutine and the main goroutine then sits around waiting for either the done channel to finish or the timeout to finish.

func TestWithTimeOut(t *testing.T) {
    timeout := time.After(3 * time.Second)
    done := make(chan bool)
    go func() {
        // do your testing
        time.Sleep(5 * time.Second)
        done <- true
    }()

    select {
    case <-timeout:
        t.Fatal("Test didn't finish in time")
    case <-done:
    }
}

Solution 3:

To add/update to Tigraine's answer:

If you need this for just one test that you want to easily fail when it times out there is a neat way of just using timeout channels.

Actually... proposal/issue 48157 "cmd/go: add per-test timeouts", accepted and possibly released with Go 1.18 (Q1 2022) will change that.

Tests have an overall timeout for the entire binary but no timeout for a specific test case.
You often want to limit any particular test case to a time much shorter than the overall binary.

I propose to add the concept of per-test (function) timeouts to the go command user experience as follows.

  1. Each test gets a per-test timeout.
    The timer for a given test only ticks down when the test is running. It does not tick down when the test is blocked in t.Parallel, nor when it is blocked in t.Run running a subtest.

  2. The default per-test case timeout is 1m (one minute).
    If the new -testtimeout flag is specified explicitly, then that sets a different default.
    If the -testtimeout flag is omitted but -timeout is specified explicitly, then that sets the default too. This way, if you have one really long test and use go test -timeout=30m, the per-case timeout doesn't kick in after 1 minute and kill it anyway.

  3. There is a new testing.TB method SetTimeout(d time.Duration) that allows a test to set its own timeout.
    Calling SetTimeout does not reset the timer. If a test runs for 30 seconds and then calls t.SetTimeout(1*time.Second), it gets killed for having timed out. A timeout set this way is inherited by subtests. (They each have their own timer.)

When a test timeout happens, the whole process still gets killed. There's nothing we can really do about that. But the failure does say which test function timed out.

And so you now (Nov. 2021) have CL 363134, as an illulstration:

internal/fuzz: set timeout for each exec of fuzz target

This change sets a timeout of 10 seconds on each execution of the fuzz target, both during fuzzing and during minimization.