Source file
src/testing/testing_test.go
1
2
3
4
5 package testing_test
6
7 import (
8 "bytes"
9 "context"
10 "errors"
11 "fmt"
12 "internal/race"
13 "internal/testenv"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "regexp"
18 "runtime"
19 "slices"
20 "strings"
21 "sync"
22 "testing"
23 "time"
24 )
25
26
27
28
29
30 func TestMain(m *testing.M) {
31 if os.Getenv("GO_WANT_RACE_BEFORE_TESTS") == "1" {
32 doRace()
33 }
34
35 m.Run()
36
37
38
39
40
41
42
43
44
45
46
47 }
48
49 func TestTempDirInCleanup(t *testing.T) {
50 var dir string
51
52 t.Run("test", func(t *testing.T) {
53 t.Cleanup(func() {
54 dir = t.TempDir()
55 })
56 _ = t.TempDir()
57 })
58
59 fi, err := os.Stat(dir)
60 if fi != nil {
61 t.Fatalf("Directory %q from user Cleanup still exists", dir)
62 }
63 if !os.IsNotExist(err) {
64 t.Fatalf("Unexpected error: %v", err)
65 }
66 }
67
68 func TestTempDirInBenchmark(t *testing.T) {
69 testing.Benchmark(func(b *testing.B) {
70 if !b.Run("test", func(b *testing.B) {
71
72 for i := 0; i < b.N; i++ {
73 _ = b.TempDir()
74 }
75 }) {
76 t.Fatal("Sub test failure in a benchmark")
77 }
78 })
79 }
80
81 func TestTempDir(t *testing.T) {
82 testTempDir(t)
83 t.Run("InSubtest", testTempDir)
84 t.Run("test/subtest", testTempDir)
85 t.Run("test\\subtest", testTempDir)
86 t.Run("test:subtest", testTempDir)
87 t.Run("test/..", testTempDir)
88 t.Run("../test", testTempDir)
89 t.Run("test[]", testTempDir)
90 t.Run("test*", testTempDir)
91 t.Run("äöüéè", testTempDir)
92 t.Run(strings.Repeat("a", 300), testTempDir)
93 }
94
95 func testTempDir(t *testing.T) {
96 dirCh := make(chan string, 1)
97 t.Cleanup(func() {
98
99 select {
100 case dir := <-dirCh:
101 fi, err := os.Stat(dir)
102 if os.IsNotExist(err) {
103
104 return
105 }
106 if err != nil {
107 t.Fatal(err)
108 }
109 t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir())
110 default:
111 if !t.Failed() {
112 t.Fatal("never received dir channel")
113 }
114 }
115 })
116
117 dir := t.TempDir()
118 if dir == "" {
119 t.Fatal("expected dir")
120 }
121 dir2 := t.TempDir()
122 if dir == dir2 {
123 t.Fatal("subsequent calls to TempDir returned the same directory")
124 }
125 if filepath.Dir(dir) != filepath.Dir(dir2) {
126 t.Fatalf("calls to TempDir do not share a parent; got %q, %q", dir, dir2)
127 }
128 dirCh <- dir
129 fi, err := os.Stat(dir)
130 if err != nil {
131 t.Fatal(err)
132 }
133 if !fi.IsDir() {
134 t.Errorf("dir %q is not a dir", dir)
135 }
136 files, err := os.ReadDir(dir)
137 if err != nil {
138 t.Fatal(err)
139 }
140 if len(files) > 0 {
141 t.Errorf("unexpected %d files in TempDir: %v", len(files), files)
142 }
143
144 glob := filepath.Join(dir, "*.txt")
145 if _, err := filepath.Glob(glob); err != nil {
146 t.Error(err)
147 }
148 }
149
150 func TestTempDirGOTMPDIR(t *testing.T) {
151
152
153
154
155
156
157 customTmpDir := filepath.Join(os.TempDir(), "custom-gotmpdir-test")
158 if err := os.MkdirAll(customTmpDir, 0777); err != nil {
159 t.Fatal(err)
160 }
161 defer os.RemoveAll(customTmpDir)
162
163 t.Setenv("GOTMPDIR", customTmpDir)
164
165 dir := t.TempDir()
166 if dir == "" {
167 t.Fatal("expected dir")
168 }
169
170 if !strings.HasPrefix(dir, customTmpDir) {
171 t.Errorf("TempDir did not use GOTMPDIR: got %q, want prefix %q", dir, customTmpDir)
172 }
173
174 fi, err := os.Stat(dir)
175 if err != nil {
176 t.Fatal(err)
177 }
178 if !fi.IsDir() {
179 t.Errorf("dir %q is not a dir", dir)
180 }
181 }
182
183 func TestSetenv(t *testing.T) {
184 tests := []struct {
185 name string
186 key string
187 initialValueExists bool
188 initialValue string
189 newValue string
190 }{
191 {
192 name: "initial value exists",
193 key: "GO_TEST_KEY_1",
194 initialValueExists: true,
195 initialValue: "111",
196 newValue: "222",
197 },
198 {
199 name: "initial value exists but empty",
200 key: "GO_TEST_KEY_2",
201 initialValueExists: true,
202 initialValue: "",
203 newValue: "222",
204 },
205 {
206 name: "initial value is not exists",
207 key: "GO_TEST_KEY_3",
208 initialValueExists: false,
209 initialValue: "",
210 newValue: "222",
211 },
212 }
213
214 for _, test := range tests {
215 if test.initialValueExists {
216 if err := os.Setenv(test.key, test.initialValue); err != nil {
217 t.Fatalf("unable to set env: got %v", err)
218 }
219 } else {
220 os.Unsetenv(test.key)
221 }
222
223 t.Run(test.name, func(t *testing.T) {
224 t.Setenv(test.key, test.newValue)
225 if os.Getenv(test.key) != test.newValue {
226 t.Fatalf("unexpected value after t.Setenv: got %s, want %s", os.Getenv(test.key), test.newValue)
227 }
228 })
229
230 got, exists := os.LookupEnv(test.key)
231 if got != test.initialValue {
232 t.Fatalf("unexpected value after t.Setenv cleanup: got %s, want %s", got, test.initialValue)
233 }
234 if exists != test.initialValueExists {
235 t.Fatalf("unexpected value after t.Setenv cleanup: got %t, want %t", exists, test.initialValueExists)
236 }
237 }
238 }
239
240 func expectParallelConflict(t *testing.T) {
241 want := testing.ParallelConflict
242 if got := recover(); got != want {
243 t.Fatalf("expected panic; got %#v want %q", got, want)
244 }
245 }
246
247 func testWithParallelAfter(t *testing.T, fn func(*testing.T)) {
248 defer expectParallelConflict(t)
249
250 fn(t)
251 t.Parallel()
252 }
253
254 func testWithParallelBefore(t *testing.T, fn func(*testing.T)) {
255 defer expectParallelConflict(t)
256
257 t.Parallel()
258 fn(t)
259 }
260
261 func testWithParallelParentBefore(t *testing.T, fn func(*testing.T)) {
262 t.Parallel()
263
264 t.Run("child", func(t *testing.T) {
265 defer expectParallelConflict(t)
266
267 fn(t)
268 })
269 }
270
271 func testWithParallelGrandParentBefore(t *testing.T, fn func(*testing.T)) {
272 t.Parallel()
273
274 t.Run("child", func(t *testing.T) {
275 t.Run("grand-child", func(t *testing.T) {
276 defer expectParallelConflict(t)
277
278 fn(t)
279 })
280 })
281 }
282
283 func tSetenv(t *testing.T) {
284 t.Setenv("GO_TEST_KEY_1", "value")
285 }
286
287 func TestSetenvWithParallelAfter(t *testing.T) {
288 testWithParallelAfter(t, tSetenv)
289 }
290
291 func TestSetenvWithParallelBefore(t *testing.T) {
292 testWithParallelBefore(t, tSetenv)
293 }
294
295 func TestSetenvWithParallelParentBefore(t *testing.T) {
296 testWithParallelParentBefore(t, tSetenv)
297 }
298
299 func TestSetenvWithParallelGrandParentBefore(t *testing.T) {
300 testWithParallelGrandParentBefore(t, tSetenv)
301 }
302
303 func tChdir(t *testing.T) {
304 t.Chdir(t.TempDir())
305 }
306
307 func TestChdirWithParallelAfter(t *testing.T) {
308 testWithParallelAfter(t, tChdir)
309 }
310
311 func TestChdirWithParallelBefore(t *testing.T) {
312 testWithParallelBefore(t, tChdir)
313 }
314
315 func TestChdirWithParallelParentBefore(t *testing.T) {
316 testWithParallelParentBefore(t, tChdir)
317 }
318
319 func TestChdirWithParallelGrandParentBefore(t *testing.T) {
320 testWithParallelGrandParentBefore(t, tChdir)
321 }
322
323 func TestChdir(t *testing.T) {
324 oldDir, err := os.Getwd()
325 if err != nil {
326 t.Fatal(err)
327 }
328 defer os.Chdir(oldDir)
329
330
331 tmp, err := filepath.EvalSymlinks(t.TempDir())
332 if err != nil {
333 t.Fatal(err)
334 }
335 rel, err := filepath.Rel(oldDir, tmp)
336 if err != nil {
337
338
339 rel = "skip"
340 }
341
342 for _, tc := range []struct {
343 name, dir, pwd string
344 extraChdir bool
345 }{
346 {
347 name: "absolute",
348 dir: tmp,
349 pwd: tmp,
350 },
351 {
352 name: "relative",
353 dir: rel,
354 pwd: tmp,
355 },
356 {
357 name: "current (absolute)",
358 dir: oldDir,
359 pwd: oldDir,
360 },
361 {
362 name: "current (relative) with extra os.Chdir",
363 dir: ".",
364 pwd: oldDir,
365
366 extraChdir: true,
367 },
368 } {
369 t.Run(tc.name, func(t *testing.T) {
370 if tc.dir == "skip" {
371 t.Skipf("skipping test because there is no relative path between %s and %s", oldDir, tmp)
372 }
373 if !filepath.IsAbs(tc.pwd) {
374 t.Fatalf("Bad tc.pwd: %q (must be absolute)", tc.pwd)
375 }
376
377 t.Chdir(tc.dir)
378
379 newDir, err := os.Getwd()
380 if err != nil {
381 t.Fatal(err)
382 }
383 if newDir != tc.pwd {
384 t.Fatalf("failed to chdir to %q: getwd: got %q, want %q", tc.dir, newDir, tc.pwd)
385 }
386
387 switch runtime.GOOS {
388 case "windows", "plan9":
389
390 default:
391 if pwd := os.Getenv("PWD"); pwd != tc.pwd {
392 t.Fatalf("PWD: got %q, want %q", pwd, tc.pwd)
393 }
394 }
395
396 if tc.extraChdir {
397 os.Chdir("..")
398 }
399 })
400
401 newDir, err := os.Getwd()
402 if err != nil {
403 t.Fatal(err)
404 }
405 if newDir != oldDir {
406 t.Fatalf("failed to restore wd to %s: getwd: %s", oldDir, newDir)
407 }
408 }
409 }
410
411
412 var testingTrueInInit = false
413
414
415 var testingTrueInPackageVarInit = testing.Testing()
416
417
418 func init() {
419 if testing.Testing() {
420 testingTrueInInit = true
421 }
422 }
423
424 var testingProg = `
425 package main
426
427 import (
428 "fmt"
429 "testing"
430 )
431
432 func main() {
433 fmt.Println(testing.Testing())
434 }
435 `
436
437 func TestTesting(t *testing.T) {
438 if !testing.Testing() {
439 t.Errorf("testing.Testing() == %t, want %t", testing.Testing(), true)
440 }
441 if !testingTrueInInit {
442 t.Errorf("testing.Testing() called by init function == %t, want %t", testingTrueInInit, true)
443 }
444 if !testingTrueInPackageVarInit {
445 t.Errorf("testing.Testing() variable initialized as %t, want %t", testingTrueInPackageVarInit, true)
446 }
447
448 if testing.Short() {
449 t.Skip("skipping building a binary in short mode")
450 }
451 testenv.MustHaveGoRun(t)
452
453 fn := filepath.Join(t.TempDir(), "x.go")
454 if err := os.WriteFile(fn, []byte(testingProg), 0644); err != nil {
455 t.Fatal(err)
456 }
457
458 cmd := testenv.Command(t, testenv.GoToolPath(t), "run", fn)
459 out, err := cmd.CombinedOutput()
460 if err != nil {
461 t.Fatalf("%v failed: %v\n%s", cmd, err, out)
462 }
463
464 s := string(bytes.TrimSpace(out))
465 if s != "false" {
466 t.Errorf("in non-test testing.Test() returned %q, want %q", s, "false")
467 }
468 }
469
470
471
472 func runTest(t *testing.T, test string, args ...string) []byte {
473 t.Helper()
474
475 testenv.MustHaveExec(t)
476
477 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+test+"$", "-test.bench="+test, "-test.v", "-test.parallel=2", "-test.benchtime=2x")
478 cmd = testenv.CleanCmdEnv(cmd)
479 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
480 cmd.Args = append(cmd.Args, args...)
481 out, err := cmd.CombinedOutput()
482 t.Logf("%v: %v\n%s", cmd, err, out)
483
484 return out
485 }
486
487
488
489 func doRace() {
490 var x int
491 c1 := make(chan bool)
492 go func() {
493 x = 1
494 c1 <- true
495 }()
496 _ = x
497 <-c1
498 }
499
500 func TestRaceReports(t *testing.T) {
501 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
502
503 t.Run("Sub", func(t *testing.T) {
504 doRace()
505 })
506 return
507 }
508
509 out := runTest(t, "TestRaceReports")
510
511
512 c := bytes.Count(out, []byte("race detected"))
513 want := 0
514 if race.Enabled {
515 want = 1
516 }
517 if c != want {
518 t.Errorf("got %d race reports, want %d", c, want)
519 }
520 }
521
522
523 func TestRaceName(t *testing.T) {
524 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
525 doRace()
526 return
527 }
528
529 out := runTest(t, "TestRaceName")
530
531 if regexp.MustCompile(`=== NAME\s*$`).Match(out) {
532 t.Errorf("incorrectly reported test with no name")
533 }
534 }
535
536 func TestRaceSubReports(t *testing.T) {
537 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
538 t.Parallel()
539 c1 := make(chan bool, 1)
540 t.Run("sub", func(t *testing.T) {
541 t.Run("subsub1", func(t *testing.T) {
542 t.Parallel()
543 doRace()
544 c1 <- true
545 })
546 t.Run("subsub2", func(t *testing.T) {
547 t.Parallel()
548 doRace()
549 <-c1
550 })
551 })
552 doRace()
553 return
554 }
555
556 out := runTest(t, "TestRaceSubReports")
557
558
559
560
561
562 cReport := bytes.Count(out, []byte("race detected during execution of test"))
563 wantReport := 0
564 if race.Enabled {
565 wantReport = 3
566 }
567 if cReport != wantReport {
568 t.Errorf("got %d race reports, want %d", cReport, wantReport)
569 }
570
571
572
573 cFail := bytes.Count(out, []byte("--- FAIL:"))
574 wantFail := 0
575 if race.Enabled {
576 wantFail = 4
577 }
578 if cFail != wantFail {
579 t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport)
580 }
581 }
582
583 func TestRaceInCleanup(t *testing.T) {
584 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
585 t.Cleanup(doRace)
586 t.Parallel()
587 t.Run("sub", func(t *testing.T) {
588 t.Parallel()
589
590 })
591 return
592 }
593
594 out := runTest(t, "TestRaceInCleanup")
595
596
597 cReport := bytes.Count(out, []byte("race detected during execution of test"))
598 wantReport := 0
599 if race.Enabled {
600 wantReport = 1
601 }
602 if cReport != wantReport {
603 t.Errorf("got %d race reports, want %d", cReport, wantReport)
604 }
605
606
607
608 cFail := bytes.Count(out, []byte("--- FAIL:"))
609 wantFail := 0
610 if race.Enabled {
611 wantFail = 1
612 }
613 if cFail != wantFail {
614 t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport)
615 }
616 }
617
618 func TestDeepSubtestRace(t *testing.T) {
619 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
620 t.Run("sub", func(t *testing.T) {
621 t.Run("subsub", func(t *testing.T) {
622 t.Run("subsubsub", func(t *testing.T) {
623 doRace()
624 })
625 })
626 doRace()
627 })
628 return
629 }
630
631 out := runTest(t, "TestDeepSubtestRace")
632
633 c := bytes.Count(out, []byte("race detected during execution of test"))
634 want := 0
635
636 if race.Enabled {
637 want = 2
638 }
639 if c != want {
640 t.Errorf("got %d race reports, want %d", c, want)
641 }
642 }
643
644 func TestRaceDuringParallelFailsAllSubtests(t *testing.T) {
645 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
646 var ready sync.WaitGroup
647 ready.Add(2)
648 done := make(chan struct{})
649 go func() {
650 ready.Wait()
651 doRace()
652 close(done)
653 }()
654
655 t.Run("sub", func(t *testing.T) {
656 t.Run("subsub1", func(t *testing.T) {
657 t.Parallel()
658 ready.Done()
659 <-done
660 })
661 t.Run("subsub2", func(t *testing.T) {
662 t.Parallel()
663 ready.Done()
664 <-done
665 })
666 })
667
668 return
669 }
670
671 out := runTest(t, "TestRaceDuringParallelFailsAllSubtests")
672
673 c := bytes.Count(out, []byte("race detected during execution of test"))
674 want := 0
675
676 if race.Enabled {
677 want = 2
678 }
679 if c != want {
680 t.Errorf("got %d race reports, want %d", c, want)
681 }
682 }
683
684 func TestRaceBeforeParallel(t *testing.T) {
685 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
686 t.Run("sub", func(t *testing.T) {
687 doRace()
688 t.Parallel()
689 })
690 return
691 }
692
693 out := runTest(t, "TestRaceBeforeParallel")
694
695 c := bytes.Count(out, []byte("race detected during execution of test"))
696 want := 0
697
698 if race.Enabled {
699 want = 1
700 }
701 if c != want {
702 t.Errorf("got %d race reports, want %d", c, want)
703 }
704 }
705
706 func TestRaceBeforeTests(t *testing.T) {
707 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^$")
708 cmd = testenv.CleanCmdEnv(cmd)
709 cmd.Env = append(cmd.Env, "GO_WANT_RACE_BEFORE_TESTS=1")
710 out, _ := cmd.CombinedOutput()
711 t.Logf("%s", out)
712
713 c := bytes.Count(out, []byte("race detected outside of test execution"))
714
715 want := 0
716 if race.Enabled {
717 want = 1
718 }
719 if c != want {
720 t.Errorf("got %d race reports; want %d", c, want)
721 }
722 }
723
724 func TestBenchmarkRace(t *testing.T) {
725 out := runTest(t, "BenchmarkRacy")
726 c := bytes.Count(out, []byte("race detected during execution of test"))
727
728 want := 0
729
730 if race.Enabled {
731 want = 1
732 }
733 if c != want {
734 t.Errorf("got %d race reports; want %d", c, want)
735 }
736 }
737
738 func TestBenchmarkRaceBLoop(t *testing.T) {
739 out := runTest(t, "BenchmarkBLoopRacy")
740 c := bytes.Count(out, []byte("race detected during execution of test"))
741
742 want := 0
743
744 if race.Enabled {
745 want = 1
746 }
747 if c != want {
748 t.Errorf("got %d race reports; want %d", c, want)
749 }
750 }
751
752 func BenchmarkRacy(b *testing.B) {
753 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
754 b.Skipf("skipping intentionally-racy benchmark")
755 }
756 for i := 0; i < b.N; i++ {
757 doRace()
758 }
759 }
760
761 func BenchmarkBLoopRacy(b *testing.B) {
762 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
763 b.Skipf("skipping intentionally-racy benchmark")
764 }
765 for b.Loop() {
766 doRace()
767 }
768 }
769
770 func TestBenchmarkSubRace(t *testing.T) {
771 out := runTest(t, "BenchmarkSubRacy")
772 c := bytes.Count(out, []byte("race detected during execution of test"))
773
774 want := 0
775
776
777
778 if race.Enabled {
779 want = 3
780 }
781 if c != want {
782 t.Errorf("got %d race reports; want %d", c, want)
783 }
784 }
785
786 func BenchmarkSubRacy(b *testing.B) {
787 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
788 b.Skipf("skipping intentionally-racy benchmark")
789 }
790
791 b.Run("non-racy", func(b *testing.B) {
792 tot := 0
793 for i := 0; i < b.N; i++ {
794 tot++
795 }
796 _ = tot
797 })
798
799 b.Run("racy", func(b *testing.B) {
800 for i := 0; i < b.N; i++ {
801 doRace()
802 }
803 })
804
805 b.Run("racy-bLoop", func(b *testing.B) {
806 for b.Loop() {
807 doRace()
808 }
809 })
810
811 doRace()
812 }
813
814 func TestRunningTests(t *testing.T) {
815 t.Parallel()
816
817
818
819
820
821 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
822 for i := 0; i < 2; i++ {
823 t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) {
824 t.Parallel()
825 for j := 0; j < 2; j++ {
826 t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) {
827 t.Parallel()
828 for {
829 time.Sleep(1 * time.Millisecond)
830 }
831 })
832 }
833 })
834 }
835 }
836
837 timeout := 10 * time.Millisecond
838 for {
839 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String(), "-test.parallel=4")
840 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
841 out, err := cmd.CombinedOutput()
842 t.Logf("%v:\n%s", cmd, out)
843 if _, ok := err.(*exec.ExitError); !ok {
844 t.Fatal(err)
845 }
846
847
848
849
850
851 want := []string{
852 "TestRunningTests/outer0/inner0",
853 "TestRunningTests/outer0/inner1",
854 "TestRunningTests/outer1/inner0",
855 "TestRunningTests/outer1/inner1",
856 }
857
858 got, ok := parseRunningTests(out)
859 if slices.Equal(got, want) {
860 break
861 }
862 if ok {
863 t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n"))
864 } else {
865 t.Logf("no running tests found")
866 }
867 t.Logf("retrying with longer timeout")
868 timeout *= 2
869 }
870 }
871
872 func TestRunningTestsInCleanup(t *testing.T) {
873 t.Parallel()
874
875 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
876 for i := 0; i < 2; i++ {
877 t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) {
878
879
880
881 t.Cleanup(func() {
882 for {
883 time.Sleep(1 * time.Millisecond)
884 }
885 })
886
887 for j := 0; j < 2; j++ {
888 t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) {
889 t.Parallel()
890 })
891 }
892 })
893 }
894 }
895
896 timeout := 10 * time.Millisecond
897 for {
898 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String())
899 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
900 out, err := cmd.CombinedOutput()
901 t.Logf("%v:\n%s", cmd, out)
902 if _, ok := err.(*exec.ExitError); !ok {
903 t.Fatal(err)
904 }
905
906
907
908
909
910
911 want := []string{
912 "TestRunningTestsInCleanup",
913 "TestRunningTestsInCleanup/outer0",
914 }
915
916 got, ok := parseRunningTests(out)
917 if slices.Equal(got, want) {
918 break
919 }
920 if ok {
921 t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n"))
922 } else {
923 t.Logf("no running tests found")
924 }
925 t.Logf("retrying with longer timeout")
926 timeout *= 2
927 }
928 }
929
930 func parseRunningTests(out []byte) (runningTests []string, ok bool) {
931 inRunningTests := false
932 for line := range strings.SplitSeq(string(out), "\n") {
933 if inRunningTests {
934
935 if trimmed, ok := strings.CutPrefix(line, "\t\t"); ok {
936 if name, _, ok := strings.Cut(trimmed, " "); ok {
937 runningTests = append(runningTests, name)
938 continue
939 }
940 }
941
942
943 return runningTests, true
944 }
945
946 if strings.TrimSpace(line) == "running tests:" {
947 inRunningTests = true
948 }
949 }
950
951 return nil, false
952 }
953
954 func TestConcurrentRun(t *testing.T) {
955
956
957
958 block := make(chan struct{})
959 var ready, done sync.WaitGroup
960 for i := 0; i < 2; i++ {
961 ready.Add(1)
962 done.Add(1)
963 go t.Run("", func(*testing.T) {
964 ready.Done()
965 <-block
966 done.Done()
967 })
968 }
969 ready.Wait()
970 close(block)
971 done.Wait()
972 }
973
974 func TestParentRun(t1 *testing.T) {
975
976
977
978 t1.Run("outer", func(t2 *testing.T) {
979 t2.Log("Hello outer!")
980 t1.Run("not_inner", func(t3 *testing.T) {
981 t3.Log("Hello inner!")
982 })
983 })
984 }
985
986 func TestContext(t *testing.T) {
987 ctx := t.Context()
988 if err := ctx.Err(); err != nil {
989 t.Fatalf("expected non-canceled context, got %v", err)
990 }
991
992 var innerCtx context.Context
993 t.Run("inner", func(t *testing.T) {
994 innerCtx = t.Context()
995 if err := innerCtx.Err(); err != nil {
996 t.Fatalf("expected inner test to not inherit canceled context, got %v", err)
997 }
998 })
999 t.Run("inner2", func(t *testing.T) {
1000 if !errors.Is(innerCtx.Err(), context.Canceled) {
1001 t.Fatal("expected context of sibling test to be canceled after its test function finished")
1002 }
1003 })
1004
1005 t.Cleanup(func() {
1006 if !errors.Is(ctx.Err(), context.Canceled) {
1007 t.Fatal("expected context canceled before cleanup")
1008 }
1009 })
1010 }
1011
1012
1013
1014 func TestAttrExample(t *testing.T) {
1015 t.Attr("key", "value")
1016 }
1017
1018 func TestAttrSet(t *testing.T) {
1019 out := string(runTest(t, "TestAttrExample"))
1020
1021 want := "=== ATTR TestAttrExample key value\n"
1022 if !strings.Contains(out, want) {
1023 t.Errorf("expected output containing %q, got:\n%q", want, out)
1024 }
1025 }
1026
1027 func TestAttrInvalid(t *testing.T) {
1028 tests := []struct {
1029 key string
1030 value string
1031 }{
1032 {"k ey", "value"},
1033 {"k\tey", "value"},
1034 {"k\rey", "value"},
1035 {"k\ney", "value"},
1036 {"key", "val\rue"},
1037 {"key", "val\nue"},
1038 }
1039
1040 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
1041 for i, test := range tests {
1042 t.Run(fmt.Sprint(i), func(t *testing.T) {
1043 t.Attr(test.key, test.value)
1044 })
1045 }
1046 return
1047 }
1048
1049 out := string(runTest(t, "TestAttrInvalid"))
1050
1051 for i := range tests {
1052 want := fmt.Sprintf("--- FAIL: TestAttrInvalid/%v ", i)
1053 if !strings.Contains(out, want) {
1054 t.Errorf("expected output containing %q, got:\n%q", want, out)
1055 }
1056 }
1057 }
1058
1059 const artifactContent = "It belongs in a museum.\n"
1060
1061 func TestArtifactDirExample(t *testing.T) {
1062 os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
1063 }
1064
1065 func TestArtifactDirDefault(t *testing.T) {
1066 tempDir := t.TempDir()
1067 t.Chdir(tempDir)
1068 out := runTest(t, "TestArtifactDirExample", "-test.artifacts")
1069 checkArtifactDir(t, out, "TestArtifactDirExample", tempDir)
1070 }
1071
1072 func TestArtifactDirSpecified(t *testing.T) {
1073 tempDir := t.TempDir()
1074 out := runTest(t, "TestArtifactDirExample", "-test.artifacts", "-test.outputdir="+tempDir)
1075 checkArtifactDir(t, out, "TestArtifactDirExample", tempDir)
1076 }
1077
1078 func TestArtifactDirNoArtifacts(t *testing.T) {
1079 t.Chdir(t.TempDir())
1080 out := string(runTest(t, "TestArtifactDirExample"))
1081 if strings.Contains(out, "=== ARTIFACTS") {
1082 t.Errorf("expected output with no === ARTIFACTS, got\n%q", out)
1083 }
1084 ents, err := os.ReadDir(".")
1085 if err != nil {
1086 t.Fatal(err)
1087 }
1088 for _, e := range ents {
1089 t.Errorf("unexpected file in current directory after test: %v", e.Name())
1090 }
1091 }
1092
1093 func TestArtifactDirSubtestExample(t *testing.T) {
1094 t.Run("Subtest", func(t *testing.T) {
1095 os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
1096 })
1097 }
1098
1099 func TestArtifactDirInSubtest(t *testing.T) {
1100 tempDir := t.TempDir()
1101 out := runTest(t, "TestArtifactDirSubtestExample/Subtest", "-test.artifacts", "-test.outputdir="+tempDir)
1102 checkArtifactDir(t, out, "TestArtifactDirSubtestExample/Subtest", tempDir)
1103 }
1104
1105 func TestArtifactDirLongTestNameExample(t *testing.T) {
1106 name := strings.Repeat("x", 256)
1107 t.Run(name, func(t *testing.T) {
1108 os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
1109 })
1110 }
1111
1112 func TestArtifactDirWithLongTestName(t *testing.T) {
1113 tempDir := t.TempDir()
1114 out := runTest(t, "TestArtifactDirLongTestNameExample", "-test.artifacts", "-test.outputdir="+tempDir)
1115 checkArtifactDir(t, out, `TestArtifactDirLongTestNameExample/\w+`, tempDir)
1116 }
1117
1118 func TestArtifactDirConsistent(t *testing.T) {
1119 a := t.ArtifactDir()
1120 b := t.ArtifactDir()
1121 if a != b {
1122 t.Errorf("t.ArtifactDir is not consistent between calls: %q, %q", a, b)
1123 }
1124 }
1125
1126 func checkArtifactDir(t *testing.T, out []byte, testName, outputDir string) {
1127 t.Helper()
1128
1129 re := regexp.MustCompile(`=== ARTIFACTS ` + testName + ` ([^\n]+)`)
1130 match := re.FindSubmatch(out)
1131 if match == nil {
1132 t.Fatalf("expected output matching %q, got\n%q", re, out)
1133 }
1134 artifactDir := string(match[1])
1135
1136
1137 relDir, err := filepath.Rel(outputDir, artifactDir)
1138 if err != nil {
1139 t.Fatal(err)
1140 }
1141 if !filepath.IsLocal(relDir) {
1142 t.Fatalf("want artifact directory contained in %q, got %q", outputDir, artifactDir)
1143 }
1144
1145 for _, part := range strings.Split(relDir, string(os.PathSeparator)) {
1146 const maxSize = 64
1147 if len(part) > maxSize {
1148 t.Errorf("artifact directory %q contains component >%v characters long: %q", relDir, maxSize, part)
1149 }
1150 }
1151
1152 got, err := os.ReadFile(filepath.Join(artifactDir, "artifact"))
1153 if err != nil || string(got) != artifactContent {
1154 t.Errorf("reading artifact in %q: got %q, %v; want %q", artifactDir, got, err, artifactContent)
1155 }
1156 }
1157
1158 func TestBenchmarkBLoopIterationCorrect(t *testing.T) {
1159 out := runTest(t, "BenchmarkBLoopPrint")
1160 c := bytes.Count(out, []byte("Printing from BenchmarkBLoopPrint"))
1161
1162 want := 2
1163 if c != want {
1164 t.Errorf("got %d loop iterations; want %d", c, want)
1165 }
1166
1167
1168 c = bytes.Count(out, []byte("Ramping up from BenchmarkBLoopPrint"))
1169 want = 1
1170 if c != want {
1171 t.Errorf("got %d loop rampup; want %d", c, want)
1172 }
1173
1174 re := regexp.MustCompile(`BenchmarkBLoopPrint(-[0-9]+)?\s+2\s+[0-9]+\s+ns/op`)
1175 if !re.Match(out) {
1176 t.Error("missing benchmark output")
1177 }
1178 }
1179
1180 func TestBenchmarkBNIterationCorrect(t *testing.T) {
1181 out := runTest(t, "BenchmarkBNPrint")
1182 c := bytes.Count(out, []byte("Printing from BenchmarkBNPrint"))
1183
1184
1185
1186 want := 3
1187 if c != want {
1188 t.Errorf("got %d loop iterations; want %d", c, want)
1189 }
1190
1191
1192
1193 c = bytes.Count(out, []byte("Ramping up from BenchmarkBNPrint"))
1194 want = 2
1195 if c != want {
1196 t.Errorf("got %d loop rampup; want %d", c, want)
1197 }
1198 }
1199
1200 func BenchmarkBLoopPrint(b *testing.B) {
1201 b.Logf("Ramping up from BenchmarkBLoopPrint")
1202 for b.Loop() {
1203 b.Logf("Printing from BenchmarkBLoopPrint")
1204 }
1205 }
1206
1207 func BenchmarkBNPrint(b *testing.B) {
1208 b.Logf("Ramping up from BenchmarkBNPrint")
1209 for i := 0; i < b.N; i++ {
1210 b.Logf("Printing from BenchmarkBNPrint")
1211 }
1212 }
1213
1214 func TestArtifactDir(t *testing.T) {
1215 t.Log(t.ArtifactDir())
1216 }
1217
View as plain text