--- /dev/null
+[short] skip
+
+go test -timeout=0 -run=TestNoDeadline
+go test -timeout=1m -run=TestDeadlineWithinMinute
+go test -timeout=1m -run=TestSubtestDeadlineWithinMinute
+
+-- deadline_test.go --
+package testing_test
+
+import (
+ "testing"
+ "time"
+)
+
+func TestNoDeadline(t *testing.T) {
+ d, ok := t.Deadline()
+ if ok || !d.IsZero() {
+ t.Fatalf("t.Deadline() = %v, %v; want 0, false", d, ok)
+ }
+}
+
+func TestDeadlineWithinMinute(t *testing.T) {
+ now := time.Now()
+ d, ok := t.Deadline()
+ if !ok || d.IsZero() {
+ t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok)
+ }
+ if !d.After(now) {
+ t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now)
+ }
+ if d.Sub(now) > time.Minute {
+ t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now)
+ }
+}
+
+func TestSubtestDeadlineWithinMinute(t *testing.T) {
+ t.Run("sub", func(t *testing.T) {
+ now := time.Now()
+ d, ok := t.Deadline()
+ if !ok || d.IsZero() {
+ t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok)
+ }
+ if !d.After(now) {
+ t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now)
+ }
+ if d.Sub(now) > time.Minute {
+ t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now)
+ }
+ })
+}
return !t.failed
}
+// Deadline reports the time at which the test binary will have
+// exceeded the timeout specified by the -timeout flag.
+//
+// The ok result is false if the -timeout flag indicates “no timeout” (0).
+func (t *T) Deadline() (deadline time.Time, ok bool) {
+ deadline = t.context.deadline
+ return deadline, !deadline.IsZero()
+}
+
// testContext holds all fields that are common to all tests. This includes
// synchronization primitives to run at most *parallel tests.
type testContext struct {
- match *matcher
+ match *matcher
+ deadline time.Time
mu sync.Mutex
m.before()
defer m.after()
- m.startAlarm()
+ deadline := m.startAlarm()
haveExamples = len(m.examples) > 0
- testRan, testOk := runTests(m.deps.MatchString, m.tests)
+ testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
m.stopAlarm()
if !testRan && !exampleRan && *matchBenchmarks == "" {
// RunTests is an internal function but exported because it is cross-package;
// it is part of the implementation of the "go test" command.
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
- ran, ok := runTests(matchString, tests)
+ var deadline time.Time
+ if *timeout > 0 {
+ deadline = time.Now().Add(*timeout)
+ }
+ ran, ok := runTests(matchString, tests, deadline)
if !ran && !haveExamples {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}
return ok
}
-func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ran, ok bool) {
+func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
ok = true
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
break
}
ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
+ ctx.deadline = deadline
t := &T{
common: common{
signal: make(chan bool),
}
// startAlarm starts an alarm if requested.
-func (m *M) startAlarm() {
- if *timeout > 0 {
- m.timer = time.AfterFunc(*timeout, func() {
- m.after()
- debug.SetTraceback("all")
- panic(fmt.Sprintf("test timed out after %v", *timeout))
- })
+func (m *M) startAlarm() time.Time {
+ if *timeout <= 0 {
+ return time.Time{}
}
+
+ deadline := time.Now().Add(*timeout)
+ m.timer = time.AfterFunc(*timeout, func() {
+ m.after()
+ debug.SetTraceback("all")
+ panic(fmt.Sprintf("test timed out after %v", *timeout))
+ })
+ return deadline
}
// stopAlarm turns off the alarm.