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