Source file
src/testing/testing.go
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
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 package testing
371
372 import (
373 "bytes"
374 "errors"
375 "flag"
376 "fmt"
377 "internal/goexperiment"
378 "internal/race"
379 "io"
380 "math/rand"
381 "os"
382 "reflect"
383 "runtime"
384 "runtime/debug"
385 "runtime/trace"
386 "sort"
387 "strconv"
388 "strings"
389 "sync"
390 "sync/atomic"
391 "time"
392 "unicode"
393 "unicode/utf8"
394 )
395
396 var initRan bool
397
398
399
400
401
402
403 func Init() {
404 if initRan {
405 return
406 }
407 initRan = true
408
409
410
411
412
413 short = flag.Bool("test.short", false, "run smaller test suite to save time")
414
415
416 failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure")
417
418
419
420
421
422 outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
423
424 flag.Var(&chatty, "test.v", "verbose: print additional output")
425 count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
426 coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
427 gocoverdir = flag.String("test.gocoverdir", "", "write coverage intermediate files to this directory")
428 matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
429 match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
430 skip = flag.String("test.skip", "", "do not list or run tests matching `regexp`")
431 memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
432 memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
433 cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
434 blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
435 blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
436 mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
437 mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
438 panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
439 traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
440 timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
441 cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
442 parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
443 testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
444 shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks")
445 fullPath = flag.Bool("test.fullpath", false, "show full file names in error messages")
446
447 initBenchmarkFlags()
448 initFuzzFlags()
449 }
450
451 var (
452
453 short *bool
454 failFast *bool
455 outputDir *string
456 chatty chattyFlag
457 count *uint
458 coverProfile *string
459 gocoverdir *string
460 matchList *string
461 match *string
462 skip *string
463 memProfile *string
464 memProfileRate *int
465 cpuProfile *string
466 blockProfile *string
467 blockProfileRate *int
468 mutexProfile *string
469 mutexProfileFraction *int
470 panicOnExit0 *bool
471 traceFile *string
472 timeout *time.Duration
473 cpuListStr *string
474 parallel *int
475 shuffle *string
476 testlog *string
477 fullPath *bool
478
479 haveExamples bool
480
481 cpuList []int
482 testlogFile *os.File
483
484 numFailed atomic.Uint32
485
486 running sync.Map
487 )
488
489 type chattyFlag struct {
490 on bool
491 json bool
492 }
493
494 func (*chattyFlag) IsBoolFlag() bool { return true }
495
496 func (f *chattyFlag) Set(arg string) error {
497 switch arg {
498 default:
499 return fmt.Errorf("invalid flag -test.v=%s", arg)
500 case "true", "test2json":
501 f.on = true
502 f.json = arg == "test2json"
503 case "false":
504 f.on = false
505 f.json = false
506 }
507 return nil
508 }
509
510 func (f *chattyFlag) String() string {
511 if f.json {
512 return "test2json"
513 }
514 if f.on {
515 return "true"
516 }
517 return "false"
518 }
519
520 func (f *chattyFlag) Get() any {
521 if f.json {
522 return "test2json"
523 }
524 return f.on
525 }
526
527 const marker = byte(0x16)
528
529 func (f *chattyFlag) prefix() string {
530 if f.json {
531 return string(marker)
532 }
533 return ""
534 }
535
536 type chattyPrinter struct {
537 w io.Writer
538 lastNameMu sync.Mutex
539 lastName string
540 json bool
541 }
542
543 func newChattyPrinter(w io.Writer) *chattyPrinter {
544 return &chattyPrinter{w: w, json: chatty.json}
545 }
546
547
548
549
550
551 func (p *chattyPrinter) prefix() string {
552 if p != nil && p.json {
553 return string(marker)
554 }
555 return ""
556 }
557
558
559
560
561 func (p *chattyPrinter) Updatef(testName, format string, args ...any) {
562 p.lastNameMu.Lock()
563 defer p.lastNameMu.Unlock()
564
565
566
567
568
569 p.lastName = testName
570 fmt.Fprintf(p.w, p.prefix()+format, args...)
571 }
572
573
574
575 func (p *chattyPrinter) Printf(testName, format string, args ...any) {
576 p.lastNameMu.Lock()
577 defer p.lastNameMu.Unlock()
578
579 if p.lastName == "" {
580 p.lastName = testName
581 } else if p.lastName != testName {
582 fmt.Fprintf(p.w, "%s=== NAME %s\n", p.prefix(), testName)
583 p.lastName = testName
584 }
585
586 fmt.Fprintf(p.w, format, args...)
587 }
588
589
590
591 const maxStackLen = 50
592
593
594
595 type common struct {
596 mu sync.RWMutex
597 output []byte
598 w io.Writer
599 ran bool
600 failed bool
601 skipped bool
602 done bool
603 helperPCs map[uintptr]struct{}
604 helperNames map[string]struct{}
605 cleanups []func()
606 cleanupName string
607 cleanupPc []uintptr
608 finished bool
609 inFuzzFn bool
610
611 chatty *chattyPrinter
612 bench bool
613 hasSub atomic.Bool
614 cleanupStarted atomic.Bool
615 runner string
616 isParallel bool
617
618 parent *common
619 level int
620 creator []uintptr
621 name string
622 start highPrecisionTime
623 duration time.Duration
624 barrier chan bool
625 signal chan bool
626 sub []*T
627
628 lastRaceErrors atomic.Int64
629 raceErrorLogged atomic.Bool
630
631 tempDirMu sync.Mutex
632 tempDir string
633 tempDirErr error
634 tempDirSeq int32
635 }
636
637
638 func Short() bool {
639 if short == nil {
640 panic("testing: Short called before Init")
641 }
642
643 if !flag.Parsed() {
644 panic("testing: Short called before Parse")
645 }
646
647 return *short
648 }
649
650
651
652
653
654
655
656
657 var testBinary = "0"
658
659
660
661
662 func Testing() bool {
663 return testBinary == "1"
664 }
665
666
667
668
669 func CoverMode() string {
670 if goexperiment.CoverageRedesign {
671 return cover2.mode
672 }
673 return cover.Mode
674 }
675
676
677 func Verbose() bool {
678
679 if !flag.Parsed() {
680 panic("testing: Verbose called before Parse")
681 }
682 return chatty.on
683 }
684
685 func (c *common) checkFuzzFn(name string) {
686 if c.inFuzzFn {
687 panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name))
688 }
689 }
690
691
692
693
694
695
696 func (c *common) frameSkip(skip int) runtime.Frame {
697
698
699 shouldUnlock := false
700 defer func() {
701 if shouldUnlock {
702 c.mu.Unlock()
703 }
704 }()
705 var pc [maxStackLen]uintptr
706
707
708 n := runtime.Callers(skip+2, pc[:])
709 if n == 0 {
710 panic("testing: zero callers found")
711 }
712 frames := runtime.CallersFrames(pc[:n])
713 var firstFrame, prevFrame, frame runtime.Frame
714 for more := true; more; prevFrame = frame {
715 frame, more = frames.Next()
716 if frame.Function == "runtime.gopanic" {
717 continue
718 }
719 if frame.Function == c.cleanupName {
720 frames = runtime.CallersFrames(c.cleanupPc)
721 continue
722 }
723 if firstFrame.PC == 0 {
724 firstFrame = frame
725 }
726 if frame.Function == c.runner {
727
728
729
730
731
732
733 if c.level > 1 {
734 frames = runtime.CallersFrames(c.creator)
735 parent := c.parent
736
737
738
739 if shouldUnlock {
740 c.mu.Unlock()
741 }
742 c = parent
743
744
745
746 shouldUnlock = true
747 c.mu.Lock()
748 continue
749 }
750 return prevFrame
751 }
752
753 if c.helperNames == nil {
754 c.helperNames = make(map[string]struct{})
755 for pc := range c.helperPCs {
756 c.helperNames[pcToName(pc)] = struct{}{}
757 }
758 }
759 if _, ok := c.helperNames[frame.Function]; !ok {
760
761 return frame
762 }
763 }
764 return firstFrame
765 }
766
767
768
769
770 func (c *common) decorate(s string, skip int) string {
771 frame := c.frameSkip(skip)
772 file := frame.File
773 line := frame.Line
774 if file != "" {
775 if *fullPath {
776
777 } else if index := strings.LastIndexAny(file, `/\`); index >= 0 {
778 file = file[index+1:]
779 }
780 } else {
781 file = "???"
782 }
783 if line == 0 {
784 line = 1
785 }
786 buf := new(strings.Builder)
787
788 buf.WriteString(" ")
789 fmt.Fprintf(buf, "%s:%d: ", file, line)
790 lines := strings.Split(s, "\n")
791 if l := len(lines); l > 1 && lines[l-1] == "" {
792 lines = lines[:l-1]
793 }
794 for i, line := range lines {
795 if i > 0 {
796
797 buf.WriteString("\n ")
798 }
799 buf.WriteString(line)
800 }
801 buf.WriteByte('\n')
802 return buf.String()
803 }
804
805
806
807 func (c *common) flushToParent(testName, format string, args ...any) {
808 p := c.parent
809 p.mu.Lock()
810 defer p.mu.Unlock()
811
812 c.mu.Lock()
813 defer c.mu.Unlock()
814
815 if len(c.output) > 0 {
816
817
818
819 format += "%s"
820 args = append(args[:len(args):len(args)], c.output)
821 c.output = c.output[:0]
822 }
823
824 if c.chatty != nil && (p.w == c.chatty.w || c.chatty.json) {
825
826
827
828
829
830
831
832
833
834
835
836
837
838 c.chatty.Updatef(testName, format, args...)
839 } else {
840
841
842 fmt.Fprintf(p.w, c.chatty.prefix()+format, args...)
843 }
844 }
845
846 type indenter struct {
847 c *common
848 }
849
850 func (w indenter) Write(b []byte) (n int, err error) {
851 n = len(b)
852 for len(b) > 0 {
853 end := bytes.IndexByte(b, '\n')
854 if end == -1 {
855 end = len(b)
856 } else {
857 end++
858 }
859
860
861 line := b[:end]
862 if line[0] == marker {
863 w.c.output = append(w.c.output, marker)
864 line = line[1:]
865 }
866 const indent = " "
867 w.c.output = append(w.c.output, indent...)
868 w.c.output = append(w.c.output, line...)
869 b = b[end:]
870 }
871 return
872 }
873
874
875 func fmtDuration(d time.Duration) string {
876 return fmt.Sprintf("%.2fs", d.Seconds())
877 }
878
879
880 type TB interface {
881 Cleanup(func())
882 Error(args ...any)
883 Errorf(format string, args ...any)
884 Fail()
885 FailNow()
886 Failed() bool
887 Fatal(args ...any)
888 Fatalf(format string, args ...any)
889 Helper()
890 Log(args ...any)
891 Logf(format string, args ...any)
892 Name() string
893 Setenv(key, value string)
894 Skip(args ...any)
895 SkipNow()
896 Skipf(format string, args ...any)
897 Skipped() bool
898 TempDir() string
899
900
901
902
903 private()
904 }
905
906 var _ TB = (*T)(nil)
907 var _ TB = (*B)(nil)
908
909
910
911
912
913
914
915
916
917
918 type T struct {
919 common
920 isEnvSet bool
921 context *testContext
922 }
923
924 func (c *common) private() {}
925
926
927
928
929
930
931 func (c *common) Name() string {
932 return c.name
933 }
934
935 func (c *common) setRan() {
936 if c.parent != nil {
937 c.parent.setRan()
938 }
939 c.mu.Lock()
940 defer c.mu.Unlock()
941 c.ran = true
942 }
943
944
945 func (c *common) Fail() {
946 if c.parent != nil {
947 c.parent.Fail()
948 }
949 c.mu.Lock()
950 defer c.mu.Unlock()
951
952 if c.done {
953 panic("Fail in goroutine after " + c.name + " has completed")
954 }
955 c.failed = true
956 }
957
958
959 func (c *common) Failed() bool {
960 c.mu.RLock()
961 defer c.mu.RUnlock()
962
963 if !c.done && int64(race.Errors()) > c.lastRaceErrors.Load() {
964 c.mu.RUnlock()
965 c.checkRaces()
966 c.mu.RLock()
967 }
968
969 return c.failed
970 }
971
972
973
974
975
976
977
978
979
980 func (c *common) FailNow() {
981 c.checkFuzzFn("FailNow")
982 c.Fail()
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003 c.mu.Lock()
1004 c.finished = true
1005 c.mu.Unlock()
1006 runtime.Goexit()
1007 }
1008
1009
1010 func (c *common) log(s string) {
1011 c.logDepth(s, 3)
1012 }
1013
1014
1015 func (c *common) logDepth(s string, depth int) {
1016 c.mu.Lock()
1017 defer c.mu.Unlock()
1018 if c.done {
1019
1020
1021 for parent := c.parent; parent != nil; parent = parent.parent {
1022 parent.mu.Lock()
1023 defer parent.mu.Unlock()
1024 if !parent.done {
1025 parent.output = append(parent.output, parent.decorate(s, depth+1)...)
1026 return
1027 }
1028 }
1029 panic("Log in goroutine after " + c.name + " has completed: " + s)
1030 } else {
1031 if c.chatty != nil {
1032 if c.bench {
1033
1034
1035 fmt.Print(c.decorate(s, depth+1))
1036 } else {
1037 c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
1038 }
1039
1040 return
1041 }
1042 c.output = append(c.output, c.decorate(s, depth+1)...)
1043 }
1044 }
1045
1046
1047
1048
1049
1050 func (c *common) Log(args ...any) {
1051 c.checkFuzzFn("Log")
1052 c.log(fmt.Sprintln(args...))
1053 }
1054
1055
1056
1057
1058
1059
1060 func (c *common) Logf(format string, args ...any) {
1061 c.checkFuzzFn("Logf")
1062 c.log(fmt.Sprintf(format, args...))
1063 }
1064
1065
1066 func (c *common) Error(args ...any) {
1067 c.checkFuzzFn("Error")
1068 c.log(fmt.Sprintln(args...))
1069 c.Fail()
1070 }
1071
1072
1073 func (c *common) Errorf(format string, args ...any) {
1074 c.checkFuzzFn("Errorf")
1075 c.log(fmt.Sprintf(format, args...))
1076 c.Fail()
1077 }
1078
1079
1080 func (c *common) Fatal(args ...any) {
1081 c.checkFuzzFn("Fatal")
1082 c.log(fmt.Sprintln(args...))
1083 c.FailNow()
1084 }
1085
1086
1087 func (c *common) Fatalf(format string, args ...any) {
1088 c.checkFuzzFn("Fatalf")
1089 c.log(fmt.Sprintf(format, args...))
1090 c.FailNow()
1091 }
1092
1093
1094 func (c *common) Skip(args ...any) {
1095 c.checkFuzzFn("Skip")
1096 c.log(fmt.Sprintln(args...))
1097 c.SkipNow()
1098 }
1099
1100
1101 func (c *common) Skipf(format string, args ...any) {
1102 c.checkFuzzFn("Skipf")
1103 c.log(fmt.Sprintf(format, args...))
1104 c.SkipNow()
1105 }
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115 func (c *common) SkipNow() {
1116 c.checkFuzzFn("SkipNow")
1117 c.mu.Lock()
1118 c.skipped = true
1119 c.finished = true
1120 c.mu.Unlock()
1121 runtime.Goexit()
1122 }
1123
1124
1125 func (c *common) Skipped() bool {
1126 c.mu.RLock()
1127 defer c.mu.RUnlock()
1128 return c.skipped
1129 }
1130
1131
1132
1133
1134 func (c *common) Helper() {
1135 c.mu.Lock()
1136 defer c.mu.Unlock()
1137 if c.helperPCs == nil {
1138 c.helperPCs = make(map[uintptr]struct{})
1139 }
1140
1141 var pc [1]uintptr
1142 n := runtime.Callers(2, pc[:])
1143 if n == 0 {
1144 panic("testing: zero callers found")
1145 }
1146 if _, found := c.helperPCs[pc[0]]; !found {
1147 c.helperPCs[pc[0]] = struct{}{}
1148 c.helperNames = nil
1149 }
1150 }
1151
1152
1153
1154
1155 func (c *common) Cleanup(f func()) {
1156 c.checkFuzzFn("Cleanup")
1157 var pc [maxStackLen]uintptr
1158
1159 n := runtime.Callers(2, pc[:])
1160 cleanupPc := pc[:n]
1161
1162 fn := func() {
1163 defer func() {
1164 c.mu.Lock()
1165 defer c.mu.Unlock()
1166 c.cleanupName = ""
1167 c.cleanupPc = nil
1168 }()
1169
1170 name := callerName(0)
1171 c.mu.Lock()
1172 c.cleanupName = name
1173 c.cleanupPc = cleanupPc
1174 c.mu.Unlock()
1175
1176 f()
1177 }
1178
1179 c.mu.Lock()
1180 defer c.mu.Unlock()
1181 c.cleanups = append(c.cleanups, fn)
1182 }
1183
1184
1185
1186
1187
1188
1189 func (c *common) TempDir() string {
1190 c.checkFuzzFn("TempDir")
1191
1192
1193 c.tempDirMu.Lock()
1194 var nonExistent bool
1195 if c.tempDir == "" {
1196 nonExistent = true
1197 } else {
1198 _, err := os.Stat(c.tempDir)
1199 nonExistent = os.IsNotExist(err)
1200 if err != nil && !nonExistent {
1201 c.Fatalf("TempDir: %v", err)
1202 }
1203 }
1204
1205 if nonExistent {
1206 c.Helper()
1207
1208
1209
1210
1211 mapper := func(r rune) rune {
1212 if r < utf8.RuneSelf {
1213 const allowed = "!#$%&()+,-.=@^_{}~ "
1214 if '0' <= r && r <= '9' ||
1215 'a' <= r && r <= 'z' ||
1216 'A' <= r && r <= 'Z' {
1217 return r
1218 }
1219 if strings.ContainsRune(allowed, r) {
1220 return r
1221 }
1222 } else if unicode.IsLetter(r) || unicode.IsNumber(r) {
1223 return r
1224 }
1225 return -1
1226 }
1227 pattern := strings.Map(mapper, c.Name())
1228 c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
1229 if c.tempDirErr == nil {
1230 c.Cleanup(func() {
1231 if err := removeAll(c.tempDir); err != nil {
1232 c.Errorf("TempDir RemoveAll cleanup: %v", err)
1233 }
1234 })
1235 }
1236 }
1237
1238 if c.tempDirErr == nil {
1239 c.tempDirSeq++
1240 }
1241 seq := c.tempDirSeq
1242 c.tempDirMu.Unlock()
1243
1244 if c.tempDirErr != nil {
1245 c.Fatalf("TempDir: %v", c.tempDirErr)
1246 }
1247
1248 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
1249 if err := os.Mkdir(dir, 0777); err != nil {
1250 c.Fatalf("TempDir: %v", err)
1251 }
1252 return dir
1253 }
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264 func removeAll(path string) error {
1265 const arbitraryTimeout = 2 * time.Second
1266 var (
1267 start time.Time
1268 nextSleep = 1 * time.Millisecond
1269 )
1270 for {
1271 err := os.RemoveAll(path)
1272 if !isWindowsRetryable(err) {
1273 return err
1274 }
1275 if start.IsZero() {
1276 start = time.Now()
1277 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
1278 return err
1279 }
1280 time.Sleep(nextSleep)
1281 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
1282 }
1283 }
1284
1285
1286
1287
1288
1289
1290
1291 func (c *common) Setenv(key, value string) {
1292 c.checkFuzzFn("Setenv")
1293 prevValue, ok := os.LookupEnv(key)
1294
1295 if err := os.Setenv(key, value); err != nil {
1296 c.Fatalf("cannot set environment variable: %v", err)
1297 }
1298
1299 if ok {
1300 c.Cleanup(func() {
1301 os.Setenv(key, prevValue)
1302 })
1303 } else {
1304 c.Cleanup(func() {
1305 os.Unsetenv(key)
1306 })
1307 }
1308 }
1309
1310
1311 type panicHandling int
1312
1313 const (
1314 normalPanic panicHandling = iota
1315 recoverAndReturnPanic
1316 )
1317
1318
1319
1320
1321 func (c *common) runCleanup(ph panicHandling) (panicVal any) {
1322 c.cleanupStarted.Store(true)
1323 defer c.cleanupStarted.Store(false)
1324
1325 if ph == recoverAndReturnPanic {
1326 defer func() {
1327 panicVal = recover()
1328 }()
1329 }
1330
1331
1332
1333 defer func() {
1334 c.mu.Lock()
1335 recur := len(c.cleanups) > 0
1336 c.mu.Unlock()
1337 if recur {
1338 c.runCleanup(normalPanic)
1339 }
1340 }()
1341
1342 for {
1343 var cleanup func()
1344 c.mu.Lock()
1345 if len(c.cleanups) > 0 {
1346 last := len(c.cleanups) - 1
1347 cleanup = c.cleanups[last]
1348 c.cleanups = c.cleanups[:last]
1349 }
1350 c.mu.Unlock()
1351 if cleanup == nil {
1352 return nil
1353 }
1354 cleanup()
1355 }
1356 }
1357
1358
1359
1360
1361
1362
1363 func (c *common) resetRaces() {
1364 if c.parent == nil {
1365 c.lastRaceErrors.Store(int64(race.Errors()))
1366 } else {
1367 c.lastRaceErrors.Store(c.parent.checkRaces())
1368 }
1369 }
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381 func (c *common) checkRaces() (raceErrors int64) {
1382 raceErrors = int64(race.Errors())
1383 for {
1384 last := c.lastRaceErrors.Load()
1385 if raceErrors <= last {
1386
1387 return raceErrors
1388 }
1389 if c.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1390 break
1391 }
1392 }
1393
1394 if c.raceErrorLogged.CompareAndSwap(false, true) {
1395
1396
1397
1398
1399 c.Errorf("race detected during execution of test")
1400 }
1401
1402
1403 parent := c.parent
1404 for parent != nil {
1405 for {
1406 last := parent.lastRaceErrors.Load()
1407 if raceErrors <= last {
1408
1409 return raceErrors
1410 }
1411 if parent.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1412 break
1413 }
1414 }
1415 parent = parent.parent
1416 }
1417
1418 return raceErrors
1419 }
1420
1421
1422
1423 func callerName(skip int) string {
1424 var pc [1]uintptr
1425 n := runtime.Callers(skip+2, pc[:])
1426 if n == 0 {
1427 panic("testing: zero callers found")
1428 }
1429 return pcToName(pc[0])
1430 }
1431
1432 func pcToName(pc uintptr) string {
1433 pcs := []uintptr{pc}
1434 frames := runtime.CallersFrames(pcs)
1435 frame, _ := frames.Next()
1436 return frame.Function
1437 }
1438
1439
1440
1441
1442
1443 func (t *T) Parallel() {
1444 if t.isParallel {
1445 panic("testing: t.Parallel called multiple times")
1446 }
1447 if t.isEnvSet {
1448 panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests")
1449 }
1450 t.isParallel = true
1451 if t.parent.barrier == nil {
1452
1453
1454
1455 return
1456 }
1457
1458
1459
1460
1461 t.duration += highPrecisionTimeSince(t.start)
1462
1463
1464 t.parent.sub = append(t.parent.sub, t)
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476 t.checkRaces()
1477
1478 if t.chatty != nil {
1479 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1480 }
1481 running.Delete(t.name)
1482
1483 t.signal <- true
1484 <-t.parent.barrier
1485 t.context.waitParallel()
1486
1487 if t.chatty != nil {
1488 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1489 }
1490 running.Store(t.name, highPrecisionTimeNow())
1491 t.start = highPrecisionTimeNow()
1492
1493
1494
1495
1496
1497
1498
1499
1500 t.lastRaceErrors.Store(int64(race.Errors()))
1501 }
1502
1503
1504
1505
1506
1507
1508
1509 func (t *T) Setenv(key, value string) {
1510
1511
1512
1513
1514
1515 isParallel := false
1516 for c := &t.common; c != nil; c = c.parent {
1517 if c.isParallel {
1518 isParallel = true
1519 break
1520 }
1521 }
1522 if isParallel {
1523 panic("testing: t.Setenv called after t.Parallel; cannot set environment variables in parallel tests")
1524 }
1525
1526 t.isEnvSet = true
1527
1528 t.common.Setenv(key, value)
1529 }
1530
1531
1532
1533 type InternalTest struct {
1534 Name string
1535 F func(*T)
1536 }
1537
1538 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
1539
1540 func tRunner(t *T, fn func(t *T)) {
1541 t.runner = callerName(0)
1542
1543
1544
1545
1546
1547 defer func() {
1548 t.checkRaces()
1549
1550
1551 if t.Failed() {
1552 numFailed.Add(1)
1553 }
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563 err := recover()
1564 signal := true
1565
1566 t.mu.RLock()
1567 finished := t.finished
1568 t.mu.RUnlock()
1569 if !finished && err == nil {
1570 err = errNilPanicOrGoexit
1571 for p := t.parent; p != nil; p = p.parent {
1572 p.mu.RLock()
1573 finished = p.finished
1574 p.mu.RUnlock()
1575 if finished {
1576 if !t.isParallel {
1577 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
1578 err = nil
1579 }
1580 signal = false
1581 break
1582 }
1583 }
1584 }
1585
1586 if err != nil && t.context.isFuzzing {
1587 prefix := "panic: "
1588 if err == errNilPanicOrGoexit {
1589 prefix = ""
1590 }
1591 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
1592 t.mu.Lock()
1593 t.finished = true
1594 t.mu.Unlock()
1595 err = nil
1596 }
1597
1598
1599
1600 didPanic := false
1601 defer func() {
1602
1603
1604
1605 if didPanic {
1606 return
1607 }
1608 if err != nil {
1609 panic(err)
1610 }
1611 running.Delete(t.name)
1612 t.signal <- signal
1613 }()
1614
1615 doPanic := func(err any) {
1616 t.Fail()
1617 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
1618 t.Logf("cleanup panicked with %v", r)
1619 }
1620
1621 for root := &t.common; root.parent != nil; root = root.parent {
1622 root.mu.Lock()
1623 root.duration += highPrecisionTimeSince(root.start)
1624 d := root.duration
1625 root.mu.Unlock()
1626 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
1627 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
1628 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
1629 }
1630 }
1631 didPanic = true
1632 panic(err)
1633 }
1634 if err != nil {
1635 doPanic(err)
1636 }
1637
1638 t.duration += highPrecisionTimeSince(t.start)
1639
1640 if len(t.sub) > 0 {
1641
1642
1643
1644 t.context.release()
1645 running.Delete(t.name)
1646
1647
1648 close(t.barrier)
1649
1650 for _, sub := range t.sub {
1651 <-sub.signal
1652 }
1653
1654
1655
1656 cleanupStart := highPrecisionTimeNow()
1657 running.Store(t.name, cleanupStart)
1658 err := t.runCleanup(recoverAndReturnPanic)
1659 t.duration += highPrecisionTimeSince(cleanupStart)
1660 if err != nil {
1661 doPanic(err)
1662 }
1663 t.checkRaces()
1664 if !t.isParallel {
1665
1666 t.context.waitParallel()
1667 }
1668 } else if t.isParallel {
1669
1670
1671 t.context.release()
1672 }
1673 t.report()
1674
1675
1676
1677 t.done = true
1678 if t.parent != nil && !t.hasSub.Load() {
1679 t.setRan()
1680 }
1681 }()
1682 defer func() {
1683 if len(t.sub) == 0 {
1684 t.runCleanup(normalPanic)
1685 }
1686 }()
1687
1688 t.start = highPrecisionTimeNow()
1689 t.resetRaces()
1690 fn(t)
1691
1692
1693 t.mu.Lock()
1694 t.finished = true
1695 t.mu.Unlock()
1696 }
1697
1698
1699
1700
1701
1702
1703
1704 func (t *T) Run(name string, f func(t *T)) bool {
1705 if t.cleanupStarted.Load() {
1706 panic("testing: t.Run called during t.Cleanup")
1707 }
1708
1709 t.hasSub.Store(true)
1710 testName, ok, _ := t.context.match.fullName(&t.common, name)
1711 if !ok || shouldFailFast() {
1712 return true
1713 }
1714
1715
1716
1717 var pc [maxStackLen]uintptr
1718 n := runtime.Callers(2, pc[:])
1719 t = &T{
1720 common: common{
1721 barrier: make(chan bool),
1722 signal: make(chan bool, 1),
1723 name: testName,
1724 parent: &t.common,
1725 level: t.level + 1,
1726 creator: pc[:n],
1727 chatty: t.chatty,
1728 },
1729 context: t.context,
1730 }
1731 t.w = indenter{&t.common}
1732
1733 if t.chatty != nil {
1734 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
1735 }
1736 running.Store(t.name, highPrecisionTimeNow())
1737
1738
1739
1740
1741
1742
1743 go tRunner(t, f)
1744
1745
1746
1747
1748
1749
1750
1751 if !<-t.signal {
1752
1753
1754 runtime.Goexit()
1755 }
1756
1757 if t.chatty != nil && t.chatty.json {
1758 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
1759 }
1760 return !t.failed
1761 }
1762
1763
1764
1765
1766
1767 func (t *T) Deadline() (deadline time.Time, ok bool) {
1768 deadline = t.context.deadline
1769 return deadline, !deadline.IsZero()
1770 }
1771
1772
1773
1774 type testContext struct {
1775 match *matcher
1776 deadline time.Time
1777
1778
1779
1780
1781
1782 isFuzzing bool
1783
1784 mu sync.Mutex
1785
1786
1787 startParallel chan bool
1788
1789
1790
1791 running int
1792
1793
1794 numWaiting int
1795
1796
1797 maxParallel int
1798 }
1799
1800 func newTestContext(maxParallel int, m *matcher) *testContext {
1801 return &testContext{
1802 match: m,
1803 startParallel: make(chan bool),
1804 maxParallel: maxParallel,
1805 running: 1,
1806 }
1807 }
1808
1809 func (c *testContext) waitParallel() {
1810 c.mu.Lock()
1811 if c.running < c.maxParallel {
1812 c.running++
1813 c.mu.Unlock()
1814 return
1815 }
1816 c.numWaiting++
1817 c.mu.Unlock()
1818 <-c.startParallel
1819 }
1820
1821 func (c *testContext) release() {
1822 c.mu.Lock()
1823 if c.numWaiting == 0 {
1824 c.running--
1825 c.mu.Unlock()
1826 return
1827 }
1828 c.numWaiting--
1829 c.mu.Unlock()
1830 c.startParallel <- true
1831 }
1832
1833
1834
1835 var errMain = errors.New("testing: unexpected use of func Main")
1836
1837 type matchStringOnly func(pat, str string) (bool, error)
1838
1839 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
1840 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
1841 func (f matchStringOnly) StopCPUProfile() {}
1842 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
1843 func (f matchStringOnly) ImportPath() string { return "" }
1844 func (f matchStringOnly) StartTestLog(io.Writer) {}
1845 func (f matchStringOnly) StopTestLog() error { return errMain }
1846 func (f matchStringOnly) SetPanicOnExit0(bool) {}
1847 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
1848 return errMain
1849 }
1850 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
1851 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
1852 return nil, errMain
1853 }
1854 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
1855 func (f matchStringOnly) ResetCoverage() {}
1856 func (f matchStringOnly) SnapshotCoverage() {}
1857
1858
1859
1860
1861
1862
1863
1864 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
1865 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
1866 }
1867
1868
1869 type M struct {
1870 deps testDeps
1871 tests []InternalTest
1872 benchmarks []InternalBenchmark
1873 fuzzTargets []InternalFuzzTarget
1874 examples []InternalExample
1875
1876 timer *time.Timer
1877 afterOnce sync.Once
1878
1879 numRun int
1880
1881
1882
1883 exitCode int
1884 }
1885
1886
1887
1888
1889
1890 type testDeps interface {
1891 ImportPath() string
1892 MatchString(pat, str string) (bool, error)
1893 SetPanicOnExit0(bool)
1894 StartCPUProfile(io.Writer) error
1895 StopCPUProfile()
1896 StartTestLog(io.Writer)
1897 StopTestLog() error
1898 WriteProfileTo(string, io.Writer, int) error
1899 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
1900 RunFuzzWorker(func(corpusEntry) error) error
1901 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
1902 CheckCorpus([]any, []reflect.Type) error
1903 ResetCoverage()
1904 SnapshotCoverage()
1905 }
1906
1907
1908
1909
1910 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
1911 Init()
1912 return &M{
1913 deps: deps,
1914 tests: tests,
1915 benchmarks: benchmarks,
1916 fuzzTargets: fuzzTargets,
1917 examples: examples,
1918 }
1919 }
1920
1921 var testingTesting bool
1922 var realStderr *os.File
1923
1924
1925 func (m *M) Run() (code int) {
1926 defer func() {
1927 code = m.exitCode
1928 }()
1929
1930
1931
1932
1933
1934 m.numRun++
1935
1936
1937 if !flag.Parsed() {
1938 flag.Parse()
1939 }
1940
1941 if chatty.json {
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975 realStderr = os.Stderr
1976 os.Stderr = os.Stdout
1977 }
1978
1979 if *parallel < 1 {
1980 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
1981 flag.Usage()
1982 m.exitCode = 2
1983 return
1984 }
1985 if *matchFuzz != "" && *fuzzCacheDir == "" {
1986 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
1987 flag.Usage()
1988 m.exitCode = 2
1989 return
1990 }
1991
1992 if *matchList != "" {
1993 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
1994 m.exitCode = 0
1995 return
1996 }
1997
1998 if *shuffle != "off" {
1999 var n int64
2000 var err error
2001 if *shuffle == "on" {
2002 n = time.Now().UnixNano()
2003 } else {
2004 n, err = strconv.ParseInt(*shuffle, 10, 64)
2005 if err != nil {
2006 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2007 m.exitCode = 2
2008 return
2009 }
2010 }
2011 fmt.Println("-test.shuffle", n)
2012 rng := rand.New(rand.NewSource(n))
2013 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2014 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2015 }
2016
2017 parseCpuList()
2018
2019 m.before()
2020 defer m.after()
2021
2022
2023
2024
2025 if !*isFuzzWorker {
2026 deadline := m.startAlarm()
2027 haveExamples = len(m.examples) > 0
2028 testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
2029 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2030 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2031 m.stopAlarm()
2032 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2033 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2034 if testingTesting && *match != "^$" {
2035
2036
2037
2038
2039
2040 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2041 testOk = false
2042 }
2043 }
2044 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2045 if !anyFailed && race.Errors() > 0 {
2046 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2047 anyFailed = true
2048 }
2049 if anyFailed {
2050 fmt.Print(chatty.prefix(), "FAIL\n")
2051 m.exitCode = 1
2052 return
2053 }
2054 }
2055
2056 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2057 if !fuzzingOk {
2058 fmt.Print(chatty.prefix(), "FAIL\n")
2059 if *isFuzzWorker {
2060 m.exitCode = fuzzWorkerExitCode
2061 } else {
2062 m.exitCode = 1
2063 }
2064 return
2065 }
2066
2067 m.exitCode = 0
2068 if !*isFuzzWorker {
2069 fmt.Print(chatty.prefix(), "PASS\n")
2070 }
2071 return
2072 }
2073
2074 func (t *T) report() {
2075 if t.parent == nil {
2076 return
2077 }
2078 dstr := fmtDuration(t.duration)
2079 format := "--- %s: %s (%s)\n"
2080 if t.Failed() {
2081 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2082 } else if t.chatty != nil {
2083 if t.Skipped() {
2084 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2085 } else {
2086 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2087 }
2088 }
2089 }
2090
2091 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2092 if _, err := matchString(*matchList, "non-empty"); err != nil {
2093 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2094 os.Exit(1)
2095 }
2096
2097 for _, test := range tests {
2098 if ok, _ := matchString(*matchList, test.Name); ok {
2099 fmt.Println(test.Name)
2100 }
2101 }
2102 for _, bench := range benchmarks {
2103 if ok, _ := matchString(*matchList, bench.Name); ok {
2104 fmt.Println(bench.Name)
2105 }
2106 }
2107 for _, fuzzTarget := range fuzzTargets {
2108 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2109 fmt.Println(fuzzTarget.Name)
2110 }
2111 }
2112 for _, example := range examples {
2113 if ok, _ := matchString(*matchList, example.Name); ok {
2114 fmt.Println(example.Name)
2115 }
2116 }
2117 }
2118
2119
2120
2121 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2122 var deadline time.Time
2123 if *timeout > 0 {
2124 deadline = time.Now().Add(*timeout)
2125 }
2126 ran, ok := runTests(matchString, tests, deadline)
2127 if !ran && !haveExamples {
2128 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2129 }
2130 return ok
2131 }
2132
2133 func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2134 ok = true
2135 for _, procs := range cpuList {
2136 runtime.GOMAXPROCS(procs)
2137 for i := uint(0); i < *count; i++ {
2138 if shouldFailFast() {
2139 break
2140 }
2141 if i > 0 && !ran {
2142
2143
2144
2145 break
2146 }
2147 ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2148 ctx.deadline = deadline
2149 t := &T{
2150 common: common{
2151 signal: make(chan bool, 1),
2152 barrier: make(chan bool),
2153 w: os.Stdout,
2154 },
2155 context: ctx,
2156 }
2157 if Verbose() {
2158 t.chatty = newChattyPrinter(t.w)
2159 }
2160 tRunner(t, func(t *T) {
2161 for _, test := range tests {
2162 t.Run(test.Name, test.F)
2163 }
2164 })
2165 select {
2166 case <-t.signal:
2167 default:
2168 panic("internal error: tRunner exited without sending on t.signal")
2169 }
2170 ok = ok && !t.Failed()
2171 ran = ran || t.ran
2172 }
2173 }
2174 return ran, ok
2175 }
2176
2177
2178 func (m *M) before() {
2179 if *memProfileRate > 0 {
2180 runtime.MemProfileRate = *memProfileRate
2181 }
2182 if *cpuProfile != "" {
2183 f, err := os.Create(toOutputDir(*cpuProfile))
2184 if err != nil {
2185 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2186 return
2187 }
2188 if err := m.deps.StartCPUProfile(f); err != nil {
2189 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2190 f.Close()
2191 return
2192 }
2193
2194 }
2195 if *traceFile != "" {
2196 f, err := os.Create(toOutputDir(*traceFile))
2197 if err != nil {
2198 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2199 return
2200 }
2201 if err := trace.Start(f); err != nil {
2202 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2203 f.Close()
2204 return
2205 }
2206
2207 }
2208 if *blockProfile != "" && *blockProfileRate >= 0 {
2209 runtime.SetBlockProfileRate(*blockProfileRate)
2210 }
2211 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2212 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2213 }
2214 if *coverProfile != "" && CoverMode() == "" {
2215 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2216 os.Exit(2)
2217 }
2218 if *gocoverdir != "" && CoverMode() == "" {
2219 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2220 os.Exit(2)
2221 }
2222 if *testlog != "" {
2223
2224
2225 var f *os.File
2226 var err error
2227 if m.numRun == 1 {
2228 f, err = os.Create(*testlog)
2229 } else {
2230 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2231 if err == nil {
2232 f.Seek(0, io.SeekEnd)
2233 }
2234 }
2235 if err != nil {
2236 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2237 os.Exit(2)
2238 }
2239 m.deps.StartTestLog(f)
2240 testlogFile = f
2241 }
2242 if *panicOnExit0 {
2243 m.deps.SetPanicOnExit0(true)
2244 }
2245 }
2246
2247
2248 func (m *M) after() {
2249 m.afterOnce.Do(func() {
2250 m.writeProfiles()
2251 })
2252
2253
2254
2255
2256 if *panicOnExit0 {
2257 m.deps.SetPanicOnExit0(false)
2258 }
2259 }
2260
2261 func (m *M) writeProfiles() {
2262 if *testlog != "" {
2263 if err := m.deps.StopTestLog(); err != nil {
2264 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2265 os.Exit(2)
2266 }
2267 if err := testlogFile.Close(); err != nil {
2268 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2269 os.Exit(2)
2270 }
2271 }
2272 if *cpuProfile != "" {
2273 m.deps.StopCPUProfile()
2274 }
2275 if *traceFile != "" {
2276 trace.Stop()
2277 }
2278 if *memProfile != "" {
2279 f, err := os.Create(toOutputDir(*memProfile))
2280 if err != nil {
2281 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2282 os.Exit(2)
2283 }
2284 runtime.GC()
2285 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2286 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2287 os.Exit(2)
2288 }
2289 f.Close()
2290 }
2291 if *blockProfile != "" && *blockProfileRate >= 0 {
2292 f, err := os.Create(toOutputDir(*blockProfile))
2293 if err != nil {
2294 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2295 os.Exit(2)
2296 }
2297 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2298 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2299 os.Exit(2)
2300 }
2301 f.Close()
2302 }
2303 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2304 f, err := os.Create(toOutputDir(*mutexProfile))
2305 if err != nil {
2306 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2307 os.Exit(2)
2308 }
2309 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2310 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2311 os.Exit(2)
2312 }
2313 f.Close()
2314 }
2315 if CoverMode() != "" {
2316 coverReport()
2317 }
2318 }
2319
2320
2321
2322 func toOutputDir(path string) string {
2323 if *outputDir == "" || path == "" {
2324 return path
2325 }
2326
2327
2328
2329
2330
2331
2332
2333 if runtime.GOOS == "windows" && len(path) >= 2 {
2334 letter, colon := path[0], path[1]
2335 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2336
2337 return path
2338 }
2339 }
2340 if os.IsPathSeparator(path[0]) {
2341 return path
2342 }
2343 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2344 }
2345
2346
2347 func (m *M) startAlarm() time.Time {
2348 if *timeout <= 0 {
2349 return time.Time{}
2350 }
2351
2352 deadline := time.Now().Add(*timeout)
2353 m.timer = time.AfterFunc(*timeout, func() {
2354 m.after()
2355 debug.SetTraceback("all")
2356 extra := ""
2357
2358 if list := runningList(); len(list) > 0 {
2359 var b strings.Builder
2360 b.WriteString("\nrunning tests:")
2361 for _, name := range list {
2362 b.WriteString("\n\t")
2363 b.WriteString(name)
2364 }
2365 extra = b.String()
2366 }
2367 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2368 })
2369 return deadline
2370 }
2371
2372
2373 func runningList() []string {
2374 var list []string
2375 running.Range(func(k, v any) bool {
2376 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2377 return true
2378 })
2379 sort.Strings(list)
2380 return list
2381 }
2382
2383
2384 func (m *M) stopAlarm() {
2385 if *timeout > 0 {
2386 m.timer.Stop()
2387 }
2388 }
2389
2390 func parseCpuList() {
2391 for _, val := range strings.Split(*cpuListStr, ",") {
2392 val = strings.TrimSpace(val)
2393 if val == "" {
2394 continue
2395 }
2396 cpu, err := strconv.Atoi(val)
2397 if err != nil || cpu <= 0 {
2398 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2399 os.Exit(1)
2400 }
2401 cpuList = append(cpuList, cpu)
2402 }
2403 if cpuList == nil {
2404 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2405 }
2406 }
2407
2408 func shouldFailFast() bool {
2409 return *failFast && numFailed.Load() > 0
2410 }
2411
View as plain text