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 or t.Chdir 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 func (t *T) checkParallel() {
1824
1825
1826
1827
1828
1829 for c := &t.common; c != nil; c = c.parent {
1830 if c.isParallel {
1831 panic(parallelConflict)
1832 }
1833 }
1834
1835 t.denyParallel = true
1836 }
1837
1838
1839
1840
1841
1842
1843
1844 func (t *T) Setenv(key, value string) {
1845 t.checkParallel()
1846 t.common.Setenv(key, value)
1847 }
1848
1849
1850
1851
1852
1853
1854
1855 func (t *T) Chdir(dir string) {
1856 t.checkParallel()
1857 t.common.Chdir(dir)
1858 }
1859
1860
1861
1862 type InternalTest struct {
1863 Name string
1864 F func(*T)
1865 }
1866
1867 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
1868
1869 func tRunner(t *T, fn func(t *T)) {
1870 t.runner = callerName(0)
1871
1872
1873
1874
1875
1876 defer func() {
1877 t.checkRaces()
1878
1879
1880 if t.Failed() {
1881 numFailed.Add(1)
1882 }
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892 err := recover()
1893 signal := true
1894
1895 t.mu.RLock()
1896 finished := t.finished
1897 t.mu.RUnlock()
1898 if !finished && err == nil {
1899 err = errNilPanicOrGoexit
1900 for p := t.parent; p != nil; p = p.parent {
1901 p.mu.RLock()
1902 finished = p.finished
1903 p.mu.RUnlock()
1904 if finished {
1905 if !t.isParallel {
1906 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
1907 err = nil
1908 }
1909 signal = false
1910 break
1911 }
1912 }
1913 }
1914
1915 if err != nil && t.tstate.isFuzzing {
1916 prefix := "panic: "
1917 if err == errNilPanicOrGoexit {
1918 prefix = ""
1919 }
1920 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
1921 t.mu.Lock()
1922 t.finished = true
1923 t.mu.Unlock()
1924 err = nil
1925 }
1926
1927
1928
1929 didPanic := false
1930 defer func() {
1931
1932
1933
1934 if didPanic {
1935 return
1936 }
1937 if err != nil {
1938 panic(err)
1939 }
1940 running.Delete(t.name)
1941 if t.isParallel {
1942 parallelStop.Add(1)
1943 }
1944 t.signal <- signal
1945 }()
1946
1947 doPanic := func(err any) {
1948 t.Fail()
1949 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
1950 t.Logf("cleanup panicked with %v", r)
1951 }
1952
1953
1954 for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent {
1955 root.mu.Lock()
1956 root.duration += highPrecisionTimeSince(root.start)
1957 d := root.duration
1958 root.mu.Unlock()
1959
1960 root.flushPartial()
1961 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
1962 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
1963 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
1964 }
1965 }
1966 didPanic = true
1967 panic(err)
1968 }
1969 if err != nil {
1970 doPanic(err)
1971 }
1972
1973 t.duration += highPrecisionTimeSince(t.start)
1974
1975 if len(t.sub) > 0 {
1976
1977
1978
1979 t.tstate.release()
1980 running.Delete(t.name)
1981
1982
1983 close(t.barrier)
1984
1985 for _, sub := range t.sub {
1986 <-sub.signal
1987 }
1988
1989
1990
1991 cleanupStart := highPrecisionTimeNow()
1992 running.Store(t.name, cleanupStart)
1993 err := t.runCleanup(recoverAndReturnPanic)
1994 t.duration += highPrecisionTimeSince(cleanupStart)
1995 if err != nil {
1996 doPanic(err)
1997 }
1998 t.checkRaces()
1999 if !t.isParallel {
2000
2001 t.tstate.waitParallel()
2002 }
2003 } else if t.isParallel {
2004
2005
2006 t.tstate.release()
2007 }
2008
2009 for root := &t.common; root.parent != nil; root = root.parent {
2010 root.flushPartial()
2011 }
2012 t.report()
2013
2014
2015
2016 t.done = true
2017 if t.parent != nil && !t.hasSub.Load() {
2018 t.setRan()
2019 }
2020 }()
2021 defer func() {
2022 if len(t.sub) == 0 {
2023 t.runCleanup(normalPanic)
2024 }
2025 }()
2026
2027 t.start = highPrecisionTimeNow()
2028 t.resetRaces()
2029 fn(t)
2030
2031
2032 t.mu.Lock()
2033 t.finished = true
2034 t.mu.Unlock()
2035 }
2036
2037
2038
2039
2040
2041
2042
2043 func (t *T) Run(name string, f func(t *T)) bool {
2044 if t.isSynctest {
2045 panic("testing: t.Run called inside synctest bubble")
2046 }
2047 if t.cleanupStarted.Load() {
2048 panic("testing: t.Run called during t.Cleanup")
2049 }
2050
2051 t.hasSub.Store(true)
2052 testName, ok, _ := t.tstate.match.fullName(&t.common, name)
2053 if !ok || shouldFailFast() {
2054 return true
2055 }
2056
2057
2058
2059 var pc [maxStackLen]uintptr
2060 n := runtime.Callers(2, pc[:])
2061
2062
2063
2064 ctx, cancelCtx := context.WithCancel(context.Background())
2065 t = &T{
2066 common: common{
2067 barrier: make(chan bool),
2068 signal: make(chan bool, 1),
2069 name: testName,
2070 modulePath: t.modulePath,
2071 importPath: t.importPath,
2072 parent: &t.common,
2073 level: t.level + 1,
2074 creator: pc[:n],
2075 chatty: t.chatty,
2076 ctx: ctx,
2077 cancelCtx: cancelCtx,
2078 },
2079 tstate: t.tstate,
2080 }
2081 t.w = indenter{&t.common}
2082 t.setOutputWriter()
2083
2084 if t.chatty != nil {
2085 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
2086 }
2087 running.Store(t.name, highPrecisionTimeNow())
2088
2089
2090
2091
2092
2093
2094 go tRunner(t, f)
2095
2096
2097
2098
2099
2100
2101
2102 if !<-t.signal {
2103
2104
2105 runtime.Goexit()
2106 }
2107
2108 if t.chatty != nil && t.chatty.json {
2109 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
2110 }
2111 return !t.failed
2112 }
2113
2114
2115
2116
2117
2118 func testingSynctestTest(t *T, f func(*T)) (ok bool) {
2119 if t.cleanupStarted.Load() {
2120 panic("testing: synctest.Run called during t.Cleanup")
2121 }
2122
2123 var pc [maxStackLen]uintptr
2124 n := runtime.Callers(2, pc[:])
2125
2126 ctx, cancelCtx := context.WithCancel(context.Background())
2127 t2 := &T{
2128 common: common{
2129 barrier: make(chan bool),
2130 signal: make(chan bool, 1),
2131 name: t.name,
2132 parent: &t.common,
2133 level: t.level + 1,
2134 creator: pc[:n],
2135 chatty: t.chatty,
2136 ctx: ctx,
2137 cancelCtx: cancelCtx,
2138 isSynctest: true,
2139 },
2140 tstate: t.tstate,
2141 }
2142
2143 go tRunner(t2, f)
2144 if !<-t2.signal {
2145
2146
2147 runtime.Goexit()
2148 }
2149 return !t2.failed
2150 }
2151
2152
2153
2154
2155
2156 func (t *T) Deadline() (deadline time.Time, ok bool) {
2157 if t.isSynctest {
2158
2159
2160
2161 panic("testing: t.Deadline called inside synctest bubble")
2162 }
2163 deadline = t.tstate.deadline
2164 return deadline, !deadline.IsZero()
2165 }
2166
2167
2168
2169 type testState struct {
2170 match *matcher
2171 deadline time.Time
2172
2173
2174
2175
2176
2177 isFuzzing bool
2178
2179 mu sync.Mutex
2180
2181
2182 startParallel chan bool
2183
2184
2185
2186 running int
2187
2188
2189 numWaiting int
2190
2191
2192 maxParallel int
2193 }
2194
2195 func newTestState(maxParallel int, m *matcher) *testState {
2196 return &testState{
2197 match: m,
2198 startParallel: make(chan bool),
2199 maxParallel: maxParallel,
2200 running: 1,
2201 }
2202 }
2203
2204 func (s *testState) waitParallel() {
2205 s.mu.Lock()
2206 if s.running < s.maxParallel {
2207 s.running++
2208 s.mu.Unlock()
2209 return
2210 }
2211 s.numWaiting++
2212 s.mu.Unlock()
2213 <-s.startParallel
2214 }
2215
2216 func (s *testState) release() {
2217 s.mu.Lock()
2218 if s.numWaiting == 0 {
2219 s.running--
2220 s.mu.Unlock()
2221 return
2222 }
2223 s.numWaiting--
2224 s.mu.Unlock()
2225 s.startParallel <- true
2226 }
2227
2228
2229
2230 var errMain = errors.New("testing: unexpected use of func Main")
2231
2232 type matchStringOnly func(pat, str string) (bool, error)
2233
2234 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
2235 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
2236 func (f matchStringOnly) StopCPUProfile() {}
2237 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
2238 func (f matchStringOnly) ModulePath() string { return "" }
2239 func (f matchStringOnly) ImportPath() string { return "" }
2240 func (f matchStringOnly) StartTestLog(io.Writer) {}
2241 func (f matchStringOnly) StopTestLog() error { return errMain }
2242 func (f matchStringOnly) SetPanicOnExit0(bool) {}
2243 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
2244 return errMain
2245 }
2246 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
2247 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
2248 return nil, errMain
2249 }
2250 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
2251 func (f matchStringOnly) ResetCoverage() {}
2252 func (f matchStringOnly) SnapshotCoverage() {}
2253
2254 func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
2255 return
2256 }
2257
2258
2259
2260
2261
2262
2263
2264 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
2265 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
2266 }
2267
2268
2269 type M struct {
2270 deps testDeps
2271 tests []InternalTest
2272 benchmarks []InternalBenchmark
2273 fuzzTargets []InternalFuzzTarget
2274 examples []InternalExample
2275
2276 timer *time.Timer
2277 afterOnce sync.Once
2278
2279 numRun int
2280
2281
2282
2283 exitCode int
2284 }
2285
2286
2287
2288
2289
2290 type testDeps interface {
2291 ImportPath() string
2292 ModulePath() string
2293 MatchString(pat, str string) (bool, error)
2294 SetPanicOnExit0(bool)
2295 StartCPUProfile(io.Writer) error
2296 StopCPUProfile()
2297 StartTestLog(io.Writer)
2298 StopTestLog() error
2299 WriteProfileTo(string, io.Writer, int) error
2300 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
2301 RunFuzzWorker(func(corpusEntry) error) error
2302 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
2303 CheckCorpus([]any, []reflect.Type) error
2304 ResetCoverage()
2305 SnapshotCoverage()
2306 InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
2307 }
2308
2309
2310
2311
2312 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
2313 registerCover(deps.InitRuntimeCoverage())
2314 Init()
2315 return &M{
2316 deps: deps,
2317 tests: tests,
2318 benchmarks: benchmarks,
2319 fuzzTargets: fuzzTargets,
2320 examples: examples,
2321 }
2322 }
2323
2324 var (
2325 testingTesting bool
2326 realStderr *os.File
2327 )
2328
2329
2330
2331
2332
2333 func (m *M) Run() (code int) {
2334 defer func() {
2335 code = m.exitCode
2336 }()
2337
2338
2339
2340
2341
2342 m.numRun++
2343
2344
2345 if !flag.Parsed() {
2346 flag.Parse()
2347 }
2348
2349 if chatty.json {
2350
2351
2352
2353
2354
2355
2356
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 realStderr = os.Stderr
2384 os.Stderr = os.Stdout
2385 }
2386
2387 if *parallel < 1 {
2388 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
2389 flag.Usage()
2390 m.exitCode = 2
2391 return
2392 }
2393 if *matchFuzz != "" && *fuzzCacheDir == "" {
2394 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
2395 flag.Usage()
2396 m.exitCode = 2
2397 return
2398 }
2399
2400 if *matchList != "" {
2401 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
2402 m.exitCode = 0
2403 return
2404 }
2405
2406 if *shuffle != "off" {
2407 var n int64
2408 var err error
2409 if *shuffle == "on" {
2410 n = time.Now().UnixNano()
2411 } else {
2412 n, err = strconv.ParseInt(*shuffle, 10, 64)
2413 if err != nil {
2414 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2415 m.exitCode = 2
2416 return
2417 }
2418 }
2419 fmt.Println("-test.shuffle", n)
2420 rng := rand.New(rand.NewSource(n))
2421 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2422 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2423 }
2424
2425 parseCpuList()
2426
2427 m.before()
2428 defer m.after()
2429
2430
2431
2432
2433 if !*isFuzzWorker {
2434 deadline := m.startAlarm()
2435 haveExamples = len(m.examples) > 0
2436 testRan, testOk := runTests(m.deps.ModulePath(), m.deps.ImportPath(), m.deps.MatchString, m.tests, deadline)
2437 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2438 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2439 m.stopAlarm()
2440 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2441 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2442 if testingTesting && *match != "^$" {
2443
2444
2445
2446
2447
2448 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2449 testOk = false
2450 }
2451 }
2452 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2453 if !anyFailed && race.Errors() > 0 {
2454 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2455 anyFailed = true
2456 }
2457 if anyFailed {
2458 fmt.Print(chatty.prefix(), "FAIL\n")
2459 m.exitCode = 1
2460 return
2461 }
2462 }
2463
2464 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2465 if !fuzzingOk {
2466 fmt.Print(chatty.prefix(), "FAIL\n")
2467 if *isFuzzWorker {
2468 m.exitCode = fuzzWorkerExitCode
2469 } else {
2470 m.exitCode = 1
2471 }
2472 return
2473 }
2474
2475 m.exitCode = 0
2476 if !*isFuzzWorker {
2477 fmt.Print(chatty.prefix(), "PASS\n")
2478 }
2479 return
2480 }
2481
2482 func (t *T) report() {
2483 if t.parent == nil {
2484 return
2485 }
2486 if t.isSynctest {
2487 return
2488 }
2489 dstr := fmtDuration(t.duration)
2490 format := "--- %s: %s (%s)\n"
2491 if t.Failed() {
2492 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2493 } else if t.chatty != nil {
2494 if t.Skipped() {
2495 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2496 } else {
2497 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2498 }
2499 }
2500 }
2501
2502 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2503 if _, err := matchString(*matchList, "non-empty"); err != nil {
2504 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2505 os.Exit(1)
2506 }
2507
2508 for _, test := range tests {
2509 if ok, _ := matchString(*matchList, test.Name); ok {
2510 fmt.Println(test.Name)
2511 }
2512 }
2513 for _, bench := range benchmarks {
2514 if ok, _ := matchString(*matchList, bench.Name); ok {
2515 fmt.Println(bench.Name)
2516 }
2517 }
2518 for _, fuzzTarget := range fuzzTargets {
2519 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2520 fmt.Println(fuzzTarget.Name)
2521 }
2522 }
2523 for _, example := range examples {
2524 if ok, _ := matchString(*matchList, example.Name); ok {
2525 fmt.Println(example.Name)
2526 }
2527 }
2528 }
2529
2530
2531
2532 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2533 var deadline time.Time
2534 if *timeout > 0 {
2535 deadline = time.Now().Add(*timeout)
2536 }
2537 ran, ok := runTests("", "", matchString, tests, deadline)
2538 if !ran && !haveExamples {
2539 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2540 }
2541 return ok
2542 }
2543
2544 func runTests(modulePath, importPath string, matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2545 ok = true
2546 for _, procs := range cpuList {
2547 runtime.GOMAXPROCS(procs)
2548 for i := uint(0); i < *count; i++ {
2549 if shouldFailFast() {
2550 break
2551 }
2552 if i > 0 && !ran {
2553
2554
2555
2556 break
2557 }
2558 ctx, cancelCtx := context.WithCancel(context.Background())
2559 tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2560 tstate.deadline = deadline
2561 t := &T{
2562 common: common{
2563 signal: make(chan bool, 1),
2564 barrier: make(chan bool),
2565 w: os.Stdout,
2566 ctx: ctx,
2567 cancelCtx: cancelCtx,
2568 modulePath: modulePath,
2569 importPath: importPath,
2570 },
2571 tstate: tstate,
2572 }
2573 if Verbose() {
2574 t.chatty = newChattyPrinter(t.w)
2575 }
2576 tRunner(t, func(t *T) {
2577 for _, test := range tests {
2578 t.Run(test.Name, test.F)
2579 }
2580 })
2581 select {
2582 case <-t.signal:
2583 default:
2584 panic("internal error: tRunner exited without sending on t.signal")
2585 }
2586 ok = ok && !t.Failed()
2587 ran = ran || t.ran
2588 }
2589 }
2590 return ran, ok
2591 }
2592
2593
2594 func (m *M) before() {
2595 if *memProfileRate > 0 {
2596 runtime.MemProfileRate = *memProfileRate
2597 }
2598 if *cpuProfile != "" {
2599 f, err := os.Create(toOutputDir(*cpuProfile))
2600 if err != nil {
2601 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2602 return
2603 }
2604 if err := m.deps.StartCPUProfile(f); err != nil {
2605 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2606 f.Close()
2607 return
2608 }
2609
2610 }
2611 if *traceFile != "" {
2612 f, err := os.Create(toOutputDir(*traceFile))
2613 if err != nil {
2614 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2615 return
2616 }
2617 if err := trace.Start(f); err != nil {
2618 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2619 f.Close()
2620 return
2621 }
2622
2623 }
2624 if *blockProfile != "" && *blockProfileRate >= 0 {
2625 runtime.SetBlockProfileRate(*blockProfileRate)
2626 }
2627 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2628 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2629 }
2630 if *coverProfile != "" && CoverMode() == "" {
2631 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2632 os.Exit(2)
2633 }
2634 if *gocoverdir != "" && CoverMode() == "" {
2635 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2636 os.Exit(2)
2637 }
2638 if *artifacts {
2639 var err error
2640 artifactDir, err = filepath.Abs(toOutputDir("_artifacts"))
2641 if err != nil {
2642 fmt.Fprintf(os.Stderr, "testing: cannot make -test.outputdir absolute: %v\n", err)
2643 os.Exit(2)
2644 }
2645 if err := os.Mkdir(artifactDir, 0o777); err != nil && !errors.Is(err, os.ErrExist) {
2646 fmt.Fprintf(os.Stderr, "testing: %v\n", err)
2647 os.Exit(2)
2648 }
2649 }
2650 if *testlog != "" {
2651
2652
2653 var f *os.File
2654 var err error
2655 if m.numRun == 1 {
2656 f, err = os.Create(*testlog)
2657 } else {
2658 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2659 if err == nil {
2660 f.Seek(0, io.SeekEnd)
2661 }
2662 }
2663 if err != nil {
2664 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2665 os.Exit(2)
2666 }
2667 m.deps.StartTestLog(f)
2668 testlogFile = f
2669 }
2670 if *panicOnExit0 {
2671 m.deps.SetPanicOnExit0(true)
2672 }
2673 }
2674
2675
2676 func (m *M) after() {
2677 m.afterOnce.Do(func() {
2678 m.writeProfiles()
2679 })
2680
2681
2682
2683
2684 if *panicOnExit0 {
2685 m.deps.SetPanicOnExit0(false)
2686 }
2687 }
2688
2689 func (m *M) writeProfiles() {
2690 if *testlog != "" {
2691 if err := m.deps.StopTestLog(); err != nil {
2692 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2693 os.Exit(2)
2694 }
2695 if err := testlogFile.Close(); err != nil {
2696 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2697 os.Exit(2)
2698 }
2699 }
2700 if *cpuProfile != "" {
2701 m.deps.StopCPUProfile()
2702 }
2703 if *traceFile != "" {
2704 trace.Stop()
2705 }
2706 if *memProfile != "" {
2707 f, err := os.Create(toOutputDir(*memProfile))
2708 if err != nil {
2709 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2710 os.Exit(2)
2711 }
2712 runtime.GC()
2713 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2714 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2715 os.Exit(2)
2716 }
2717 f.Close()
2718 }
2719 if *blockProfile != "" && *blockProfileRate >= 0 {
2720 f, err := os.Create(toOutputDir(*blockProfile))
2721 if err != nil {
2722 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2723 os.Exit(2)
2724 }
2725 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2726 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2727 os.Exit(2)
2728 }
2729 f.Close()
2730 }
2731 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2732 f, err := os.Create(toOutputDir(*mutexProfile))
2733 if err != nil {
2734 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2735 os.Exit(2)
2736 }
2737 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2738 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2739 os.Exit(2)
2740 }
2741 f.Close()
2742 }
2743 if CoverMode() != "" {
2744 coverReport()
2745 }
2746 }
2747
2748
2749
2750 func toOutputDir(path string) string {
2751 if *outputDir == "" || path == "" {
2752 return path
2753 }
2754
2755
2756
2757
2758
2759
2760
2761 if runtime.GOOS == "windows" && len(path) >= 2 {
2762 letter, colon := path[0], path[1]
2763 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2764
2765 return path
2766 }
2767 }
2768 if os.IsPathSeparator(path[0]) {
2769 return path
2770 }
2771 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2772 }
2773
2774
2775 func (m *M) startAlarm() time.Time {
2776 if *timeout <= 0 {
2777 return time.Time{}
2778 }
2779
2780 deadline := time.Now().Add(*timeout)
2781 m.timer = time.AfterFunc(*timeout, func() {
2782 m.after()
2783 debug.SetTraceback("all")
2784 extra := ""
2785
2786 if list := runningList(); len(list) > 0 {
2787 var b strings.Builder
2788 b.WriteString("\nrunning tests:")
2789 for _, name := range list {
2790 b.WriteString("\n\t")
2791 b.WriteString(name)
2792 }
2793 extra = b.String()
2794 }
2795 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2796 })
2797 return deadline
2798 }
2799
2800
2801 func runningList() []string {
2802 var list []string
2803 running.Range(func(k, v any) bool {
2804 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2805 return true
2806 })
2807 slices.Sort(list)
2808 return list
2809 }
2810
2811
2812 func (m *M) stopAlarm() {
2813 if *timeout > 0 {
2814 m.timer.Stop()
2815 }
2816 }
2817
2818 func parseCpuList() {
2819 for val := range strings.SplitSeq(*cpuListStr, ",") {
2820 val = strings.TrimSpace(val)
2821 if val == "" {
2822 continue
2823 }
2824 cpu, err := strconv.Atoi(val)
2825 if err != nil || cpu <= 0 {
2826 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2827 os.Exit(1)
2828 }
2829 cpuList = append(cpuList, cpu)
2830 }
2831 if cpuList == nil {
2832 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2833 }
2834 }
2835
2836 func shouldFailFast() bool {
2837 return *failFast && numFailed.Load() > 0
2838 }
2839
View as plain text