Source file
src/testing/testing.go
Documentation: testing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 package testing
341
342 import (
343 "bytes"
344 "errors"
345 "flag"
346 "fmt"
347 "internal/race"
348 "io"
349 "math/rand"
350 "os"
351 "reflect"
352 "runtime"
353 "runtime/debug"
354 "runtime/trace"
355 "strconv"
356 "strings"
357 "sync"
358 "sync/atomic"
359 "time"
360 "unicode"
361 "unicode/utf8"
362 )
363
364 var initRan bool
365
366
367
368
369
370
371 func Init() {
372 if initRan {
373 return
374 }
375 initRan = true
376
377
378
379
380
381 short = flag.Bool("test.short", false, "run smaller test suite to save time")
382
383
384 failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure")
385
386
387
388
389
390 outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
391
392 chatty = flag.Bool("test.v", false, "verbose: print additional output")
393 count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
394 coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
395 matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
396 match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
397 memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
398 memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
399 cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
400 blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
401 blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
402 mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
403 mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
404 panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
405 traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
406 timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
407 cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
408 parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
409 testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
410 shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks")
411
412 initBenchmarkFlags()
413 initFuzzFlags()
414 }
415
416 var (
417
418 short *bool
419 failFast *bool
420 outputDir *string
421 chatty *bool
422 count *uint
423 coverProfile *string
424 matchList *string
425 match *string
426 memProfile *string
427 memProfileRate *int
428 cpuProfile *string
429 blockProfile *string
430 blockProfileRate *int
431 mutexProfile *string
432 mutexProfileFraction *int
433 panicOnExit0 *bool
434 traceFile *string
435 timeout *time.Duration
436 cpuListStr *string
437 parallel *int
438 shuffle *string
439 testlog *string
440
441 haveExamples bool
442
443 cpuList []int
444 testlogFile *os.File
445
446 numFailed uint32
447 )
448
449 type chattyPrinter struct {
450 w io.Writer
451 lastNameMu sync.Mutex
452 lastName string
453 }
454
455 func newChattyPrinter(w io.Writer) *chattyPrinter {
456 return &chattyPrinter{w: w}
457 }
458
459
460
461
462 func (p *chattyPrinter) Updatef(testName, format string, args ...any) {
463 p.lastNameMu.Lock()
464 defer p.lastNameMu.Unlock()
465
466
467
468
469
470 p.lastName = testName
471 fmt.Fprintf(p.w, format, args...)
472 }
473
474
475
476 func (p *chattyPrinter) Printf(testName, format string, args ...any) {
477 p.lastNameMu.Lock()
478 defer p.lastNameMu.Unlock()
479
480 if p.lastName == "" {
481 p.lastName = testName
482 } else if p.lastName != testName {
483 fmt.Fprintf(p.w, "=== CONT %s\n", testName)
484 p.lastName = testName
485 }
486
487 fmt.Fprintf(p.w, format, args...)
488 }
489
490
491
492 const maxStackLen = 50
493
494
495
496 type common struct {
497 mu sync.RWMutex
498 output []byte
499 w io.Writer
500 ran bool
501 failed bool
502 skipped bool
503 done bool
504 helperPCs map[uintptr]struct{}
505 helperNames map[string]struct{}
506 cleanups []func()
507 cleanupName string
508 cleanupPc []uintptr
509 finished bool
510 inFuzzFn bool
511
512 chatty *chattyPrinter
513 bench bool
514 hasSub int32
515 raceErrors int
516 runner string
517
518 parent *common
519 level int
520 creator []uintptr
521 name string
522 start time.Time
523 duration time.Duration
524 barrier chan bool
525 signal chan bool
526 sub []*T
527
528 tempDirMu sync.Mutex
529 tempDir string
530 tempDirErr error
531 tempDirSeq int32
532 }
533
534
535 func Short() bool {
536 if short == nil {
537 panic("testing: Short called before Init")
538 }
539
540 if !flag.Parsed() {
541 panic("testing: Short called before Parse")
542 }
543
544 return *short
545 }
546
547
548
549
550 func CoverMode() string {
551 return cover.Mode
552 }
553
554
555 func Verbose() bool {
556
557 if chatty == nil {
558 panic("testing: Verbose called before Init")
559 }
560 if !flag.Parsed() {
561 panic("testing: Verbose called before Parse")
562 }
563 return *chatty
564 }
565
566 func (c *common) checkFuzzFn(name string) {
567 if c.inFuzzFn {
568 panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name))
569 }
570 }
571
572
573
574
575
576
577 func (c *common) frameSkip(skip int) runtime.Frame {
578
579
580 shouldUnlock := false
581 defer func() {
582 if shouldUnlock {
583 c.mu.Unlock()
584 }
585 }()
586 var pc [maxStackLen]uintptr
587
588
589 n := runtime.Callers(skip+2, pc[:])
590 if n == 0 {
591 panic("testing: zero callers found")
592 }
593 frames := runtime.CallersFrames(pc[:n])
594 var firstFrame, prevFrame, frame runtime.Frame
595 for more := true; more; prevFrame = frame {
596 frame, more = frames.Next()
597 if frame.Function == "runtime.gopanic" {
598 continue
599 }
600 if frame.Function == c.cleanupName {
601 frames = runtime.CallersFrames(c.cleanupPc)
602 continue
603 }
604 if firstFrame.PC == 0 {
605 firstFrame = frame
606 }
607 if frame.Function == c.runner {
608
609
610
611
612
613
614 if c.level > 1 {
615 frames = runtime.CallersFrames(c.creator)
616 parent := c.parent
617
618
619
620 if shouldUnlock {
621 c.mu.Unlock()
622 }
623 c = parent
624
625
626
627 shouldUnlock = true
628 c.mu.Lock()
629 continue
630 }
631 return prevFrame
632 }
633
634 if c.helperNames == nil {
635 c.helperNames = make(map[string]struct{})
636 for pc := range c.helperPCs {
637 c.helperNames[pcToName(pc)] = struct{}{}
638 }
639 }
640 if _, ok := c.helperNames[frame.Function]; !ok {
641
642 return frame
643 }
644 }
645 return firstFrame
646 }
647
648
649
650
651 func (c *common) decorate(s string, skip int) string {
652 frame := c.frameSkip(skip)
653 file := frame.File
654 line := frame.Line
655 if file != "" {
656
657 if index := strings.LastIndex(file, "/"); index >= 0 {
658 file = file[index+1:]
659 } else if index = strings.LastIndex(file, "\\"); index >= 0 {
660 file = file[index+1:]
661 }
662 } else {
663 file = "???"
664 }
665 if line == 0 {
666 line = 1
667 }
668 buf := new(strings.Builder)
669
670 buf.WriteString(" ")
671 fmt.Fprintf(buf, "%s:%d: ", file, line)
672 lines := strings.Split(s, "\n")
673 if l := len(lines); l > 1 && lines[l-1] == "" {
674 lines = lines[:l-1]
675 }
676 for i, line := range lines {
677 if i > 0 {
678
679 buf.WriteString("\n ")
680 }
681 buf.WriteString(line)
682 }
683 buf.WriteByte('\n')
684 return buf.String()
685 }
686
687
688
689 func (c *common) flushToParent(testName, format string, args ...any) {
690 p := c.parent
691 p.mu.Lock()
692 defer p.mu.Unlock()
693
694 c.mu.Lock()
695 defer c.mu.Unlock()
696
697 if len(c.output) > 0 {
698 format += "%s"
699 args = append(args[:len(args):len(args)], c.output)
700 c.output = c.output[:0]
701 }
702
703 if c.chatty != nil && p.w == c.chatty.w {
704
705
706
707
708
709
710
711
712
713 c.chatty.Updatef(testName, format, args...)
714 } else {
715
716
717 fmt.Fprintf(p.w, format, args...)
718 }
719 }
720
721 type indenter struct {
722 c *common
723 }
724
725 func (w indenter) Write(b []byte) (n int, err error) {
726 n = len(b)
727 for len(b) > 0 {
728 end := bytes.IndexByte(b, '\n')
729 if end == -1 {
730 end = len(b)
731 } else {
732 end++
733 }
734
735
736 const indent = " "
737 w.c.output = append(w.c.output, indent...)
738 w.c.output = append(w.c.output, b[:end]...)
739 b = b[end:]
740 }
741 return
742 }
743
744
745 func fmtDuration(d time.Duration) string {
746 return fmt.Sprintf("%.2fs", d.Seconds())
747 }
748
749
750 type TB interface {
751 Cleanup(func())
752 Error(args ...any)
753 Errorf(format string, args ...any)
754 Fail()
755 FailNow()
756 Failed() bool
757 Fatal(args ...any)
758 Fatalf(format string, args ...any)
759 Helper()
760 Log(args ...any)
761 Logf(format string, args ...any)
762 Name() string
763 Setenv(key, value string)
764 Skip(args ...any)
765 SkipNow()
766 Skipf(format string, args ...any)
767 Skipped() bool
768 TempDir() string
769
770
771
772
773 private()
774 }
775
776 var _ TB = (*T)(nil)
777 var _ TB = (*B)(nil)
778
779
780
781
782
783
784
785
786
787
788 type T struct {
789 common
790 isParallel bool
791 isEnvSet bool
792 context *testContext
793 }
794
795 func (c *common) private() {}
796
797
798
799
800
801
802 func (c *common) Name() string {
803 return c.name
804 }
805
806 func (c *common) setRan() {
807 if c.parent != nil {
808 c.parent.setRan()
809 }
810 c.mu.Lock()
811 defer c.mu.Unlock()
812 c.ran = true
813 }
814
815
816 func (c *common) Fail() {
817 if c.parent != nil {
818 c.parent.Fail()
819 }
820 c.mu.Lock()
821 defer c.mu.Unlock()
822
823 if c.done {
824 panic("Fail in goroutine after " + c.name + " has completed")
825 }
826 c.failed = true
827 }
828
829
830 func (c *common) Failed() bool {
831 c.mu.RLock()
832 failed := c.failed
833 c.mu.RUnlock()
834 return failed || c.raceErrors+race.Errors() > 0
835 }
836
837
838
839
840
841
842
843
844
845 func (c *common) FailNow() {
846 c.checkFuzzFn("FailNow")
847 c.Fail()
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868 c.mu.Lock()
869 c.finished = true
870 c.mu.Unlock()
871 runtime.Goexit()
872 }
873
874
875 func (c *common) log(s string) {
876 c.logDepth(s, 3)
877 }
878
879
880 func (c *common) logDepth(s string, depth int) {
881 c.mu.Lock()
882 defer c.mu.Unlock()
883 if c.done {
884
885
886 for parent := c.parent; parent != nil; parent = parent.parent {
887 parent.mu.Lock()
888 defer parent.mu.Unlock()
889 if !parent.done {
890 parent.output = append(parent.output, parent.decorate(s, depth+1)...)
891 return
892 }
893 }
894 panic("Log in goroutine after " + c.name + " has completed: " + s)
895 } else {
896 if c.chatty != nil {
897 if c.bench {
898
899
900 fmt.Print(c.decorate(s, depth+1))
901 } else {
902 c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
903 }
904
905 return
906 }
907 c.output = append(c.output, c.decorate(s, depth+1)...)
908 }
909 }
910
911
912
913
914
915 func (c *common) Log(args ...any) {
916 c.checkFuzzFn("Log")
917 c.log(fmt.Sprintln(args...))
918 }
919
920
921
922
923
924
925 func (c *common) Logf(format string, args ...any) {
926 c.checkFuzzFn("Logf")
927 c.log(fmt.Sprintf(format, args...))
928 }
929
930
931 func (c *common) Error(args ...any) {
932 c.checkFuzzFn("Error")
933 c.log(fmt.Sprintln(args...))
934 c.Fail()
935 }
936
937
938 func (c *common) Errorf(format string, args ...any) {
939 c.checkFuzzFn("Errorf")
940 c.log(fmt.Sprintf(format, args...))
941 c.Fail()
942 }
943
944
945 func (c *common) Fatal(args ...any) {
946 c.checkFuzzFn("Fatal")
947 c.log(fmt.Sprintln(args...))
948 c.FailNow()
949 }
950
951
952 func (c *common) Fatalf(format string, args ...any) {
953 c.checkFuzzFn("Fatalf")
954 c.log(fmt.Sprintf(format, args...))
955 c.FailNow()
956 }
957
958
959 func (c *common) Skip(args ...any) {
960 c.checkFuzzFn("Skip")
961 c.log(fmt.Sprintln(args...))
962 c.SkipNow()
963 }
964
965
966 func (c *common) Skipf(format string, args ...any) {
967 c.checkFuzzFn("Skipf")
968 c.log(fmt.Sprintf(format, args...))
969 c.SkipNow()
970 }
971
972
973
974
975
976
977
978
979
980 func (c *common) SkipNow() {
981 c.checkFuzzFn("SkipNow")
982 c.mu.Lock()
983 c.skipped = true
984 c.finished = true
985 c.mu.Unlock()
986 runtime.Goexit()
987 }
988
989
990 func (c *common) Skipped() bool {
991 c.mu.RLock()
992 defer c.mu.RUnlock()
993 return c.skipped
994 }
995
996
997
998
999 func (c *common) Helper() {
1000 c.mu.Lock()
1001 defer c.mu.Unlock()
1002 if c.helperPCs == nil {
1003 c.helperPCs = make(map[uintptr]struct{})
1004 }
1005
1006 var pc [1]uintptr
1007 n := runtime.Callers(2, pc[:])
1008 if n == 0 {
1009 panic("testing: zero callers found")
1010 }
1011 if _, found := c.helperPCs[pc[0]]; !found {
1012 c.helperPCs[pc[0]] = struct{}{}
1013 c.helperNames = nil
1014 }
1015 }
1016
1017
1018
1019
1020 func (c *common) Cleanup(f func()) {
1021 c.checkFuzzFn("Cleanup")
1022 var pc [maxStackLen]uintptr
1023
1024 n := runtime.Callers(2, pc[:])
1025 cleanupPc := pc[:n]
1026
1027 fn := func() {
1028 defer func() {
1029 c.mu.Lock()
1030 defer c.mu.Unlock()
1031 c.cleanupName = ""
1032 c.cleanupPc = nil
1033 }()
1034
1035 name := callerName(0)
1036 c.mu.Lock()
1037 c.cleanupName = name
1038 c.cleanupPc = cleanupPc
1039 c.mu.Unlock()
1040
1041 f()
1042 }
1043
1044 c.mu.Lock()
1045 defer c.mu.Unlock()
1046 c.cleanups = append(c.cleanups, fn)
1047 }
1048
1049
1050
1051
1052
1053
1054 func (c *common) TempDir() string {
1055 c.checkFuzzFn("TempDir")
1056
1057
1058 c.tempDirMu.Lock()
1059 var nonExistent bool
1060 if c.tempDir == "" {
1061 nonExistent = true
1062 } else {
1063 _, err := os.Stat(c.tempDir)
1064 nonExistent = os.IsNotExist(err)
1065 if err != nil && !nonExistent {
1066 c.Fatalf("TempDir: %v", err)
1067 }
1068 }
1069
1070 if nonExistent {
1071 c.Helper()
1072
1073
1074
1075
1076 mapper := func(r rune) rune {
1077 if r < utf8.RuneSelf {
1078 const allowed = "!#$%&()+,-.=@^_{}~ "
1079 if '0' <= r && r <= '9' ||
1080 'a' <= r && r <= 'z' ||
1081 'A' <= r && r <= 'Z' {
1082 return r
1083 }
1084 if strings.ContainsRune(allowed, r) {
1085 return r
1086 }
1087 } else if unicode.IsLetter(r) || unicode.IsNumber(r) {
1088 return r
1089 }
1090 return -1
1091 }
1092 pattern := strings.Map(mapper, c.Name())
1093 c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
1094 if c.tempDirErr == nil {
1095 c.Cleanup(func() {
1096 if err := removeAll(c.tempDir); err != nil {
1097 c.Errorf("TempDir RemoveAll cleanup: %v", err)
1098 }
1099 })
1100 }
1101 }
1102 c.tempDirMu.Unlock()
1103
1104 if c.tempDirErr != nil {
1105 c.Fatalf("TempDir: %v", c.tempDirErr)
1106 }
1107 seq := atomic.AddInt32(&c.tempDirSeq, 1)
1108 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
1109 if err := os.Mkdir(dir, 0777); err != nil {
1110 c.Fatalf("TempDir: %v", err)
1111 }
1112 return dir
1113 }
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124 func removeAll(path string) error {
1125 const arbitraryTimeout = 2 * time.Second
1126 var (
1127 start time.Time
1128 nextSleep = 1 * time.Millisecond
1129 )
1130 for {
1131 err := os.RemoveAll(path)
1132 if !isWindowsRetryable(err) {
1133 return err
1134 }
1135 if start.IsZero() {
1136 start = time.Now()
1137 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
1138 return err
1139 }
1140 time.Sleep(nextSleep)
1141 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
1142 }
1143 }
1144
1145
1146
1147
1148
1149
1150 func (c *common) Setenv(key, value string) {
1151 c.checkFuzzFn("Setenv")
1152 prevValue, ok := os.LookupEnv(key)
1153
1154 if err := os.Setenv(key, value); err != nil {
1155 c.Fatalf("cannot set environment variable: %v", err)
1156 }
1157
1158 if ok {
1159 c.Cleanup(func() {
1160 os.Setenv(key, prevValue)
1161 })
1162 } else {
1163 c.Cleanup(func() {
1164 os.Unsetenv(key)
1165 })
1166 }
1167 }
1168
1169
1170 type panicHandling int
1171
1172 const (
1173 normalPanic panicHandling = iota
1174 recoverAndReturnPanic
1175 )
1176
1177
1178
1179
1180 func (c *common) runCleanup(ph panicHandling) (panicVal any) {
1181 if ph == recoverAndReturnPanic {
1182 defer func() {
1183 panicVal = recover()
1184 }()
1185 }
1186
1187
1188
1189 defer func() {
1190 c.mu.Lock()
1191 recur := len(c.cleanups) > 0
1192 c.mu.Unlock()
1193 if recur {
1194 c.runCleanup(normalPanic)
1195 }
1196 }()
1197
1198 for {
1199 var cleanup func()
1200 c.mu.Lock()
1201 if len(c.cleanups) > 0 {
1202 last := len(c.cleanups) - 1
1203 cleanup = c.cleanups[last]
1204 c.cleanups = c.cleanups[:last]
1205 }
1206 c.mu.Unlock()
1207 if cleanup == nil {
1208 return nil
1209 }
1210 cleanup()
1211 }
1212 }
1213
1214
1215
1216 func callerName(skip int) string {
1217 var pc [1]uintptr
1218 n := runtime.Callers(skip+2, pc[:])
1219 if n == 0 {
1220 panic("testing: zero callers found")
1221 }
1222 return pcToName(pc[0])
1223 }
1224
1225 func pcToName(pc uintptr) string {
1226 pcs := []uintptr{pc}
1227 frames := runtime.CallersFrames(pcs)
1228 frame, _ := frames.Next()
1229 return frame.Function
1230 }
1231
1232
1233
1234
1235
1236 func (t *T) Parallel() {
1237 if t.isParallel {
1238 panic("testing: t.Parallel called multiple times")
1239 }
1240 if t.isEnvSet {
1241 panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests")
1242 }
1243 t.isParallel = true
1244 if t.parent.barrier == nil {
1245
1246
1247
1248 return
1249 }
1250
1251
1252
1253
1254 t.duration += time.Since(t.start)
1255
1256
1257 t.parent.sub = append(t.parent.sub, t)
1258 t.raceErrors += race.Errors()
1259
1260 if t.chatty != nil {
1261
1262
1263
1264
1265
1266
1267 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1268 }
1269
1270 t.signal <- true
1271 <-t.parent.barrier
1272 t.context.waitParallel()
1273
1274 if t.chatty != nil {
1275 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1276 }
1277
1278 t.start = time.Now()
1279 t.raceErrors += -race.Errors()
1280 }
1281
1282
1283
1284
1285
1286
1287 func (t *T) Setenv(key, value string) {
1288 if t.isParallel {
1289 panic("testing: t.Setenv called after t.Parallel; cannot set environment variables in parallel tests")
1290 }
1291
1292 t.isEnvSet = true
1293
1294 t.common.Setenv(key, value)
1295 }
1296
1297
1298
1299 type InternalTest struct {
1300 Name string
1301 F func(*T)
1302 }
1303
1304 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
1305
1306 func tRunner(t *T, fn func(t *T)) {
1307 t.runner = callerName(0)
1308
1309
1310
1311
1312
1313 defer func() {
1314 if t.Failed() {
1315 atomic.AddUint32(&numFailed, 1)
1316 }
1317
1318 if t.raceErrors+race.Errors() > 0 {
1319 t.Errorf("race detected during execution of test")
1320 }
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330 err := recover()
1331 signal := true
1332
1333 t.mu.RLock()
1334 finished := t.finished
1335 t.mu.RUnlock()
1336 if !finished && err == nil {
1337 err = errNilPanicOrGoexit
1338 for p := t.parent; p != nil; p = p.parent {
1339 p.mu.RLock()
1340 finished = p.finished
1341 p.mu.RUnlock()
1342 if finished {
1343 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
1344 err = nil
1345 signal = false
1346 break
1347 }
1348 }
1349 }
1350
1351 if err != nil && t.context.isFuzzing {
1352 prefix := "panic: "
1353 if err == errNilPanicOrGoexit {
1354 prefix = ""
1355 }
1356 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
1357 t.mu.Lock()
1358 t.finished = true
1359 t.mu.Unlock()
1360 err = nil
1361 }
1362
1363
1364
1365 didPanic := false
1366 defer func() {
1367 if didPanic {
1368 return
1369 }
1370 if err != nil {
1371 panic(err)
1372 }
1373
1374
1375
1376 t.signal <- signal
1377 }()
1378
1379 doPanic := func(err any) {
1380 t.Fail()
1381 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
1382 t.Logf("cleanup panicked with %v", r)
1383 }
1384
1385 for root := &t.common; root.parent != nil; root = root.parent {
1386 root.mu.Lock()
1387 root.duration += time.Since(root.start)
1388 d := root.duration
1389 root.mu.Unlock()
1390 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
1391 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
1392 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
1393 }
1394 }
1395 didPanic = true
1396 panic(err)
1397 }
1398 if err != nil {
1399 doPanic(err)
1400 }
1401
1402 t.duration += time.Since(t.start)
1403
1404 if len(t.sub) > 0 {
1405
1406
1407 t.context.release()
1408
1409 close(t.barrier)
1410
1411 for _, sub := range t.sub {
1412 <-sub.signal
1413 }
1414 cleanupStart := time.Now()
1415 err := t.runCleanup(recoverAndReturnPanic)
1416 t.duration += time.Since(cleanupStart)
1417 if err != nil {
1418 doPanic(err)
1419 }
1420 if !t.isParallel {
1421
1422 t.context.waitParallel()
1423 }
1424 } else if t.isParallel {
1425
1426
1427 t.context.release()
1428 }
1429 t.report()
1430
1431
1432
1433 t.done = true
1434 if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
1435 t.setRan()
1436 }
1437 }()
1438 defer func() {
1439 if len(t.sub) == 0 {
1440 t.runCleanup(normalPanic)
1441 }
1442 }()
1443
1444 t.start = time.Now()
1445 t.raceErrors = -race.Errors()
1446 fn(t)
1447
1448
1449 t.mu.Lock()
1450 t.finished = true
1451 t.mu.Unlock()
1452 }
1453
1454
1455
1456
1457
1458
1459
1460 func (t *T) Run(name string, f func(t *T)) bool {
1461 atomic.StoreInt32(&t.hasSub, 1)
1462 testName, ok, _ := t.context.match.fullName(&t.common, name)
1463 if !ok || shouldFailFast() {
1464 return true
1465 }
1466
1467
1468
1469 var pc [maxStackLen]uintptr
1470 n := runtime.Callers(2, pc[:])
1471 t = &T{
1472 common: common{
1473 barrier: make(chan bool),
1474 signal: make(chan bool, 1),
1475 name: testName,
1476 parent: &t.common,
1477 level: t.level + 1,
1478 creator: pc[:n],
1479 chatty: t.chatty,
1480 },
1481 context: t.context,
1482 }
1483 t.w = indenter{&t.common}
1484
1485 if t.chatty != nil {
1486 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
1487 }
1488
1489
1490
1491
1492
1493 go tRunner(t, f)
1494 if !<-t.signal {
1495
1496
1497 runtime.Goexit()
1498 }
1499 return !t.failed
1500 }
1501
1502
1503
1504
1505
1506 func (t *T) Deadline() (deadline time.Time, ok bool) {
1507 deadline = t.context.deadline
1508 return deadline, !deadline.IsZero()
1509 }
1510
1511
1512
1513 type testContext struct {
1514 match *matcher
1515 deadline time.Time
1516
1517
1518
1519
1520
1521 isFuzzing bool
1522
1523 mu sync.Mutex
1524
1525
1526 startParallel chan bool
1527
1528
1529
1530 running int
1531
1532
1533 numWaiting int
1534
1535
1536 maxParallel int
1537 }
1538
1539 func newTestContext(maxParallel int, m *matcher) *testContext {
1540 return &testContext{
1541 match: m,
1542 startParallel: make(chan bool),
1543 maxParallel: maxParallel,
1544 running: 1,
1545 }
1546 }
1547
1548 func (c *testContext) waitParallel() {
1549 c.mu.Lock()
1550 if c.running < c.maxParallel {
1551 c.running++
1552 c.mu.Unlock()
1553 return
1554 }
1555 c.numWaiting++
1556 c.mu.Unlock()
1557 <-c.startParallel
1558 }
1559
1560 func (c *testContext) release() {
1561 c.mu.Lock()
1562 if c.numWaiting == 0 {
1563 c.running--
1564 c.mu.Unlock()
1565 return
1566 }
1567 c.numWaiting--
1568 c.mu.Unlock()
1569 c.startParallel <- true
1570 }
1571
1572
1573
1574 var errMain = errors.New("testing: unexpected use of func Main")
1575
1576 type matchStringOnly func(pat, str string) (bool, error)
1577
1578 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
1579 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
1580 func (f matchStringOnly) StopCPUProfile() {}
1581 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
1582 func (f matchStringOnly) ImportPath() string { return "" }
1583 func (f matchStringOnly) StartTestLog(io.Writer) {}
1584 func (f matchStringOnly) StopTestLog() error { return errMain }
1585 func (f matchStringOnly) SetPanicOnExit0(bool) {}
1586 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
1587 return errMain
1588 }
1589 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
1590 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
1591 return nil, errMain
1592 }
1593 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
1594 func (f matchStringOnly) ResetCoverage() {}
1595 func (f matchStringOnly) SnapshotCoverage() {}
1596
1597
1598
1599
1600
1601
1602
1603 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
1604 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
1605 }
1606
1607
1608 type M struct {
1609 deps testDeps
1610 tests []InternalTest
1611 benchmarks []InternalBenchmark
1612 fuzzTargets []InternalFuzzTarget
1613 examples []InternalExample
1614
1615 timer *time.Timer
1616 afterOnce sync.Once
1617
1618 numRun int
1619
1620
1621
1622 exitCode int
1623 }
1624
1625
1626
1627
1628
1629 type testDeps interface {
1630 ImportPath() string
1631 MatchString(pat, str string) (bool, error)
1632 SetPanicOnExit0(bool)
1633 StartCPUProfile(io.Writer) error
1634 StopCPUProfile()
1635 StartTestLog(io.Writer)
1636 StopTestLog() error
1637 WriteProfileTo(string, io.Writer, int) error
1638 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
1639 RunFuzzWorker(func(corpusEntry) error) error
1640 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
1641 CheckCorpus([]any, []reflect.Type) error
1642 ResetCoverage()
1643 SnapshotCoverage()
1644 }
1645
1646
1647
1648
1649 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
1650 Init()
1651 return &M{
1652 deps: deps,
1653 tests: tests,
1654 benchmarks: benchmarks,
1655 fuzzTargets: fuzzTargets,
1656 examples: examples,
1657 }
1658 }
1659
1660
1661 func (m *M) Run() (code int) {
1662 defer func() {
1663 code = m.exitCode
1664 }()
1665
1666
1667
1668
1669
1670 m.numRun++
1671
1672
1673 if !flag.Parsed() {
1674 flag.Parse()
1675 }
1676
1677 if *parallel < 1 {
1678 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
1679 flag.Usage()
1680 m.exitCode = 2
1681 return
1682 }
1683 if *matchFuzz != "" && *fuzzCacheDir == "" {
1684 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
1685 flag.Usage()
1686 m.exitCode = 2
1687 return
1688 }
1689
1690 if len(*matchList) != 0 {
1691 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
1692 m.exitCode = 0
1693 return
1694 }
1695
1696 if *shuffle != "off" {
1697 var n int64
1698 var err error
1699 if *shuffle == "on" {
1700 n = time.Now().UnixNano()
1701 } else {
1702 n, err = strconv.ParseInt(*shuffle, 10, 64)
1703 if err != nil {
1704 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
1705 m.exitCode = 2
1706 return
1707 }
1708 }
1709 fmt.Println("-test.shuffle", n)
1710 rng := rand.New(rand.NewSource(n))
1711 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
1712 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
1713 }
1714
1715 parseCpuList()
1716
1717 m.before()
1718 defer m.after()
1719
1720
1721
1722
1723 if !*isFuzzWorker {
1724 deadline := m.startAlarm()
1725 haveExamples = len(m.examples) > 0
1726 testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
1727 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
1728 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
1729 m.stopAlarm()
1730 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
1731 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
1732 }
1733 if !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
1734 fmt.Println("FAIL")
1735 m.exitCode = 1
1736 return
1737 }
1738 }
1739
1740 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
1741 if !fuzzingOk {
1742 fmt.Println("FAIL")
1743 if *isFuzzWorker {
1744 m.exitCode = fuzzWorkerExitCode
1745 } else {
1746 m.exitCode = 1
1747 }
1748 return
1749 }
1750
1751 m.exitCode = 0
1752 if !*isFuzzWorker {
1753 fmt.Println("PASS")
1754 }
1755 return
1756 }
1757
1758 func (t *T) report() {
1759 if t.parent == nil {
1760 return
1761 }
1762 dstr := fmtDuration(t.duration)
1763 format := "--- %s: %s (%s)\n"
1764 if t.Failed() {
1765 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
1766 } else if t.chatty != nil {
1767 if t.Skipped() {
1768 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
1769 } else {
1770 t.flushToParent(t.name, format, "PASS", t.name, dstr)
1771 }
1772 }
1773 }
1774
1775 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
1776 if _, err := matchString(*matchList, "non-empty"); err != nil {
1777 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
1778 os.Exit(1)
1779 }
1780
1781 for _, test := range tests {
1782 if ok, _ := matchString(*matchList, test.Name); ok {
1783 fmt.Println(test.Name)
1784 }
1785 }
1786 for _, bench := range benchmarks {
1787 if ok, _ := matchString(*matchList, bench.Name); ok {
1788 fmt.Println(bench.Name)
1789 }
1790 }
1791 for _, fuzzTarget := range fuzzTargets {
1792 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
1793 fmt.Println(fuzzTarget.Name)
1794 }
1795 }
1796 for _, example := range examples {
1797 if ok, _ := matchString(*matchList, example.Name); ok {
1798 fmt.Println(example.Name)
1799 }
1800 }
1801 }
1802
1803
1804
1805 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
1806 var deadline time.Time
1807 if *timeout > 0 {
1808 deadline = time.Now().Add(*timeout)
1809 }
1810 ran, ok := runTests(matchString, tests, deadline)
1811 if !ran && !haveExamples {
1812 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
1813 }
1814 return ok
1815 }
1816
1817 func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
1818 ok = true
1819 for _, procs := range cpuList {
1820 runtime.GOMAXPROCS(procs)
1821 for i := uint(0); i < *count; i++ {
1822 if shouldFailFast() {
1823 break
1824 }
1825 if i > 0 && !ran {
1826
1827
1828
1829 break
1830 }
1831 ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
1832 ctx.deadline = deadline
1833 t := &T{
1834 common: common{
1835 signal: make(chan bool, 1),
1836 barrier: make(chan bool),
1837 w: os.Stdout,
1838 },
1839 context: ctx,
1840 }
1841 if Verbose() {
1842 t.chatty = newChattyPrinter(t.w)
1843 }
1844 tRunner(t, func(t *T) {
1845 for _, test := range tests {
1846 t.Run(test.Name, test.F)
1847 }
1848 })
1849 select {
1850 case <-t.signal:
1851 default:
1852 panic("internal error: tRunner exited without sending on t.signal")
1853 }
1854 ok = ok && !t.Failed()
1855 ran = ran || t.ran
1856 }
1857 }
1858 return ran, ok
1859 }
1860
1861
1862 func (m *M) before() {
1863 if *memProfileRate > 0 {
1864 runtime.MemProfileRate = *memProfileRate
1865 }
1866 if *cpuProfile != "" {
1867 f, err := os.Create(toOutputDir(*cpuProfile))
1868 if err != nil {
1869 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1870 return
1871 }
1872 if err := m.deps.StartCPUProfile(f); err != nil {
1873 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
1874 f.Close()
1875 return
1876 }
1877
1878 }
1879 if *traceFile != "" {
1880 f, err := os.Create(toOutputDir(*traceFile))
1881 if err != nil {
1882 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1883 return
1884 }
1885 if err := trace.Start(f); err != nil {
1886 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
1887 f.Close()
1888 return
1889 }
1890
1891 }
1892 if *blockProfile != "" && *blockProfileRate >= 0 {
1893 runtime.SetBlockProfileRate(*blockProfileRate)
1894 }
1895 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
1896 runtime.SetMutexProfileFraction(*mutexProfileFraction)
1897 }
1898 if *coverProfile != "" && cover.Mode == "" {
1899 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
1900 os.Exit(2)
1901 }
1902 if *testlog != "" {
1903
1904
1905 var f *os.File
1906 var err error
1907 if m.numRun == 1 {
1908 f, err = os.Create(*testlog)
1909 } else {
1910 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
1911 if err == nil {
1912 f.Seek(0, io.SeekEnd)
1913 }
1914 }
1915 if err != nil {
1916 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1917 os.Exit(2)
1918 }
1919 m.deps.StartTestLog(f)
1920 testlogFile = f
1921 }
1922 if *panicOnExit0 {
1923 m.deps.SetPanicOnExit0(true)
1924 }
1925 }
1926
1927
1928 func (m *M) after() {
1929 m.afterOnce.Do(func() {
1930 m.writeProfiles()
1931 })
1932
1933
1934
1935
1936 if *panicOnExit0 {
1937 m.deps.SetPanicOnExit0(false)
1938 }
1939 }
1940
1941 func (m *M) writeProfiles() {
1942 if *testlog != "" {
1943 if err := m.deps.StopTestLog(); err != nil {
1944 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
1945 os.Exit(2)
1946 }
1947 if err := testlogFile.Close(); err != nil {
1948 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
1949 os.Exit(2)
1950 }
1951 }
1952 if *cpuProfile != "" {
1953 m.deps.StopCPUProfile()
1954 }
1955 if *traceFile != "" {
1956 trace.Stop()
1957 }
1958 if *memProfile != "" {
1959 f, err := os.Create(toOutputDir(*memProfile))
1960 if err != nil {
1961 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1962 os.Exit(2)
1963 }
1964 runtime.GC()
1965 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
1966 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
1967 os.Exit(2)
1968 }
1969 f.Close()
1970 }
1971 if *blockProfile != "" && *blockProfileRate >= 0 {
1972 f, err := os.Create(toOutputDir(*blockProfile))
1973 if err != nil {
1974 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1975 os.Exit(2)
1976 }
1977 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
1978 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
1979 os.Exit(2)
1980 }
1981 f.Close()
1982 }
1983 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
1984 f, err := os.Create(toOutputDir(*mutexProfile))
1985 if err != nil {
1986 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1987 os.Exit(2)
1988 }
1989 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
1990 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
1991 os.Exit(2)
1992 }
1993 f.Close()
1994 }
1995 if cover.Mode != "" {
1996 coverReport()
1997 }
1998 }
1999
2000
2001
2002 func toOutputDir(path string) string {
2003 if *outputDir == "" || path == "" {
2004 return path
2005 }
2006
2007
2008
2009
2010
2011
2012
2013 if runtime.GOOS == "windows" && len(path) >= 2 {
2014 letter, colon := path[0], path[1]
2015 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2016
2017 return path
2018 }
2019 }
2020 if os.IsPathSeparator(path[0]) {
2021 return path
2022 }
2023 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2024 }
2025
2026
2027 func (m *M) startAlarm() time.Time {
2028 if *timeout <= 0 {
2029 return time.Time{}
2030 }
2031
2032 deadline := time.Now().Add(*timeout)
2033 m.timer = time.AfterFunc(*timeout, func() {
2034 m.after()
2035 debug.SetTraceback("all")
2036 panic(fmt.Sprintf("test timed out after %v", *timeout))
2037 })
2038 return deadline
2039 }
2040
2041
2042 func (m *M) stopAlarm() {
2043 if *timeout > 0 {
2044 m.timer.Stop()
2045 }
2046 }
2047
2048 func parseCpuList() {
2049 for _, val := range strings.Split(*cpuListStr, ",") {
2050 val = strings.TrimSpace(val)
2051 if val == "" {
2052 continue
2053 }
2054 cpu, err := strconv.Atoi(val)
2055 if err != nil || cpu <= 0 {
2056 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2057 os.Exit(1)
2058 }
2059 cpuList = append(cpuList, cpu)
2060 }
2061 if cpuList == nil {
2062 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2063 }
2064 }
2065
2066 func shouldFailFast() bool {
2067 return *failFast && atomic.LoadUint32(&numFailed) > 0
2068 }
2069
View as plain text