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