1 // Copyright 2016 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.
20 // Make benchmark tests run 10x faster.
21 benchTime.d = 100 * time.Millisecond
24 func TestTestContext(t *T) {
29 // After each of the calls are applied to the context, the
31 typ int // run or done
32 // result from applying the call
37 testCases := []struct {
43 {typ: add1, running: 1, waiting: 0, started: true},
44 {typ: done, running: 0, waiting: 0, started: false},
49 {typ: add1, running: 1, waiting: 0, started: true},
50 {typ: add1, running: 1, waiting: 1, started: false},
51 {typ: done, running: 1, waiting: 0, started: true},
52 {typ: done, running: 0, waiting: 0, started: false},
53 {typ: add1, running: 1, waiting: 0, started: true},
58 {typ: add1, running: 1, waiting: 0, started: true},
59 {typ: add1, running: 2, waiting: 0, started: true},
60 {typ: add1, running: 3, waiting: 0, started: true},
61 {typ: add1, running: 3, waiting: 1, started: false},
62 {typ: add1, running: 3, waiting: 2, started: false},
63 {typ: add1, running: 3, waiting: 3, started: false},
64 {typ: done, running: 3, waiting: 2, started: true},
65 {typ: add1, running: 3, waiting: 3, started: false},
66 {typ: done, running: 3, waiting: 2, started: true},
67 {typ: done, running: 3, waiting: 1, started: true},
68 {typ: done, running: 3, waiting: 0, started: true},
69 {typ: done, running: 2, waiting: 0, started: false},
70 {typ: done, running: 1, waiting: 0, started: false},
71 {typ: done, running: 0, waiting: 0, started: false},
74 for i, tc := range testCases {
76 startParallel: make(chan bool),
79 for j, call := range tc.run {
80 doCall := func(f func()) chan bool {
81 done := make(chan bool)
91 signal := doCall(ctx.waitParallel)
95 case ctx.startParallel <- true:
99 signal := doCall(ctx.release)
102 case <-ctx.startParallel:
107 if started != call.started {
108 t.Errorf("%d:%d:started: got %v; want %v", i, j, started, call.started)
110 if ctx.running != call.running {
111 t.Errorf("%d:%d:running: got %v; want %v", i, j, ctx.running, call.running)
113 if ctx.numWaiting != call.waiting {
114 t.Errorf("%d:%d:waiting: got %v; want %v", i, j, ctx.numWaiting, call.waiting)
120 func TestTRun(t *T) {
122 testCases := []struct {
130 desc: "failnow skips future sequential and parallel tests at same level",
134 --- FAIL: failnow skips future sequential and parallel tests at same level (N.NNs)
135 --- FAIL: failnow skips future sequential and parallel tests at same level/#00 (N.NNs)
140 t.Run("", func(t *T) {
141 t.Run("par", func(t *T) {
145 t.Run("seq", func(t *T) {
149 t.Run("seq", func(t *T) {
150 realTest.Error("test must be skipped")
152 t.Run("par", func(t *T) {
154 realTest.Error("test must be skipped.")
158 realTest.Error("parallel test was not run")
161 realTest.Error("sequential test was not run")
165 desc: "failure in parallel test propagates upwards",
169 --- FAIL: failure in parallel test propagates upwards (N.NNs)
170 --- FAIL: failure in parallel test propagates upwards/#00 (N.NNs)
171 --- FAIL: failure in parallel test propagates upwards/#00/par (N.NNs)
174 t.Run("", func(t *T) {
176 t.Run("par", func(t *T) {
183 desc: "skipping without message, chatty",
187 === RUN skipping without message, chatty
188 --- SKIP: skipping without message, chatty (N.NNs)`,
189 f: func(t *T) { t.SkipNow() },
191 desc: "chatty with recursion",
195 === RUN chatty with recursion
196 === RUN chatty with recursion/#00
197 === RUN chatty with recursion/#00/#00
198 --- PASS: chatty with recursion (N.NNs)
199 --- PASS: chatty with recursion/#00 (N.NNs)
200 --- PASS: chatty with recursion/#00/#00 (N.NNs)`,
202 t.Run("", func(t *T) {
203 t.Run("", func(t *T) {})
207 desc: "skipping without message, not chatty",
209 f: func(t *T) { t.SkipNow() },
211 desc: "skipping after error",
213 --- FAIL: skipping after error (N.NNs)
214 sub_test.go:NNN: an error
215 sub_test.go:NNN: skipped`,
221 desc: "use Run to locally synchronize parallelism",
226 t.Run("waitGroup", func(t *T) {
227 for i := 0; i < 4; i++ {
228 t.Run("par", func(t *T) {
230 atomic.AddUint32(&count, 1)
235 t.Errorf("count was %d; want 4", count)
239 desc: "alternate sequential and parallel",
240 // Sequential tests should partake in the counting of running threads.
241 // Otherwise, if one runs parallel subtests in sequential tests that are
242 // itself subtests of parallel tests, the counts can get askew.
246 t.Run("a", func(t *T) {
248 t.Run("b", func(t *T) {
249 // Sequential: ensure running count is decremented.
250 t.Run("c", func(t *T) {
258 desc: "alternate sequential and parallel 2",
259 // Sequential tests should partake in the counting of running threads.
260 // Otherwise, if one runs parallel subtests in sequential tests that are
261 // itself subtests of parallel tests, the counts can get askew.
265 for i := 0; i < 2; i++ {
266 t.Run("a", func(t *T) {
268 time.Sleep(time.Nanosecond)
269 for i := 0; i < 2; i++ {
270 t.Run("b", func(t *T) {
271 time.Sleep(time.Nanosecond)
272 for i := 0; i < 2; i++ {
273 t.Run("c", func(t *T) {
275 time.Sleep(time.Nanosecond)
290 for i := 0; i < 12; i++ {
291 t.Run("a", func(t *T) {
293 time.Sleep(time.Nanosecond)
294 for i := 0; i < 12; i++ {
295 t.Run("b", func(t *T) {
296 time.Sleep(time.Nanosecond)
297 for i := 0; i < 12; i++ {
298 t.Run("c", func(t *T) {
300 time.Sleep(time.Nanosecond)
301 t.Run("d1", func(t *T) {})
302 t.Run("d2", func(t *T) {})
303 t.Run("d3", func(t *T) {})
304 t.Run("d4", func(t *T) {})
320 desc: "subtest calls error on parent",
323 --- FAIL: subtest calls error on parent (N.NNs)
324 sub_test.go:NNN: first this
325 sub_test.go:NNN: and now this!
326 sub_test.go:NNN: oh, and this too`,
329 t.Errorf("first this")
331 t.Run("", func(t *T) {
332 outer.Errorf("and now this!")
334 t.Errorf("oh, and this too")
337 desc: "subtest calls fatal on parent",
340 --- FAIL: subtest calls fatal on parent (N.NNs)
341 sub_test.go:NNN: first this
342 sub_test.go:NNN: and now this!
343 --- FAIL: subtest calls fatal on parent/#00 (N.NNs)
344 testing.go:NNN: test executed panic(nil) or runtime.Goexit: subtest may have called FailNow on a parent test`,
348 t.Errorf("first this")
349 t.Run("", func(t *T) {
350 outer.Fatalf("and now this!")
352 t.Errorf("Should not reach here.")
355 desc: "subtest calls error on ancestor",
358 --- FAIL: subtest calls error on ancestor (N.NNs)
359 sub_test.go:NNN: Report to ancestor
360 --- FAIL: subtest calls error on ancestor/#00 (N.NNs)
361 sub_test.go:NNN: Still do this
362 sub_test.go:NNN: Also do this`,
366 t.Run("", func(t *T) {
367 t.Run("", func(t *T) {
368 outer.Errorf("Report to ancestor")
370 t.Errorf("Still do this")
372 t.Errorf("Also do this")
375 desc: "subtest calls fatal on ancestor",
378 --- FAIL: subtest calls fatal on ancestor (N.NNs)
379 sub_test.go:NNN: Nope`,
383 t.Run("", func(t *T) {
384 for i := 0; i < 4; i++ {
385 t.Run("", func(t *T) {
388 t.Errorf("Don't do this")
390 t.Errorf("And neither do this")
395 desc: "panic on goroutine fail after test exit",
399 ch := make(chan bool)
400 t.Run("", func(t *T) {
404 if r := recover(); r == nil {
405 realTest.Errorf("expected panic")
409 t.Errorf("failed after success")
416 desc: "log in finished sub test logs to parent",
419 --- FAIL: log in finished sub test logs to parent (N.NNs)
420 sub_test.go:NNN: message2
421 sub_test.go:NNN: message1
422 sub_test.go:NNN: error`,
425 ch := make(chan bool)
426 t.Run("sub", func(t2 *T) {
439 // A chatty test should always log with fmt.Print, even if the
440 // parent test has completed.
441 desc: "log in finished sub test with chatty",
445 --- FAIL: log in finished sub test with chatty (N.NNs)`,
448 ch := make(chan bool)
449 t.Run("sub", func(t2 *T) {
462 // If a subtest panics we should run cleanups.
463 desc: "cleanup when subtest panics",
467 --- FAIL: cleanup when subtest panics (N.NNs)
468 --- FAIL: cleanup when subtest panics/sub (N.NNs)
469 sub_test.go:NNN: running cleanup`,
471 t.Cleanup(func() { t.Log("running cleanup") })
472 t.Run("sub", func(t2 *T) {
477 for _, tc := range testCases {
478 t.Run(tc.desc, func(t *T) {
479 ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
480 buf := &bytes.Buffer{}
483 signal: make(chan bool),
484 barrier: make(chan bool),
491 root.chatty = newChattyPrinter(root.w)
493 ok := root.Run(tc.desc, tc.f)
497 t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok)
499 if ok != !root.Failed() {
500 t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
502 if ctx.running != 0 || ctx.numWaiting != 0 {
503 t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting)
505 got := strings.TrimSpace(buf.String())
506 want := strings.TrimSpace(tc.output)
507 re := makeRegexp(want)
508 if ok, err := regexp.MatchString(re, got); !ok || err != nil {
509 t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
515 func TestBRun(t *T) {
517 for i := 0; i < b.N; i++ {
518 time.Sleep(time.Nanosecond)
521 testCases := []struct {
528 desc: "simulate sequential run of subbenchmarks.",
530 b.Run("", func(b *B) { work(b) })
531 time1 := b.result.NsPerOp()
532 b.Run("", func(b *B) { work(b) })
533 time2 := b.result.NsPerOp()
535 t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2)
539 desc: "bytes set by all benchmarks",
541 b.Run("", func(b *B) { b.SetBytes(10); work(b) })
542 b.Run("", func(b *B) { b.SetBytes(10); work(b) })
543 if b.result.Bytes != 20 {
544 t.Errorf("bytes: got: %d; want 20", b.result.Bytes)
548 desc: "bytes set by some benchmarks",
549 // In this case the bytes result is meaningless, so it must be 0.
551 b.Run("", func(b *B) { b.SetBytes(10); work(b) })
552 b.Run("", func(b *B) { work(b) })
553 b.Run("", func(b *B) { b.SetBytes(10); work(b) })
554 if b.result.Bytes != 0 {
555 t.Errorf("bytes: got: %d; want 0", b.result.Bytes)
559 desc: "failure carried over to root",
561 output: "--- FAIL: root",
562 f: func(b *B) { b.Fail() },
564 desc: "skipping without message, chatty",
566 output: "--- SKIP: root",
567 f: func(b *B) { b.SkipNow() },
569 desc: "chatty with recursion",
572 b.Run("", func(b *B) {
573 b.Run("", func(b *B) {})
577 desc: "skipping without message, not chatty",
578 f: func(b *B) { b.SkipNow() },
580 desc: "skipping after error",
584 sub_test.go:NNN: an error
585 sub_test.go:NNN: skipped`,
591 desc: "memory allocation",
594 alloc := func(b *B) {
595 var buf [bufSize]byte
596 for i := 0; i < b.N; i++ {
597 _ = append([]byte(nil), buf[:]...)
600 b.Run("", func(b *B) {
604 b.Run("", func(b *B) {
608 // runtime.MemStats sometimes reports more allocations than the
609 // benchmark is responsible for. Luckily the point of this test is
610 // to ensure that the results are not underreported, so we can
611 // simply verify the lower bound.
612 if got := b.result.MemAllocs; got < 2 {
613 t.Errorf("MemAllocs was %v; want 2", got)
615 if got := b.result.MemBytes; got < 2*bufSize {
616 t.Errorf("MemBytes was %v; want %v", got, 2*bufSize)
620 desc: "cleanup is called",
622 var calls, cleanups, innerCalls, innerCleanups int
623 b.Run("", func(b *B) {
628 b.Run("", func(b *B) {
636 if calls == 0 || calls != cleanups {
637 t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls)
639 if innerCalls == 0 || innerCalls != innerCleanups {
640 t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls)
644 desc: "cleanup is called on failure",
647 var calls, cleanups int
648 b.Run("", func(b *B) {
655 if calls == 0 || calls != cleanups {
656 t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls)
660 for _, tc := range testCases {
661 t.Run(tc.desc, func(t *T) {
663 buf := &bytes.Buffer{}
664 // This is almost like the Benchmark function, except that we override
665 // the benchtime and catch the failure result of the subbenchmark.
668 signal: make(chan bool),
672 benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
673 benchTime: durationOrCountFlag{d: 1 * time.Microsecond},
676 root.chatty = newChattyPrinter(root.w)
679 if ok != !tc.failed {
680 t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
682 if !ok != root.Failed() {
683 t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
685 // All tests are run as subtests
686 if root.result.N != 1 {
687 t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
689 got := strings.TrimSpace(buf.String())
690 want := strings.TrimSpace(tc.output)
691 re := makeRegexp(want)
692 if ok, err := regexp.MatchString(re, got); !ok || err != nil {
693 t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
699 func makeRegexp(s string) string {
700 s = regexp.QuoteMeta(s)
701 s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d\d?:`)
702 s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`)
706 func TestBenchmarkOutput(t *T) {
707 // Ensure Benchmark initialized common.w by invoking it with an error and
709 Benchmark(func(b *B) { b.Error("do not print this output") })
710 Benchmark(func(b *B) {})
713 func TestBenchmarkStartsFrom1(t *T) {
715 Benchmark(func(b *B) {
716 if first && b.N != 1 {
717 panic(fmt.Sprintf("Benchmark() first N=%v; want 1", b.N))
723 func TestBenchmarkReadMemStatsBeforeFirstRun(t *T) {
725 Benchmark(func(b *B) {
726 if first && (b.startAllocs == 0 || b.startBytes == 0) {
727 panic(fmt.Sprintf("ReadMemStats not called before first run"))
733 func TestParallelSub(t *T) {
735 block := make(chan int)
736 for i := 0; i < 10; i++ {
739 t.Run(fmt.Sprint(i), func(t *T) {})
744 for i := 0; i < 10; i++ {
749 type funcWriter struct {
750 write func([]byte) (int, error)
753 func (fw *funcWriter) Write(b []byte) (int, error) {
757 func TestRacyOutput(t *T) {
758 var runs int32 // The number of running Writes
759 var races int32 // Incremented for each race detected
760 raceDetector := func(b []byte) (int, error) {
761 // Check if some other goroutine is concurrently calling Write.
762 if atomic.LoadInt32(&runs) > 0 {
763 atomic.AddInt32(&races, 1) // Race detected!
765 atomic.AddInt32(&runs, 1)
766 defer atomic.AddInt32(&runs, -1)
767 runtime.Gosched() // Increase probability of a race
771 var wg sync.WaitGroup
773 common: common{w: &funcWriter{raceDetector}},
774 context: newTestContext(1, newMatcher(regexp.MatchString, "", "")),
776 root.chatty = newChattyPrinter(root.w)
777 root.Run("", func(t *T) {
778 for i := 0; i < 100; i++ {
782 t.Run(fmt.Sprint(i), func(t *T) {
783 t.Logf("testing run %d", i)
791 t.Errorf("detected %d racy Writes", races)
795 // The late log message did not include the test name. Issue 29388.
796 func TestLogAfterComplete(t *T) {
797 ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
801 // Use a buffered channel so that tRunner can write
802 // to it although nothing is reading from it.
803 signal: make(chan bool, 1),
809 c1 := make(chan bool)
810 c2 := make(chan string)
811 tRunner(t1, func(t *T) {
812 t.Run("TestLateLog", func(t *T) {
818 c2 <- "subtest did not panic"
823 c2 <- fmt.Sprintf("subtest panic with unexpected value %v", p)
826 const want = "Log in goroutine after TestLateLog has completed: log after test"
827 if !strings.Contains(s, want) {
828 c2 <- fmt.Sprintf("subtest panic %q does not contain %q", s, want)
833 t.Log("log after test")
839 if s := <-c2; s != "" {
844 func TestBenchmark(t *T) {
846 t.Skip("skipping in short mode")
848 res := Benchmark(func(b *B) {
849 for i := 0; i < 5; i++ {
850 b.Run("", func(b *B) {
851 for i := 0; i < b.N; i++ {
852 time.Sleep(time.Millisecond)
857 if res.NsPerOp() < 4000000 {
858 t.Errorf("want >5ms; got %v", time.Duration(res.NsPerOp()))
862 func TestCleanup(t *T) {
864 t.Run("test", func(t *T) {
865 t.Cleanup(func() { cleanups = append(cleanups, 1) })
866 t.Cleanup(func() { cleanups = append(cleanups, 2) })
868 if got, want := cleanups, []int{2, 1}; !reflect.DeepEqual(got, want) {
869 t.Errorf("unexpected cleanup record; got %v want %v", got, want)
873 func TestConcurrentCleanup(t *T) {
875 t.Run("test", func(t *T) {
876 done := make(chan struct{})
877 for i := 0; i < 2; i++ {
890 t.Errorf("unexpected cleanup; got %d want 3", cleanups)
894 func TestCleanupCalledEvenAfterGoexit(t *T) {
896 t.Run("test", func(t *T) {
905 t.Errorf("unexpected cleanup count; got %d want 1", cleanups)
909 func TestRunCleanup(t *T) {
912 t.Run("test", func(t *T) {
913 t.Cleanup(func() { outerCleanup++ })
914 t.Run("x", func(t *T) {
915 t.Cleanup(func() { innerCleanup++ })
918 if innerCleanup != 1 {
919 t.Errorf("unexpected inner cleanup count; got %d want 1", innerCleanup)
921 if outerCleanup != 1 {
922 t.Errorf("unexpected outer cleanup count; got %d want 0", outerCleanup)
926 func TestCleanupParallelSubtests(t *T) {
928 t.Run("test", func(t *T) {
929 t.Cleanup(func() { ranCleanup++ })
930 t.Run("x", func(t *T) {
933 t.Error("outer cleanup ran before parallel subtest")
938 t.Errorf("unexpected cleanup count; got %d want 1", ranCleanup)
942 func TestNestedCleanup(t *T) {
944 t.Run("test", func(t *T) {
947 t.Errorf("unexpected cleanup count in first cleanup: got %d want 2", ranCleanup)
953 t.Errorf("unexpected cleanup count in second cleanup: got %d want 0", ranCleanup)
958 t.Errorf("unexpected cleanup count in nested cleanup: got %d want 1", ranCleanup)
965 t.Errorf("unexpected cleanup count: got %d want 3", ranCleanup)