Skip to content

Commit 9ca5792

Browse files
author
Bryan C. Mills
committed
testing: testing: add (*T).Deadline method for test timeout
Fixes #28135 Change-Id: I62818595eaf4a59d8b5c26cd6848c08fec795ad1 Reviewed-on: https://go-review.googlesource.com/c/go/+/202758 Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 1b47fde commit 9ca5792

File tree

4 files changed

+91
-12
lines changed

4 files changed

+91
-12
lines changed

api/next.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pkg testing, method (*T) Deadline() (time.Time, bool)

doc/go1.15.html

+9
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ <h2 id="library">Core library</h2>
6060
TODO
6161
</p>
6262

63+
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
64+
<dd>
65+
<p><!-- golang.org/issue/28135 -->
66+
The <code>testing.T</code> type now has a <code>Deadline</code> method
67+
that reports the time at which the test binary will have exceeded its
68+
timeout.
69+
</p>
70+
</dl><!-- testing -->
71+
6372
<h3 id="minor_library_changes">Minor changes to the library</h3>
6473

6574
<p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[short] skip
2+
3+
go test -timeout=0 -run=TestNoDeadline
4+
go test -timeout=1m -run=TestDeadlineWithinMinute
5+
go test -timeout=1m -run=TestSubtestDeadlineWithinMinute
6+
7+
-- deadline_test.go --
8+
package testing_test
9+
10+
import (
11+
"testing"
12+
"time"
13+
)
14+
15+
func TestNoDeadline(t *testing.T) {
16+
d, ok := t.Deadline()
17+
if ok || !d.IsZero() {
18+
t.Fatalf("t.Deadline() = %v, %v; want 0, false", d, ok)
19+
}
20+
}
21+
22+
func TestDeadlineWithinMinute(t *testing.T) {
23+
now := time.Now()
24+
d, ok := t.Deadline()
25+
if !ok || d.IsZero() {
26+
t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok)
27+
}
28+
if !d.After(now) {
29+
t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now)
30+
}
31+
if d.Sub(now) > time.Minute {
32+
t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now)
33+
}
34+
}
35+
36+
func TestSubtestDeadlineWithinMinute(t *testing.T) {
37+
t.Run("sub", func(t *testing.T) {
38+
now := time.Now()
39+
d, ok := t.Deadline()
40+
if !ok || d.IsZero() {
41+
t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok)
42+
}
43+
if !d.After(now) {
44+
t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now)
45+
}
46+
if d.Sub(now) > time.Minute {
47+
t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now)
48+
}
49+
})
50+
}

src/testing/testing.go

+31-12
Original file line numberDiff line numberDiff line change
@@ -1049,10 +1049,20 @@ func (t *T) Run(name string, f func(t *T)) bool {
10491049
return !t.failed
10501050
}
10511051

1052+
// Deadline reports the time at which the test binary will have
1053+
// exceeded the timeout specified by the -timeout flag.
1054+
//
1055+
// The ok result is false if the -timeout flag indicates “no timeout” (0).
1056+
func (t *T) Deadline() (deadline time.Time, ok bool) {
1057+
deadline = t.context.deadline
1058+
return deadline, !deadline.IsZero()
1059+
}
1060+
10521061
// testContext holds all fields that are common to all tests. This includes
10531062
// synchronization primitives to run at most *parallel tests.
10541063
type testContext struct {
1055-
match *matcher
1064+
match *matcher
1065+
deadline time.Time
10561066

10571067
mu sync.Mutex
10581068

@@ -1195,9 +1205,9 @@ func (m *M) Run() int {
11951205

11961206
m.before()
11971207
defer m.after()
1198-
m.startAlarm()
1208+
deadline := m.startAlarm()
11991209
haveExamples = len(m.examples) > 0
1200-
testRan, testOk := runTests(m.deps.MatchString, m.tests)
1210+
testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
12011211
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
12021212
m.stopAlarm()
12031213
if !testRan && !exampleRan && *matchBenchmarks == "" {
@@ -1255,14 +1265,18 @@ func listTests(matchString func(pat, str string) (bool, error), tests []Internal
12551265
// RunTests is an internal function but exported because it is cross-package;
12561266
// it is part of the implementation of the "go test" command.
12571267
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
1258-
ran, ok := runTests(matchString, tests)
1268+
var deadline time.Time
1269+
if *timeout > 0 {
1270+
deadline = time.Now().Add(*timeout)
1271+
}
1272+
ran, ok := runTests(matchString, tests, deadline)
12591273
if !ran && !haveExamples {
12601274
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
12611275
}
12621276
return ok
12631277
}
12641278

1265-
func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ran, ok bool) {
1279+
func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
12661280
ok = true
12671281
for _, procs := range cpuList {
12681282
runtime.GOMAXPROCS(procs)
@@ -1271,6 +1285,7 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
12711285
break
12721286
}
12731287
ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
1288+
ctx.deadline = deadline
12741289
t := &T{
12751290
common: common{
12761291
signal: make(chan bool),
@@ -1452,14 +1467,18 @@ func toOutputDir(path string) string {
14521467
}
14531468

14541469
// startAlarm starts an alarm if requested.
1455-
func (m *M) startAlarm() {
1456-
if *timeout > 0 {
1457-
m.timer = time.AfterFunc(*timeout, func() {
1458-
m.after()
1459-
debug.SetTraceback("all")
1460-
panic(fmt.Sprintf("test timed out after %v", *timeout))
1461-
})
1470+
func (m *M) startAlarm() time.Time {
1471+
if *timeout <= 0 {
1472+
return time.Time{}
14621473
}
1474+
1475+
deadline := time.Now().Add(*timeout)
1476+
m.timer = time.AfterFunc(*timeout, func() {
1477+
m.after()
1478+
debug.SetTraceback("all")
1479+
panic(fmt.Sprintf("test timed out after %v", *timeout))
1480+
})
1481+
return deadline
14631482
}
14641483

14651484
// stopAlarm turns off the alarm.

0 commit comments

Comments
 (0)