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 func (c *common) TempDir() string {
1322 c.checkFuzzFn("TempDir")
1323
1324
1325 c.tempDirMu.Lock()
1326 var nonExistent bool
1327 if c.tempDir == "" {
1328 nonExistent = true
1329 } else {
1330 _, err := os.Stat(c.tempDir)
1331 nonExistent = os.IsNotExist(err)
1332 if err != nil && !nonExistent {
1333 c.Fatalf("TempDir: %v", err)
1334 }
1335 }
1336
1337 if nonExistent {
1338 c.Helper()
1339
1340 pattern := c.Name()
1341
1342
1343 pattern = pattern[:min(len(pattern), 64)]
1344
1345
1346
1347
1348 mapper := func(r rune) rune {
1349 if r < utf8.RuneSelf {
1350 const allowed = "!#$%&()+,-.=@^_{}~ "
1351 if '0' <= r && r <= '9' ||
1352 'a' <= r && r <= 'z' ||
1353 'A' <= r && r <= 'Z' {
1354 return r
1355 }
1356 if strings.ContainsRune(allowed, r) {
1357 return r
1358 }
1359 } else if unicode.IsLetter(r) || unicode.IsNumber(r) {
1360 return r
1361 }
1362 return -1
1363 }
1364 pattern = strings.Map(mapper, pattern)
1365 c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
1366 if c.tempDirErr == nil {
1367 c.Cleanup(func() {
1368 if err := removeAll(c.tempDir); err != nil {
1369 c.Errorf("TempDir RemoveAll cleanup: %v", err)
1370 }
1371 })
1372 }
1373 }
1374
1375 if c.tempDirErr == nil {
1376 c.tempDirSeq++
1377 }
1378 seq := c.tempDirSeq
1379 c.tempDirMu.Unlock()
1380
1381 if c.tempDirErr != nil {
1382 c.Fatalf("TempDir: %v", c.tempDirErr)
1383 }
1384
1385 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
1386 if err := os.Mkdir(dir, 0o777); err != nil {
1387 c.Fatalf("TempDir: %v", err)
1388 }
1389 return dir
1390 }
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 func removeAll(path string) error {
1402 const arbitraryTimeout = 2 * time.Second
1403 var (
1404 start time.Time
1405 nextSleep = 1 * time.Millisecond
1406 )
1407 for {
1408 err := os.RemoveAll(path)
1409 if !isWindowsRetryable(err) {
1410 return err
1411 }
1412 if start.IsZero() {
1413 start = time.Now()
1414 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
1415 return err
1416 }
1417 time.Sleep(nextSleep)
1418 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
1419 }
1420 }
1421
1422
1423
1424
1425
1426
1427
1428 func (c *common) Setenv(key, value string) {
1429 c.checkFuzzFn("Setenv")
1430 prevValue, ok := os.LookupEnv(key)
1431
1432 if err := os.Setenv(key, value); err != nil {
1433 c.Fatalf("cannot set environment variable: %v", err)
1434 }
1435
1436 if ok {
1437 c.Cleanup(func() {
1438 os.Setenv(key, prevValue)
1439 })
1440 } else {
1441 c.Cleanup(func() {
1442 os.Unsetenv(key)
1443 })
1444 }
1445 }
1446
1447
1448
1449
1450
1451
1452
1453 func (c *common) Chdir(dir string) {
1454 c.checkFuzzFn("Chdir")
1455 oldwd, err := os.Open(".")
1456 if err != nil {
1457 c.Fatal(err)
1458 }
1459 if err := os.Chdir(dir); err != nil {
1460 c.Fatal(err)
1461 }
1462
1463
1464
1465 switch runtime.GOOS {
1466 case "windows", "plan9":
1467
1468 default:
1469 if !filepath.IsAbs(dir) {
1470 dir, err = os.Getwd()
1471 if err != nil {
1472 c.Fatal(err)
1473 }
1474 }
1475 c.Setenv("PWD", dir)
1476 }
1477 c.Cleanup(func() {
1478 err := oldwd.Chdir()
1479 oldwd.Close()
1480 if err != nil {
1481
1482
1483
1484 panic("testing.Chdir: " + err.Error())
1485 }
1486 })
1487 }
1488
1489
1490
1491
1492
1493
1494 func (c *common) Context() context.Context {
1495 c.checkFuzzFn("Context")
1496 return c.ctx
1497 }
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509 func (c *common) Attr(key, value string) {
1510 if strings.ContainsFunc(key, unicode.IsSpace) {
1511 c.Errorf("disallowed whitespace in attribute key %q", key)
1512 return
1513 }
1514 if strings.ContainsAny(value, "\r\n") {
1515 c.Errorf("disallowed newline in attribute value %q", value)
1516 return
1517 }
1518 if c.chatty == nil {
1519 return
1520 }
1521 c.chatty.Updatef(c.name, "=== ATTR %s %v %v\n", c.name, key, value)
1522 }
1523
1524
1525 type panicHandling int
1526
1527 const (
1528 normalPanic panicHandling = iota
1529 recoverAndReturnPanic
1530 )
1531
1532
1533
1534
1535 func (c *common) runCleanup(ph panicHandling) (panicVal any) {
1536 c.cleanupStarted.Store(true)
1537 defer c.cleanupStarted.Store(false)
1538
1539 if ph == recoverAndReturnPanic {
1540 defer func() {
1541 panicVal = recover()
1542 }()
1543 }
1544
1545
1546
1547 defer func() {
1548 c.mu.Lock()
1549 recur := len(c.cleanups) > 0
1550 c.mu.Unlock()
1551 if recur {
1552 c.runCleanup(normalPanic)
1553 }
1554 }()
1555
1556 if c.cancelCtx != nil {
1557 c.cancelCtx()
1558 }
1559
1560 for {
1561 var cleanup func()
1562 c.mu.Lock()
1563 if len(c.cleanups) > 0 {
1564 last := len(c.cleanups) - 1
1565 cleanup = c.cleanups[last]
1566 c.cleanups = c.cleanups[:last]
1567 }
1568 c.mu.Unlock()
1569 if cleanup == nil {
1570 return nil
1571 }
1572 cleanup()
1573 }
1574 }
1575
1576
1577
1578
1579
1580
1581 func (c *common) resetRaces() {
1582 if c.parent == nil {
1583 c.lastRaceErrors.Store(int64(race.Errors()))
1584 } else {
1585 c.lastRaceErrors.Store(c.parent.checkRaces())
1586 }
1587 }
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599 func (c *common) checkRaces() (raceErrors int64) {
1600 raceErrors = int64(race.Errors())
1601 for {
1602 last := c.lastRaceErrors.Load()
1603 if raceErrors <= last {
1604
1605 return raceErrors
1606 }
1607 if c.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1608 break
1609 }
1610 }
1611
1612 if c.raceErrorLogged.CompareAndSwap(false, true) {
1613
1614
1615
1616
1617 c.Errorf("race detected during execution of test")
1618 }
1619
1620
1621 parent := c.parent
1622 for parent != nil {
1623 for {
1624 last := parent.lastRaceErrors.Load()
1625 if raceErrors <= last {
1626
1627 return raceErrors
1628 }
1629 if parent.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1630 break
1631 }
1632 }
1633 parent = parent.parent
1634 }
1635
1636 return raceErrors
1637 }
1638
1639
1640
1641 func callerName(skip int) string {
1642 var pc [1]uintptr
1643 n := runtime.Callers(skip+2, pc[:])
1644 if n == 0 {
1645 panic("testing: zero callers found")
1646 }
1647 return pcToName(pc[0])
1648 }
1649
1650 func pcToName(pc uintptr) string {
1651 pcs := []uintptr{pc}
1652 frames := runtime.CallersFrames(pcs)
1653 frame, _ := frames.Next()
1654 return frame.Function
1655 }
1656
1657 const parallelConflict = `testing: test using t.Setenv or t.Chdir can not use t.Parallel`
1658
1659
1660
1661
1662
1663 func (t *T) Parallel() {
1664 if t.isParallel {
1665 panic("testing: t.Parallel called multiple times")
1666 }
1667 if t.isSynctest {
1668 panic("testing: t.Parallel called inside synctest bubble")
1669 }
1670 if t.denyParallel {
1671 panic(parallelConflict)
1672 }
1673 if t.parent.barrier == nil {
1674
1675
1676
1677 return
1678 }
1679
1680 t.isParallel = true
1681
1682
1683
1684
1685 t.duration += highPrecisionTimeSince(t.start)
1686
1687
1688 t.parent.sub = append(t.parent.sub, t)
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700 t.checkRaces()
1701
1702 if t.chatty != nil {
1703 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1704 }
1705 running.Delete(t.name)
1706
1707 t.signal <- true
1708 <-t.parent.barrier
1709 t.tstate.waitParallel()
1710 parallelStart.Add(1)
1711
1712 if t.chatty != nil {
1713 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1714 }
1715 running.Store(t.name, highPrecisionTimeNow())
1716 t.start = highPrecisionTimeNow()
1717
1718
1719
1720
1721
1722
1723
1724
1725 t.lastRaceErrors.Store(int64(race.Errors()))
1726 }
1727
1728 func (t *T) checkParallel() {
1729
1730
1731
1732
1733
1734 for c := &t.common; c != nil; c = c.parent {
1735 if c.isParallel {
1736 panic(parallelConflict)
1737 }
1738 }
1739
1740 t.denyParallel = true
1741 }
1742
1743
1744
1745
1746
1747
1748
1749 func (t *T) Setenv(key, value string) {
1750 t.checkParallel()
1751 t.common.Setenv(key, value)
1752 }
1753
1754
1755
1756
1757
1758
1759
1760 func (t *T) Chdir(dir string) {
1761 t.checkParallel()
1762 t.common.Chdir(dir)
1763 }
1764
1765
1766
1767 type InternalTest struct {
1768 Name string
1769 F func(*T)
1770 }
1771
1772 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
1773
1774 func tRunner(t *T, fn func(t *T)) {
1775 t.runner = callerName(0)
1776
1777
1778
1779
1780
1781 defer func() {
1782 t.checkRaces()
1783
1784
1785 if t.Failed() {
1786 numFailed.Add(1)
1787 }
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797 err := recover()
1798 signal := true
1799
1800 t.mu.RLock()
1801 finished := t.finished
1802 t.mu.RUnlock()
1803 if !finished && err == nil {
1804 err = errNilPanicOrGoexit
1805 for p := t.parent; p != nil; p = p.parent {
1806 p.mu.RLock()
1807 finished = p.finished
1808 p.mu.RUnlock()
1809 if finished {
1810 if !t.isParallel {
1811 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
1812 err = nil
1813 }
1814 signal = false
1815 break
1816 }
1817 }
1818 }
1819
1820 if err != nil && t.tstate.isFuzzing {
1821 prefix := "panic: "
1822 if err == errNilPanicOrGoexit {
1823 prefix = ""
1824 }
1825 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
1826 t.mu.Lock()
1827 t.finished = true
1828 t.mu.Unlock()
1829 err = nil
1830 }
1831
1832
1833
1834 didPanic := false
1835 defer func() {
1836
1837
1838
1839 if didPanic {
1840 return
1841 }
1842 if err != nil {
1843 panic(err)
1844 }
1845 running.Delete(t.name)
1846 if t.isParallel {
1847 parallelStop.Add(1)
1848 }
1849 t.signal <- signal
1850 }()
1851
1852 doPanic := func(err any) {
1853 t.Fail()
1854 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
1855 t.Logf("cleanup panicked with %v", r)
1856 }
1857
1858
1859 for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent {
1860 root.mu.Lock()
1861 root.duration += highPrecisionTimeSince(root.start)
1862 d := root.duration
1863 root.mu.Unlock()
1864
1865 root.flushPartial()
1866 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
1867 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
1868 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
1869 }
1870 }
1871 didPanic = true
1872 panic(err)
1873 }
1874 if err != nil {
1875 doPanic(err)
1876 }
1877
1878 t.duration += highPrecisionTimeSince(t.start)
1879
1880 if len(t.sub) > 0 {
1881
1882
1883
1884 t.tstate.release()
1885 running.Delete(t.name)
1886
1887
1888 close(t.barrier)
1889
1890 for _, sub := range t.sub {
1891 <-sub.signal
1892 }
1893
1894
1895
1896 cleanupStart := highPrecisionTimeNow()
1897 running.Store(t.name, cleanupStart)
1898 err := t.runCleanup(recoverAndReturnPanic)
1899 t.duration += highPrecisionTimeSince(cleanupStart)
1900 if err != nil {
1901 doPanic(err)
1902 }
1903 t.checkRaces()
1904 if !t.isParallel {
1905
1906 t.tstate.waitParallel()
1907 }
1908 } else if t.isParallel {
1909
1910
1911 t.tstate.release()
1912 }
1913
1914 for root := &t.common; root.parent != nil; root = root.parent {
1915 root.flushPartial()
1916 }
1917 t.report()
1918
1919
1920
1921 t.done = true
1922 if t.parent != nil && !t.hasSub.Load() {
1923 t.setRan()
1924 }
1925 }()
1926 defer func() {
1927 if len(t.sub) == 0 {
1928 t.runCleanup(normalPanic)
1929 }
1930 }()
1931
1932 t.start = highPrecisionTimeNow()
1933 t.resetRaces()
1934 fn(t)
1935
1936
1937 t.mu.Lock()
1938 t.finished = true
1939 t.mu.Unlock()
1940 }
1941
1942
1943
1944
1945
1946
1947
1948 func (t *T) Run(name string, f func(t *T)) bool {
1949 if t.isSynctest {
1950 panic("testing: t.Run called inside synctest bubble")
1951 }
1952 if t.cleanupStarted.Load() {
1953 panic("testing: t.Run called during t.Cleanup")
1954 }
1955
1956 t.hasSub.Store(true)
1957 testName, ok, _ := t.tstate.match.fullName(&t.common, name)
1958 if !ok || shouldFailFast() {
1959 return true
1960 }
1961
1962
1963
1964 var pc [maxStackLen]uintptr
1965 n := runtime.Callers(2, pc[:])
1966
1967
1968
1969 ctx, cancelCtx := context.WithCancel(context.Background())
1970 t = &T{
1971 common: common{
1972 barrier: make(chan bool),
1973 signal: make(chan bool, 1),
1974 name: testName,
1975 parent: &t.common,
1976 level: t.level + 1,
1977 creator: pc[:n],
1978 chatty: t.chatty,
1979 ctx: ctx,
1980 cancelCtx: cancelCtx,
1981 },
1982 tstate: t.tstate,
1983 }
1984 t.w = indenter{&t.common}
1985 t.setOutputWriter()
1986
1987 if t.chatty != nil {
1988 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
1989 }
1990 running.Store(t.name, highPrecisionTimeNow())
1991
1992
1993
1994
1995
1996
1997 go tRunner(t, f)
1998
1999
2000
2001
2002
2003
2004
2005 if !<-t.signal {
2006
2007
2008 runtime.Goexit()
2009 }
2010
2011 if t.chatty != nil && t.chatty.json {
2012 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
2013 }
2014 return !t.failed
2015 }
2016
2017
2018
2019
2020
2021 func testingSynctestTest(t *T, f func(*T)) (ok bool) {
2022 if t.cleanupStarted.Load() {
2023 panic("testing: synctest.Run called during t.Cleanup")
2024 }
2025
2026 var pc [maxStackLen]uintptr
2027 n := runtime.Callers(2, pc[:])
2028
2029 ctx, cancelCtx := context.WithCancel(context.Background())
2030 t2 := &T{
2031 common: common{
2032 barrier: make(chan bool),
2033 signal: make(chan bool, 1),
2034 name: t.name,
2035 parent: &t.common,
2036 level: t.level + 1,
2037 creator: pc[:n],
2038 chatty: t.chatty,
2039 ctx: ctx,
2040 cancelCtx: cancelCtx,
2041 isSynctest: true,
2042 },
2043 tstate: t.tstate,
2044 }
2045
2046 go tRunner(t2, f)
2047 if !<-t2.signal {
2048
2049
2050 runtime.Goexit()
2051 }
2052 return !t2.failed
2053 }
2054
2055
2056
2057
2058
2059 func (t *T) Deadline() (deadline time.Time, ok bool) {
2060 if t.isSynctest {
2061
2062
2063
2064 panic("testing: t.Deadline called inside synctest bubble")
2065 }
2066 deadline = t.tstate.deadline
2067 return deadline, !deadline.IsZero()
2068 }
2069
2070
2071
2072 type testState struct {
2073 match *matcher
2074 deadline time.Time
2075
2076
2077
2078
2079
2080 isFuzzing bool
2081
2082 mu sync.Mutex
2083
2084
2085 startParallel chan bool
2086
2087
2088
2089 running int
2090
2091
2092 numWaiting int
2093
2094
2095 maxParallel int
2096 }
2097
2098 func newTestState(maxParallel int, m *matcher) *testState {
2099 return &testState{
2100 match: m,
2101 startParallel: make(chan bool),
2102 maxParallel: maxParallel,
2103 running: 1,
2104 }
2105 }
2106
2107 func (s *testState) waitParallel() {
2108 s.mu.Lock()
2109 if s.running < s.maxParallel {
2110 s.running++
2111 s.mu.Unlock()
2112 return
2113 }
2114 s.numWaiting++
2115 s.mu.Unlock()
2116 <-s.startParallel
2117 }
2118
2119 func (s *testState) release() {
2120 s.mu.Lock()
2121 if s.numWaiting == 0 {
2122 s.running--
2123 s.mu.Unlock()
2124 return
2125 }
2126 s.numWaiting--
2127 s.mu.Unlock()
2128 s.startParallel <- true
2129 }
2130
2131
2132
2133 var errMain = errors.New("testing: unexpected use of func Main")
2134
2135 type matchStringOnly func(pat, str string) (bool, error)
2136
2137 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
2138 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
2139 func (f matchStringOnly) StopCPUProfile() {}
2140 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
2141 func (f matchStringOnly) ImportPath() string { return "" }
2142 func (f matchStringOnly) StartTestLog(io.Writer) {}
2143 func (f matchStringOnly) StopTestLog() error { return errMain }
2144 func (f matchStringOnly) SetPanicOnExit0(bool) {}
2145 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
2146 return errMain
2147 }
2148 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
2149 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
2150 return nil, errMain
2151 }
2152 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
2153 func (f matchStringOnly) ResetCoverage() {}
2154 func (f matchStringOnly) SnapshotCoverage() {}
2155
2156 func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
2157 return
2158 }
2159
2160
2161
2162
2163
2164
2165
2166 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
2167 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
2168 }
2169
2170
2171 type M struct {
2172 deps testDeps
2173 tests []InternalTest
2174 benchmarks []InternalBenchmark
2175 fuzzTargets []InternalFuzzTarget
2176 examples []InternalExample
2177
2178 timer *time.Timer
2179 afterOnce sync.Once
2180
2181 numRun int
2182
2183
2184
2185 exitCode int
2186 }
2187
2188
2189
2190
2191
2192 type testDeps interface {
2193 ImportPath() string
2194 MatchString(pat, str string) (bool, error)
2195 SetPanicOnExit0(bool)
2196 StartCPUProfile(io.Writer) error
2197 StopCPUProfile()
2198 StartTestLog(io.Writer)
2199 StopTestLog() error
2200 WriteProfileTo(string, io.Writer, int) error
2201 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
2202 RunFuzzWorker(func(corpusEntry) error) error
2203 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
2204 CheckCorpus([]any, []reflect.Type) error
2205 ResetCoverage()
2206 SnapshotCoverage()
2207 InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
2208 }
2209
2210
2211
2212
2213 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
2214 registerCover(deps.InitRuntimeCoverage())
2215 Init()
2216 return &M{
2217 deps: deps,
2218 tests: tests,
2219 benchmarks: benchmarks,
2220 fuzzTargets: fuzzTargets,
2221 examples: examples,
2222 }
2223 }
2224
2225 var (
2226 testingTesting bool
2227 realStderr *os.File
2228 )
2229
2230
2231
2232
2233
2234 func (m *M) Run() (code int) {
2235 defer func() {
2236 code = m.exitCode
2237 }()
2238
2239
2240
2241
2242
2243 m.numRun++
2244
2245
2246 if !flag.Parsed() {
2247 flag.Parse()
2248 }
2249
2250 if chatty.json {
2251
2252
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 realStderr = os.Stderr
2285 os.Stderr = os.Stdout
2286 }
2287
2288 if *parallel < 1 {
2289 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
2290 flag.Usage()
2291 m.exitCode = 2
2292 return
2293 }
2294 if *matchFuzz != "" && *fuzzCacheDir == "" {
2295 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
2296 flag.Usage()
2297 m.exitCode = 2
2298 return
2299 }
2300
2301 if *matchList != "" {
2302 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
2303 m.exitCode = 0
2304 return
2305 }
2306
2307 if *shuffle != "off" {
2308 var n int64
2309 var err error
2310 if *shuffle == "on" {
2311 n = time.Now().UnixNano()
2312 } else {
2313 n, err = strconv.ParseInt(*shuffle, 10, 64)
2314 if err != nil {
2315 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2316 m.exitCode = 2
2317 return
2318 }
2319 }
2320 fmt.Println("-test.shuffle", n)
2321 rng := rand.New(rand.NewSource(n))
2322 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2323 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2324 }
2325
2326 parseCpuList()
2327
2328 m.before()
2329 defer m.after()
2330
2331
2332
2333
2334 if !*isFuzzWorker {
2335 deadline := m.startAlarm()
2336 haveExamples = len(m.examples) > 0
2337 testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
2338 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2339 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2340 m.stopAlarm()
2341 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2342 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2343 if testingTesting && *match != "^$" {
2344
2345
2346
2347
2348
2349 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2350 testOk = false
2351 }
2352 }
2353 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2354 if !anyFailed && race.Errors() > 0 {
2355 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2356 anyFailed = true
2357 }
2358 if anyFailed {
2359 fmt.Print(chatty.prefix(), "FAIL\n")
2360 m.exitCode = 1
2361 return
2362 }
2363 }
2364
2365 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2366 if !fuzzingOk {
2367 fmt.Print(chatty.prefix(), "FAIL\n")
2368 if *isFuzzWorker {
2369 m.exitCode = fuzzWorkerExitCode
2370 } else {
2371 m.exitCode = 1
2372 }
2373 return
2374 }
2375
2376 m.exitCode = 0
2377 if !*isFuzzWorker {
2378 fmt.Print(chatty.prefix(), "PASS\n")
2379 }
2380 return
2381 }
2382
2383 func (t *T) report() {
2384 if t.parent == nil {
2385 return
2386 }
2387 if t.isSynctest {
2388 return
2389 }
2390 dstr := fmtDuration(t.duration)
2391 format := "--- %s: %s (%s)\n"
2392 if t.Failed() {
2393 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2394 } else if t.chatty != nil {
2395 if t.Skipped() {
2396 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2397 } else {
2398 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2399 }
2400 }
2401 }
2402
2403 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2404 if _, err := matchString(*matchList, "non-empty"); err != nil {
2405 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2406 os.Exit(1)
2407 }
2408
2409 for _, test := range tests {
2410 if ok, _ := matchString(*matchList, test.Name); ok {
2411 fmt.Println(test.Name)
2412 }
2413 }
2414 for _, bench := range benchmarks {
2415 if ok, _ := matchString(*matchList, bench.Name); ok {
2416 fmt.Println(bench.Name)
2417 }
2418 }
2419 for _, fuzzTarget := range fuzzTargets {
2420 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2421 fmt.Println(fuzzTarget.Name)
2422 }
2423 }
2424 for _, example := range examples {
2425 if ok, _ := matchString(*matchList, example.Name); ok {
2426 fmt.Println(example.Name)
2427 }
2428 }
2429 }
2430
2431
2432
2433 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2434 var deadline time.Time
2435 if *timeout > 0 {
2436 deadline = time.Now().Add(*timeout)
2437 }
2438 ran, ok := runTests(matchString, tests, deadline)
2439 if !ran && !haveExamples {
2440 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2441 }
2442 return ok
2443 }
2444
2445 func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2446 ok = true
2447 for _, procs := range cpuList {
2448 runtime.GOMAXPROCS(procs)
2449 for i := uint(0); i < *count; i++ {
2450 if shouldFailFast() {
2451 break
2452 }
2453 if i > 0 && !ran {
2454
2455
2456
2457 break
2458 }
2459 ctx, cancelCtx := context.WithCancel(context.Background())
2460 tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2461 tstate.deadline = deadline
2462 t := &T{
2463 common: common{
2464 signal: make(chan bool, 1),
2465 barrier: make(chan bool),
2466 w: os.Stdout,
2467 ctx: ctx,
2468 cancelCtx: cancelCtx,
2469 },
2470 tstate: tstate,
2471 }
2472 if Verbose() {
2473 t.chatty = newChattyPrinter(t.w)
2474 }
2475 tRunner(t, func(t *T) {
2476 for _, test := range tests {
2477 t.Run(test.Name, test.F)
2478 }
2479 })
2480 select {
2481 case <-t.signal:
2482 default:
2483 panic("internal error: tRunner exited without sending on t.signal")
2484 }
2485 ok = ok && !t.Failed()
2486 ran = ran || t.ran
2487 }
2488 }
2489 return ran, ok
2490 }
2491
2492
2493 func (m *M) before() {
2494 if *memProfileRate > 0 {
2495 runtime.MemProfileRate = *memProfileRate
2496 }
2497 if *cpuProfile != "" {
2498 f, err := os.Create(toOutputDir(*cpuProfile))
2499 if err != nil {
2500 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2501 return
2502 }
2503 if err := m.deps.StartCPUProfile(f); err != nil {
2504 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2505 f.Close()
2506 return
2507 }
2508
2509 }
2510 if *traceFile != "" {
2511 f, err := os.Create(toOutputDir(*traceFile))
2512 if err != nil {
2513 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2514 return
2515 }
2516 if err := trace.Start(f); err != nil {
2517 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2518 f.Close()
2519 return
2520 }
2521
2522 }
2523 if *blockProfile != "" && *blockProfileRate >= 0 {
2524 runtime.SetBlockProfileRate(*blockProfileRate)
2525 }
2526 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2527 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2528 }
2529 if *coverProfile != "" && CoverMode() == "" {
2530 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2531 os.Exit(2)
2532 }
2533 if *gocoverdir != "" && CoverMode() == "" {
2534 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2535 os.Exit(2)
2536 }
2537 if *testlog != "" {
2538
2539
2540 var f *os.File
2541 var err error
2542 if m.numRun == 1 {
2543 f, err = os.Create(*testlog)
2544 } else {
2545 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2546 if err == nil {
2547 f.Seek(0, io.SeekEnd)
2548 }
2549 }
2550 if err != nil {
2551 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2552 os.Exit(2)
2553 }
2554 m.deps.StartTestLog(f)
2555 testlogFile = f
2556 }
2557 if *panicOnExit0 {
2558 m.deps.SetPanicOnExit0(true)
2559 }
2560 }
2561
2562
2563 func (m *M) after() {
2564 m.afterOnce.Do(func() {
2565 m.writeProfiles()
2566 })
2567
2568
2569
2570
2571 if *panicOnExit0 {
2572 m.deps.SetPanicOnExit0(false)
2573 }
2574 }
2575
2576 func (m *M) writeProfiles() {
2577 if *testlog != "" {
2578 if err := m.deps.StopTestLog(); err != nil {
2579 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2580 os.Exit(2)
2581 }
2582 if err := testlogFile.Close(); err != nil {
2583 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2584 os.Exit(2)
2585 }
2586 }
2587 if *cpuProfile != "" {
2588 m.deps.StopCPUProfile()
2589 }
2590 if *traceFile != "" {
2591 trace.Stop()
2592 }
2593 if *memProfile != "" {
2594 f, err := os.Create(toOutputDir(*memProfile))
2595 if err != nil {
2596 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2597 os.Exit(2)
2598 }
2599 runtime.GC()
2600 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2601 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2602 os.Exit(2)
2603 }
2604 f.Close()
2605 }
2606 if *blockProfile != "" && *blockProfileRate >= 0 {
2607 f, err := os.Create(toOutputDir(*blockProfile))
2608 if err != nil {
2609 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2610 os.Exit(2)
2611 }
2612 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2613 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2614 os.Exit(2)
2615 }
2616 f.Close()
2617 }
2618 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2619 f, err := os.Create(toOutputDir(*mutexProfile))
2620 if err != nil {
2621 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2622 os.Exit(2)
2623 }
2624 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2625 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2626 os.Exit(2)
2627 }
2628 f.Close()
2629 }
2630 if CoverMode() != "" {
2631 coverReport()
2632 }
2633 }
2634
2635
2636
2637 func toOutputDir(path string) string {
2638 if *outputDir == "" || path == "" {
2639 return path
2640 }
2641
2642
2643
2644
2645
2646
2647
2648 if runtime.GOOS == "windows" && len(path) >= 2 {
2649 letter, colon := path[0], path[1]
2650 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2651
2652 return path
2653 }
2654 }
2655 if os.IsPathSeparator(path[0]) {
2656 return path
2657 }
2658 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2659 }
2660
2661
2662 func (m *M) startAlarm() time.Time {
2663 if *timeout <= 0 {
2664 return time.Time{}
2665 }
2666
2667 deadline := time.Now().Add(*timeout)
2668 m.timer = time.AfterFunc(*timeout, func() {
2669 m.after()
2670 debug.SetTraceback("all")
2671 extra := ""
2672
2673 if list := runningList(); len(list) > 0 {
2674 var b strings.Builder
2675 b.WriteString("\nrunning tests:")
2676 for _, name := range list {
2677 b.WriteString("\n\t")
2678 b.WriteString(name)
2679 }
2680 extra = b.String()
2681 }
2682 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2683 })
2684 return deadline
2685 }
2686
2687
2688 func runningList() []string {
2689 var list []string
2690 running.Range(func(k, v any) bool {
2691 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2692 return true
2693 })
2694 slices.Sort(list)
2695 return list
2696 }
2697
2698
2699 func (m *M) stopAlarm() {
2700 if *timeout > 0 {
2701 m.timer.Stop()
2702 }
2703 }
2704
2705 func parseCpuList() {
2706 for val := range strings.SplitSeq(*cpuListStr, ",") {
2707 val = strings.TrimSpace(val)
2708 if val == "" {
2709 continue
2710 }
2711 cpu, err := strconv.Atoi(val)
2712 if err != nil || cpu <= 0 {
2713 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2714 os.Exit(1)
2715 }
2716 cpuList = append(cpuList, cpu)
2717 }
2718 if cpuList == nil {
2719 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2720 }
2721 }
2722
2723 func shouldFailFast() bool {
2724 return *failFast && numFailed.Load() > 0
2725 }
2726
View as plain text