Skip to content

Latest commit

 

History

History
84 lines (66 loc) · 2.19 KB

File metadata and controls

84 lines (66 loc) · 2.19 KB

paralleltestctx

A Go static analysis tool that warns when contexts with a deadline are used in parallel subtests.

Problem

See our blog post for an in-depth explanation of the problem.

Usage

go run github.com/coder/paralleltestctx/cmd/paralleltestctx@latest ./...

Custom functions that produce contexts with timeouts

By default, the linter detects context.WithTimeout and context.WithDeadline as producing contexts with timeouts or deadlines. Additional functions that create a context with a deadline or timeout can be specified using the -custom-funcs flag.

go run github.com/coder/paralleltestctx/cmd/paralleltestctx@latest -custom-funcs="testutil.Context" ./...

Examples

❌ Potentially flakey test

func TestBad(t *testing.T) {
   ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   defer cancel()
   // WARNING: do not do this!
   t.Parallel()

   uut := newUnitUnderTest()
   // Danger! Context may have timed out by this point
   writeCtx(ctx, t, uut.Input, 5)
   output := readCtx(ctx, t, uut.Output)
   if output != 25 {
      t.Errorf("expected 25 got %d", output)
   }
}

❌ Potentially flakey parallel subtest

func TestBad(t *testing.T) {
    t.Parallel()
    ctx, cancel := context.WithTimeout(context.Background(), time.Second * 5)
    t.Cleanup(cancel)
    t.Run("sub", func(t *testing.T) {
        t.Parallel()
        // Danger! Context may have timed out by this point
        doSomething(ctx) // Warning: timeout context used after t.Parallel call
    })
}

✅ Fixed test - create a new context

func TestGood(t *testing.T) {
    t.Parallel()
    ctx, cancel := context.WithTimeout(context.Background(), time.Second * 5)
    t.Cleanup(cancel)
    t.Run("sub", func(t *testing.T) {
        t.Parallel()
        // We're shadowing the parent context with a new deadline, so this is fine
        ctx, cancel := context.WithTimeout(context.Background(), time.Second * 5)
        t.Cleanup(cancel)
        doSomething(ctx)
    })
}

License

This project is licensed under the MIT License - see the LICENSE file for details.