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