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 "slices"
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 func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
1859 return
1860 }
1861
1862
1863
1864
1865
1866
1867
1868 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
1869 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
1870 }
1871
1872
1873 type M struct {
1874 deps testDeps
1875 tests []InternalTest
1876 benchmarks []InternalBenchmark
1877 fuzzTargets []InternalFuzzTarget
1878 examples []InternalExample
1879
1880 timer *time.Timer
1881 afterOnce sync.Once
1882
1883 numRun int
1884
1885
1886
1887 exitCode int
1888 }
1889
1890
1891
1892
1893
1894 type testDeps interface {
1895 ImportPath() string
1896 MatchString(pat, str string) (bool, error)
1897 SetPanicOnExit0(bool)
1898 StartCPUProfile(io.Writer) error
1899 StopCPUProfile()
1900 StartTestLog(io.Writer)
1901 StopTestLog() error
1902 WriteProfileTo(string, io.Writer, int) error
1903 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
1904 RunFuzzWorker(func(corpusEntry) error) error
1905 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
1906 CheckCorpus([]any, []reflect.Type) error
1907 ResetCoverage()
1908 SnapshotCoverage()
1909 InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
1910 }
1911
1912
1913
1914
1915 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
1916 registerCover2(deps.InitRuntimeCoverage())
1917 Init()
1918 return &M{
1919 deps: deps,
1920 tests: tests,
1921 benchmarks: benchmarks,
1922 fuzzTargets: fuzzTargets,
1923 examples: examples,
1924 }
1925 }
1926
1927 var testingTesting bool
1928 var realStderr *os.File
1929
1930
1931 func (m *M) Run() (code int) {
1932 defer func() {
1933 code = m.exitCode
1934 }()
1935
1936
1937
1938
1939
1940 m.numRun++
1941
1942
1943 if !flag.Parsed() {
1944 flag.Parse()
1945 }
1946
1947 if chatty.json {
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
1976
1977
1978
1979
1980
1981 realStderr = os.Stderr
1982 os.Stderr = os.Stdout
1983 }
1984
1985 if *parallel < 1 {
1986 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
1987 flag.Usage()
1988 m.exitCode = 2
1989 return
1990 }
1991 if *matchFuzz != "" && *fuzzCacheDir == "" {
1992 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
1993 flag.Usage()
1994 m.exitCode = 2
1995 return
1996 }
1997
1998 if *matchList != "" {
1999 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
2000 m.exitCode = 0
2001 return
2002 }
2003
2004 if *shuffle != "off" {
2005 var n int64
2006 var err error
2007 if *shuffle == "on" {
2008 n = time.Now().UnixNano()
2009 } else {
2010 n, err = strconv.ParseInt(*shuffle, 10, 64)
2011 if err != nil {
2012 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2013 m.exitCode = 2
2014 return
2015 }
2016 }
2017 fmt.Println("-test.shuffle", n)
2018 rng := rand.New(rand.NewSource(n))
2019 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2020 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2021 }
2022
2023 parseCpuList()
2024
2025 m.before()
2026 defer m.after()
2027
2028
2029
2030
2031 if !*isFuzzWorker {
2032 deadline := m.startAlarm()
2033 haveExamples = len(m.examples) > 0
2034 testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
2035 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2036 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2037 m.stopAlarm()
2038 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2039 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2040 if testingTesting && *match != "^$" {
2041
2042
2043
2044
2045
2046 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2047 testOk = false
2048 }
2049 }
2050 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2051 if !anyFailed && race.Errors() > 0 {
2052 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2053 anyFailed = true
2054 }
2055 if anyFailed {
2056 fmt.Print(chatty.prefix(), "FAIL\n")
2057 m.exitCode = 1
2058 return
2059 }
2060 }
2061
2062 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2063 if !fuzzingOk {
2064 fmt.Print(chatty.prefix(), "FAIL\n")
2065 if *isFuzzWorker {
2066 m.exitCode = fuzzWorkerExitCode
2067 } else {
2068 m.exitCode = 1
2069 }
2070 return
2071 }
2072
2073 m.exitCode = 0
2074 if !*isFuzzWorker {
2075 fmt.Print(chatty.prefix(), "PASS\n")
2076 }
2077 return
2078 }
2079
2080 func (t *T) report() {
2081 if t.parent == nil {
2082 return
2083 }
2084 dstr := fmtDuration(t.duration)
2085 format := "--- %s: %s (%s)\n"
2086 if t.Failed() {
2087 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2088 } else if t.chatty != nil {
2089 if t.Skipped() {
2090 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2091 } else {
2092 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2093 }
2094 }
2095 }
2096
2097 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2098 if _, err := matchString(*matchList, "non-empty"); err != nil {
2099 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2100 os.Exit(1)
2101 }
2102
2103 for _, test := range tests {
2104 if ok, _ := matchString(*matchList, test.Name); ok {
2105 fmt.Println(test.Name)
2106 }
2107 }
2108 for _, bench := range benchmarks {
2109 if ok, _ := matchString(*matchList, bench.Name); ok {
2110 fmt.Println(bench.Name)
2111 }
2112 }
2113 for _, fuzzTarget := range fuzzTargets {
2114 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2115 fmt.Println(fuzzTarget.Name)
2116 }
2117 }
2118 for _, example := range examples {
2119 if ok, _ := matchString(*matchList, example.Name); ok {
2120 fmt.Println(example.Name)
2121 }
2122 }
2123 }
2124
2125
2126
2127 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2128 var deadline time.Time
2129 if *timeout > 0 {
2130 deadline = time.Now().Add(*timeout)
2131 }
2132 ran, ok := runTests(matchString, tests, deadline)
2133 if !ran && !haveExamples {
2134 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2135 }
2136 return ok
2137 }
2138
2139 func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2140 ok = true
2141 for _, procs := range cpuList {
2142 runtime.GOMAXPROCS(procs)
2143 for i := uint(0); i < *count; i++ {
2144 if shouldFailFast() {
2145 break
2146 }
2147 if i > 0 && !ran {
2148
2149
2150
2151 break
2152 }
2153 ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2154 ctx.deadline = deadline
2155 t := &T{
2156 common: common{
2157 signal: make(chan bool, 1),
2158 barrier: make(chan bool),
2159 w: os.Stdout,
2160 },
2161 context: ctx,
2162 }
2163 if Verbose() {
2164 t.chatty = newChattyPrinter(t.w)
2165 }
2166 tRunner(t, func(t *T) {
2167 for _, test := range tests {
2168 t.Run(test.Name, test.F)
2169 }
2170 })
2171 select {
2172 case <-t.signal:
2173 default:
2174 panic("internal error: tRunner exited without sending on t.signal")
2175 }
2176 ok = ok && !t.Failed()
2177 ran = ran || t.ran
2178 }
2179 }
2180 return ran, ok
2181 }
2182
2183
2184 func (m *M) before() {
2185 if *memProfileRate > 0 {
2186 runtime.MemProfileRate = *memProfileRate
2187 }
2188 if *cpuProfile != "" {
2189 f, err := os.Create(toOutputDir(*cpuProfile))
2190 if err != nil {
2191 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2192 return
2193 }
2194 if err := m.deps.StartCPUProfile(f); err != nil {
2195 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2196 f.Close()
2197 return
2198 }
2199
2200 }
2201 if *traceFile != "" {
2202 f, err := os.Create(toOutputDir(*traceFile))
2203 if err != nil {
2204 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2205 return
2206 }
2207 if err := trace.Start(f); err != nil {
2208 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2209 f.Close()
2210 return
2211 }
2212
2213 }
2214 if *blockProfile != "" && *blockProfileRate >= 0 {
2215 runtime.SetBlockProfileRate(*blockProfileRate)
2216 }
2217 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2218 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2219 }
2220 if *coverProfile != "" && CoverMode() == "" {
2221 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2222 os.Exit(2)
2223 }
2224 if *gocoverdir != "" && CoverMode() == "" {
2225 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2226 os.Exit(2)
2227 }
2228 if *testlog != "" {
2229
2230
2231 var f *os.File
2232 var err error
2233 if m.numRun == 1 {
2234 f, err = os.Create(*testlog)
2235 } else {
2236 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2237 if err == nil {
2238 f.Seek(0, io.SeekEnd)
2239 }
2240 }
2241 if err != nil {
2242 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2243 os.Exit(2)
2244 }
2245 m.deps.StartTestLog(f)
2246 testlogFile = f
2247 }
2248 if *panicOnExit0 {
2249 m.deps.SetPanicOnExit0(true)
2250 }
2251 }
2252
2253
2254 func (m *M) after() {
2255 m.afterOnce.Do(func() {
2256 m.writeProfiles()
2257 })
2258
2259
2260
2261
2262 if *panicOnExit0 {
2263 m.deps.SetPanicOnExit0(false)
2264 }
2265 }
2266
2267 func (m *M) writeProfiles() {
2268 if *testlog != "" {
2269 if err := m.deps.StopTestLog(); err != nil {
2270 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2271 os.Exit(2)
2272 }
2273 if err := testlogFile.Close(); err != nil {
2274 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2275 os.Exit(2)
2276 }
2277 }
2278 if *cpuProfile != "" {
2279 m.deps.StopCPUProfile()
2280 }
2281 if *traceFile != "" {
2282 trace.Stop()
2283 }
2284 if *memProfile != "" {
2285 f, err := os.Create(toOutputDir(*memProfile))
2286 if err != nil {
2287 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2288 os.Exit(2)
2289 }
2290 runtime.GC()
2291 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2292 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2293 os.Exit(2)
2294 }
2295 f.Close()
2296 }
2297 if *blockProfile != "" && *blockProfileRate >= 0 {
2298 f, err := os.Create(toOutputDir(*blockProfile))
2299 if err != nil {
2300 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2301 os.Exit(2)
2302 }
2303 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2304 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2305 os.Exit(2)
2306 }
2307 f.Close()
2308 }
2309 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2310 f, err := os.Create(toOutputDir(*mutexProfile))
2311 if err != nil {
2312 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2313 os.Exit(2)
2314 }
2315 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2316 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2317 os.Exit(2)
2318 }
2319 f.Close()
2320 }
2321 if CoverMode() != "" {
2322 coverReport()
2323 }
2324 }
2325
2326
2327
2328 func toOutputDir(path string) string {
2329 if *outputDir == "" || path == "" {
2330 return path
2331 }
2332
2333
2334
2335
2336
2337
2338
2339 if runtime.GOOS == "windows" && len(path) >= 2 {
2340 letter, colon := path[0], path[1]
2341 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2342
2343 return path
2344 }
2345 }
2346 if os.IsPathSeparator(path[0]) {
2347 return path
2348 }
2349 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2350 }
2351
2352
2353 func (m *M) startAlarm() time.Time {
2354 if *timeout <= 0 {
2355 return time.Time{}
2356 }
2357
2358 deadline := time.Now().Add(*timeout)
2359 m.timer = time.AfterFunc(*timeout, func() {
2360 m.after()
2361 debug.SetTraceback("all")
2362 extra := ""
2363
2364 if list := runningList(); len(list) > 0 {
2365 var b strings.Builder
2366 b.WriteString("\nrunning tests:")
2367 for _, name := range list {
2368 b.WriteString("\n\t")
2369 b.WriteString(name)
2370 }
2371 extra = b.String()
2372 }
2373 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2374 })
2375 return deadline
2376 }
2377
2378
2379 func runningList() []string {
2380 var list []string
2381 running.Range(func(k, v any) bool {
2382 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2383 return true
2384 })
2385 slices.Sort(list)
2386 return list
2387 }
2388
2389
2390 func (m *M) stopAlarm() {
2391 if *timeout > 0 {
2392 m.timer.Stop()
2393 }
2394 }
2395
2396 func parseCpuList() {
2397 for _, val := range strings.Split(*cpuListStr, ",") {
2398 val = strings.TrimSpace(val)
2399 if val == "" {
2400 continue
2401 }
2402 cpu, err := strconv.Atoi(val)
2403 if err != nil || cpu <= 0 {
2404 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2405 os.Exit(1)
2406 }
2407 cpuList = append(cpuList, cpu)
2408 }
2409 if cpuList == nil {
2410 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2411 }
2412 }
2413
2414 func shouldFailFast() bool {
2415 return *failFast && numFailed.Load() > 0
2416 }
2417
View as plain text