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