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