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