1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package stacktest
6
7import (
8	"testing"
9	"time"
10
11	"golang.org/x/tools/internal/stack"
12)
13
14//this is only needed to support pre 1.14 when testing.TB did not have Cleanup
15type withCleanup interface {
16	Cleanup(func())
17}
18
19// the maximum amount of time to wait for goroutines to clean themselves up.
20const maxWait = time.Second
21
22// NoLeak checks that a test (or benchmark) does not leak any goroutines.
23func NoLeak(t testing.TB) {
24	c, ok := t.(withCleanup)
25	if !ok {
26		return
27	}
28	before := stack.Capture()
29	c.Cleanup(func() {
30		var delta stack.Delta
31		start := time.Now()
32		delay := time.Millisecond
33		for {
34			after := stack.Capture()
35			delta = stack.Diff(before, after)
36			if len(delta.After) == 0 {
37				// no leaks
38				return
39			}
40			if time.Since(start) > maxWait {
41				break
42			}
43			time.Sleep(delay)
44			delay *= 2
45		}
46		// it's been long enough, and leaks are still present
47		summary := stack.Summarize(delta.After)
48		t.Errorf("goroutine leak detected:\n%+v", summary)
49	})
50}
51