Source file
src/testing/testing.go
Documentation: testing
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 package testing
237
238 import (
239 "bytes"
240 "errors"
241 "flag"
242 "fmt"
243 "internal/race"
244 "io"
245 "os"
246 "runtime"
247 "runtime/debug"
248 "runtime/trace"
249 "strconv"
250 "strings"
251 "sync"
252 "sync/atomic"
253 "time"
254 )
255
256 var initRan bool
257
258
259
260
261
262
263 func Init() {
264 if initRan {
265 return
266 }
267 initRan = true
268
269
270
271
272
273 short = flag.Bool("test.short", false, "run smaller test suite to save time")
274
275
276 failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure")
277
278
279
280
281
282 outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
283
284 chatty = flag.Bool("test.v", false, "verbose: print additional output")
285 count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
286 coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
287 matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
288 match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
289 memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
290 memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
291 cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
292 blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
293 blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
294 mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
295 mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
296 panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
297 traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
298 timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
299 cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
300 parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
301 testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
302
303 initBenchmarkFlags()
304 }
305
306 var (
307
308 short *bool
309 failFast *bool
310 outputDir *string
311 chatty *bool
312 count *uint
313 coverProfile *string
314 matchList *string
315 match *string
316 memProfile *string
317 memProfileRate *int
318 cpuProfile *string
319 blockProfile *string
320 blockProfileRate *int
321 mutexProfile *string
322 mutexProfileFraction *int
323 panicOnExit0 *bool
324 traceFile *string
325 timeout *time.Duration
326 cpuListStr *string
327 parallel *int
328 testlog *string
329
330 haveExamples bool
331
332 cpuList []int
333 testlogFile *os.File
334
335 numFailed uint32
336 )
337
338 type chattyPrinter struct {
339 w io.Writer
340 lastNameMu sync.Mutex
341 lastName string
342 }
343
344 func newChattyPrinter(w io.Writer) *chattyPrinter {
345 return &chattyPrinter{w: w}
346 }
347
348
349
350
351 func (p *chattyPrinter) Updatef(testName, format string, args ...interface{}) {
352 p.lastNameMu.Lock()
353 defer p.lastNameMu.Unlock()
354
355
356
357
358
359 p.lastName = testName
360 fmt.Fprintf(p.w, format, args...)
361 }
362
363
364
365 func (p *chattyPrinter) Printf(testName, format string, args ...interface{}) {
366 p.lastNameMu.Lock()
367 defer p.lastNameMu.Unlock()
368
369 if p.lastName == "" {
370 p.lastName = testName
371 } else if p.lastName != testName {
372 fmt.Fprintf(p.w, "=== CONT %s\n", testName)
373 p.lastName = testName
374 }
375
376 fmt.Fprintf(p.w, format, args...)
377 }
378
379
380
381 const maxStackLen = 50
382
383
384
385 type common struct {
386 mu sync.RWMutex
387 output []byte
388 w io.Writer
389 ran bool
390 failed bool
391 skipped bool
392 done bool
393 helperPCs map[uintptr]struct{}
394 helperNames map[string]struct{}
395 cleanups []func()
396 cleanupName string
397 cleanupPc []uintptr
398
399 chatty *chattyPrinter
400 bench bool
401 finished bool
402 hasSub int32
403 raceErrors int
404 runner string
405
406 parent *common
407 level int
408 creator []uintptr
409 name string
410 start time.Time
411 duration time.Duration
412 barrier chan bool
413 signal chan bool
414 sub []*T
415
416 tempDirMu sync.Mutex
417 tempDir string
418 tempDirErr error
419 tempDirSeq int32
420 }
421
422
423 func Short() bool {
424 if short == nil {
425 panic("testing: Short called before Init")
426 }
427
428 if !flag.Parsed() {
429 panic("testing: Short called before Parse")
430 }
431
432 return *short
433 }
434
435
436
437
438 func CoverMode() string {
439 return cover.Mode
440 }
441
442
443 func Verbose() bool {
444
445 if chatty == nil {
446 panic("testing: Verbose called before Init")
447 }
448 if !flag.Parsed() {
449 panic("testing: Verbose called before Parse")
450 }
451 return *chatty
452 }
453
454
455
456
457
458
459 func (c *common) frameSkip(skip int) runtime.Frame {
460
461
462 shouldUnlock := false
463 defer func() {
464 if shouldUnlock {
465 c.mu.Unlock()
466 }
467 }()
468 var pc [maxStackLen]uintptr
469
470
471 n := runtime.Callers(skip+2, pc[:])
472 if n == 0 {
473 panic("testing: zero callers found")
474 }
475 frames := runtime.CallersFrames(pc[:n])
476 var firstFrame, prevFrame, frame runtime.Frame
477 for more := true; more; prevFrame = frame {
478 frame, more = frames.Next()
479 if frame.Function == c.cleanupName {
480 frames = runtime.CallersFrames(c.cleanupPc)
481 continue
482 }
483 if firstFrame.PC == 0 {
484 firstFrame = frame
485 }
486 if frame.Function == c.runner {
487
488
489
490
491
492
493 if c.level > 1 {
494 frames = runtime.CallersFrames(c.creator)
495 parent := c.parent
496
497
498
499 if shouldUnlock {
500 c.mu.Unlock()
501 }
502 c = parent
503
504
505
506 shouldUnlock = true
507 c.mu.Lock()
508 continue
509 }
510 return prevFrame
511 }
512 if _, ok := c.helperNames[frame.Function]; !ok {
513
514 return frame
515 }
516 }
517 return firstFrame
518 }
519
520
521
522
523 func (c *common) decorate(s string, skip int) string {
524
525 if c.helperNames == nil {
526 c.helperNames = make(map[string]struct{})
527 for pc := range c.helperPCs {
528 c.helperNames[pcToName(pc)] = struct{}{}
529 }
530 }
531
532 frame := c.frameSkip(skip)
533 file := frame.File
534 line := frame.Line
535 if file != "" {
536
537 if index := strings.LastIndex(file, "/"); index >= 0 {
538 file = file[index+1:]
539 } else if index = strings.LastIndex(file, "\\"); index >= 0 {
540 file = file[index+1:]
541 }
542 } else {
543 file = "???"
544 }
545 if line == 0 {
546 line = 1
547 }
548 buf := new(strings.Builder)
549
550 buf.WriteString(" ")
551 fmt.Fprintf(buf, "%s:%d: ", file, line)
552 lines := strings.Split(s, "\n")
553 if l := len(lines); l > 1 && lines[l-1] == "" {
554 lines = lines[:l-1]
555 }
556 for i, line := range lines {
557 if i > 0 {
558
559 buf.WriteString("\n ")
560 }
561 buf.WriteString(line)
562 }
563 buf.WriteByte('\n')
564 return buf.String()
565 }
566
567
568
569 func (c *common) flushToParent(testName, format string, args ...interface{}) {
570 p := c.parent
571 p.mu.Lock()
572 defer p.mu.Unlock()
573
574 c.mu.Lock()
575 defer c.mu.Unlock()
576
577 if len(c.output) > 0 {
578 format += "%s"
579 args = append(args[:len(args):len(args)], c.output)
580 c.output = c.output[:0]
581 }
582
583 if c.chatty != nil && p.w == c.chatty.w {
584
585
586
587
588
589
590
591
592
593 c.chatty.Updatef(testName, format, args...)
594 } else {
595
596
597 fmt.Fprintf(p.w, format, args...)
598 }
599 }
600
601 type indenter struct {
602 c *common
603 }
604
605 func (w indenter) Write(b []byte) (n int, err error) {
606 n = len(b)
607 for len(b) > 0 {
608 end := bytes.IndexByte(b, '\n')
609 if end == -1 {
610 end = len(b)
611 } else {
612 end++
613 }
614
615
616 const indent = " "
617 w.c.output = append(w.c.output, indent...)
618 w.c.output = append(w.c.output, b[:end]...)
619 b = b[end:]
620 }
621 return
622 }
623
624
625 func fmtDuration(d time.Duration) string {
626 return fmt.Sprintf("%.2fs", d.Seconds())
627 }
628
629
630 type TB interface {
631 Cleanup(func())
632 Error(args ...interface{})
633 Errorf(format string, args ...interface{})
634 Fail()
635 FailNow()
636 Failed() bool
637 Fatal(args ...interface{})
638 Fatalf(format string, args ...interface{})
639 Helper()
640 Log(args ...interface{})
641 Logf(format string, args ...interface{})
642 Name() string
643 Skip(args ...interface{})
644 SkipNow()
645 Skipf(format string, args ...interface{})
646 Skipped() bool
647 TempDir() string
648
649
650
651
652 private()
653 }
654
655 var _ TB = (*T)(nil)
656 var _ TB = (*B)(nil)
657
658
659
660
661
662
663
664
665
666
667 type T struct {
668 common
669 isParallel bool
670 context *testContext
671 }
672
673 func (c *common) private() {}
674
675
676 func (c *common) Name() string {
677 return c.name
678 }
679
680 func (c *common) setRan() {
681 if c.parent != nil {
682 c.parent.setRan()
683 }
684 c.mu.Lock()
685 defer c.mu.Unlock()
686 c.ran = true
687 }
688
689
690 func (c *common) Fail() {
691 if c.parent != nil {
692 c.parent.Fail()
693 }
694 c.mu.Lock()
695 defer c.mu.Unlock()
696
697 if c.done {
698 panic("Fail in goroutine after " + c.name + " has completed")
699 }
700 c.failed = true
701 }
702
703
704 func (c *common) Failed() bool {
705 c.mu.RLock()
706 failed := c.failed
707 c.mu.RUnlock()
708 return failed || c.raceErrors+race.Errors() > 0
709 }
710
711
712
713
714
715
716
717
718
719 func (c *common) FailNow() {
720 c.Fail()
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741 c.finished = true
742 runtime.Goexit()
743 }
744
745
746 func (c *common) log(s string) {
747 c.logDepth(s, 3)
748 }
749
750
751 func (c *common) logDepth(s string, depth int) {
752 c.mu.Lock()
753 defer c.mu.Unlock()
754 if c.done {
755
756
757 for parent := c.parent; parent != nil; parent = parent.parent {
758 parent.mu.Lock()
759 defer parent.mu.Unlock()
760 if !parent.done {
761 parent.output = append(parent.output, parent.decorate(s, depth+1)...)
762 return
763 }
764 }
765 panic("Log in goroutine after " + c.name + " has completed")
766 } else {
767 if c.chatty != nil {
768 if c.bench {
769
770
771 fmt.Print(c.decorate(s, depth+1))
772 } else {
773 c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
774 }
775
776 return
777 }
778 c.output = append(c.output, c.decorate(s, depth+1)...)
779 }
780 }
781
782
783
784
785
786 func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
787
788
789
790
791
792
793 func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
794
795
796 func (c *common) Error(args ...interface{}) {
797 c.log(fmt.Sprintln(args...))
798 c.Fail()
799 }
800
801
802 func (c *common) Errorf(format string, args ...interface{}) {
803 c.log(fmt.Sprintf(format, args...))
804 c.Fail()
805 }
806
807
808 func (c *common) Fatal(args ...interface{}) {
809 c.log(fmt.Sprintln(args...))
810 c.FailNow()
811 }
812
813
814 func (c *common) Fatalf(format string, args ...interface{}) {
815 c.log(fmt.Sprintf(format, args...))
816 c.FailNow()
817 }
818
819
820 func (c *common) Skip(args ...interface{}) {
821 c.log(fmt.Sprintln(args...))
822 c.SkipNow()
823 }
824
825
826 func (c *common) Skipf(format string, args ...interface{}) {
827 c.log(fmt.Sprintf(format, args...))
828 c.SkipNow()
829 }
830
831
832
833
834
835
836
837
838
839 func (c *common) SkipNow() {
840 c.skip()
841 c.finished = true
842 runtime.Goexit()
843 }
844
845 func (c *common) skip() {
846 c.mu.Lock()
847 defer c.mu.Unlock()
848 c.skipped = true
849 }
850
851
852 func (c *common) Skipped() bool {
853 c.mu.RLock()
854 defer c.mu.RUnlock()
855 return c.skipped
856 }
857
858
859
860
861 func (c *common) Helper() {
862 c.mu.Lock()
863 defer c.mu.Unlock()
864 if c.helperPCs == nil {
865 c.helperPCs = make(map[uintptr]struct{})
866 }
867
868 var pc [1]uintptr
869 n := runtime.Callers(2, pc[:])
870 if n == 0 {
871 panic("testing: zero callers found")
872 }
873 if _, found := c.helperPCs[pc[0]]; !found {
874 c.helperPCs[pc[0]] = struct{}{}
875 c.helperNames = nil
876 }
877 }
878
879
880
881
882 func (c *common) Cleanup(f func()) {
883 var pc [maxStackLen]uintptr
884
885 n := runtime.Callers(2, pc[:])
886 cleanupPc := pc[:n]
887
888 fn := func() {
889 defer func() {
890 c.mu.Lock()
891 defer c.mu.Unlock()
892 c.cleanupName = ""
893 c.cleanupPc = nil
894 }()
895
896 name := callerName(0)
897 c.mu.Lock()
898 c.cleanupName = name
899 c.cleanupPc = cleanupPc
900 c.mu.Unlock()
901
902 f()
903 }
904
905 c.mu.Lock()
906 defer c.mu.Unlock()
907 c.cleanups = append(c.cleanups, fn)
908 }
909
910 var tempDirReplacer struct {
911 sync.Once
912 r *strings.Replacer
913 }
914
915
916
917
918
919
920 func (c *common) TempDir() string {
921
922
923 c.tempDirMu.Lock()
924 var nonExistent bool
925 if c.tempDir == "" {
926 nonExistent = true
927 } else {
928 _, err := os.Stat(c.tempDir)
929 nonExistent = os.IsNotExist(err)
930 if err != nil && !nonExistent {
931 c.Fatalf("TempDir: %v", err)
932 }
933 }
934
935 if nonExistent {
936 c.Helper()
937
938
939
940 tempDirReplacer.Do(func() {
941 tempDirReplacer.r = strings.NewReplacer("/", "_", "\\", "_", ":", "_")
942 })
943 pattern := tempDirReplacer.r.Replace(c.Name())
944
945 c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
946 if c.tempDirErr == nil {
947 c.Cleanup(func() {
948 if err := os.RemoveAll(c.tempDir); err != nil {
949 c.Errorf("TempDir RemoveAll cleanup: %v", err)
950 }
951 })
952 }
953 }
954 c.tempDirMu.Unlock()
955
956 if c.tempDirErr != nil {
957 c.Fatalf("TempDir: %v", c.tempDirErr)
958 }
959 seq := atomic.AddInt32(&c.tempDirSeq, 1)
960 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
961 if err := os.Mkdir(dir, 0777); err != nil {
962 c.Fatalf("TempDir: %v", err)
963 }
964 return dir
965 }
966
967
968 type panicHandling int
969
970 const (
971 normalPanic panicHandling = iota
972 recoverAndReturnPanic
973 )
974
975
976
977
978 func (c *common) runCleanup(ph panicHandling) (panicVal interface{}) {
979 if ph == recoverAndReturnPanic {
980 defer func() {
981 panicVal = recover()
982 }()
983 }
984
985
986
987 defer func() {
988 c.mu.Lock()
989 recur := len(c.cleanups) > 0
990 c.mu.Unlock()
991 if recur {
992 c.runCleanup(normalPanic)
993 }
994 }()
995
996 for {
997 var cleanup func()
998 c.mu.Lock()
999 if len(c.cleanups) > 0 {
1000 last := len(c.cleanups) - 1
1001 cleanup = c.cleanups[last]
1002 c.cleanups = c.cleanups[:last]
1003 }
1004 c.mu.Unlock()
1005 if cleanup == nil {
1006 return nil
1007 }
1008 cleanup()
1009 }
1010 }
1011
1012
1013
1014 func callerName(skip int) string {
1015 var pc [1]uintptr
1016 n := runtime.Callers(skip+2, pc[:])
1017 if n == 0 {
1018 panic("testing: zero callers found")
1019 }
1020 return pcToName(pc[0])
1021 }
1022
1023 func pcToName(pc uintptr) string {
1024 pcs := []uintptr{pc}
1025 frames := runtime.CallersFrames(pcs)
1026 frame, _ := frames.Next()
1027 return frame.Function
1028 }
1029
1030
1031
1032
1033
1034 func (t *T) Parallel() {
1035 if t.isParallel {
1036 panic("testing: t.Parallel called multiple times")
1037 }
1038 t.isParallel = true
1039
1040
1041
1042
1043 t.duration += time.Since(t.start)
1044
1045
1046 t.parent.sub = append(t.parent.sub, t)
1047 t.raceErrors += race.Errors()
1048
1049 if t.chatty != nil {
1050
1051
1052
1053
1054
1055
1056 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1057 }
1058
1059 t.signal <- true
1060 <-t.parent.barrier
1061 t.context.waitParallel()
1062
1063 if t.chatty != nil {
1064 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1065 }
1066
1067 t.start = time.Now()
1068 t.raceErrors += -race.Errors()
1069 }
1070
1071
1072
1073 type InternalTest struct {
1074 Name string
1075 F func(*T)
1076 }
1077
1078 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
1079
1080 func tRunner(t *T, fn func(t *T)) {
1081 t.runner = callerName(0)
1082
1083
1084
1085
1086
1087 defer func() {
1088 if t.Failed() {
1089 atomic.AddUint32(&numFailed, 1)
1090 }
1091
1092 if t.raceErrors+race.Errors() > 0 {
1093 t.Errorf("race detected during execution of test")
1094 }
1095
1096
1097 err := recover()
1098 signal := true
1099
1100 if !t.finished && err == nil {
1101 err = errNilPanicOrGoexit
1102 for p := t.parent; p != nil; p = p.parent {
1103 if p.finished {
1104 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
1105 err = nil
1106 signal = false
1107 break
1108 }
1109 }
1110 }
1111
1112
1113 didPanic := false
1114 defer func() {
1115 if didPanic {
1116 return
1117 }
1118 if err != nil {
1119 panic(err)
1120 }
1121
1122
1123
1124 t.signal <- signal
1125 }()
1126
1127 doPanic := func(err interface{}) {
1128 t.Fail()
1129 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
1130 t.Logf("cleanup panicked with %v", r)
1131 }
1132
1133 for root := &t.common; root.parent != nil; root = root.parent {
1134 root.mu.Lock()
1135 root.duration += time.Since(root.start)
1136 d := root.duration
1137 root.mu.Unlock()
1138 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
1139 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
1140 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
1141 }
1142 }
1143 didPanic = true
1144 panic(err)
1145 }
1146 if err != nil {
1147 doPanic(err)
1148 }
1149
1150 t.duration += time.Since(t.start)
1151
1152 if len(t.sub) > 0 {
1153
1154
1155 t.context.release()
1156
1157 close(t.barrier)
1158
1159 for _, sub := range t.sub {
1160 <-sub.signal
1161 }
1162 cleanupStart := time.Now()
1163 err := t.runCleanup(recoverAndReturnPanic)
1164 t.duration += time.Since(cleanupStart)
1165 if err != nil {
1166 doPanic(err)
1167 }
1168 if !t.isParallel {
1169
1170 t.context.waitParallel()
1171 }
1172 } else if t.isParallel {
1173
1174
1175 t.context.release()
1176 }
1177 t.report()
1178
1179
1180
1181 t.done = true
1182 if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
1183 t.setRan()
1184 }
1185 }()
1186 defer func() {
1187 if len(t.sub) == 0 {
1188 t.runCleanup(normalPanic)
1189 }
1190 }()
1191
1192 t.start = time.Now()
1193 t.raceErrors = -race.Errors()
1194 fn(t)
1195
1196
1197 t.finished = true
1198 }
1199
1200
1201
1202
1203
1204
1205
1206 func (t *T) Run(name string, f func(t *T)) bool {
1207 atomic.StoreInt32(&t.hasSub, 1)
1208 testName, ok, _ := t.context.match.fullName(&t.common, name)
1209 if !ok || shouldFailFast() {
1210 return true
1211 }
1212
1213
1214
1215 var pc [maxStackLen]uintptr
1216 n := runtime.Callers(2, pc[:])
1217 t = &T{
1218 common: common{
1219 barrier: make(chan bool),
1220 signal: make(chan bool),
1221 name: testName,
1222 parent: &t.common,
1223 level: t.level + 1,
1224 creator: pc[:n],
1225 chatty: t.chatty,
1226 },
1227 context: t.context,
1228 }
1229 t.w = indenter{&t.common}
1230
1231 if t.chatty != nil {
1232 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
1233 }
1234
1235
1236
1237
1238
1239 go tRunner(t, f)
1240 if !<-t.signal {
1241
1242
1243 runtime.Goexit()
1244 }
1245 return !t.failed
1246 }
1247
1248
1249
1250
1251
1252 func (t *T) Deadline() (deadline time.Time, ok bool) {
1253 deadline = t.context.deadline
1254 return deadline, !deadline.IsZero()
1255 }
1256
1257
1258
1259 type testContext struct {
1260 match *matcher
1261 deadline time.Time
1262
1263 mu sync.Mutex
1264
1265
1266 startParallel chan bool
1267
1268
1269
1270 running int
1271
1272
1273 numWaiting int
1274
1275
1276 maxParallel int
1277 }
1278
1279 func newTestContext(maxParallel int, m *matcher) *testContext {
1280 return &testContext{
1281 match: m,
1282 startParallel: make(chan bool),
1283 maxParallel: maxParallel,
1284 running: 1,
1285 }
1286 }
1287
1288 func (c *testContext) waitParallel() {
1289 c.mu.Lock()
1290 if c.running < c.maxParallel {
1291 c.running++
1292 c.mu.Unlock()
1293 return
1294 }
1295 c.numWaiting++
1296 c.mu.Unlock()
1297 <-c.startParallel
1298 }
1299
1300 func (c *testContext) release() {
1301 c.mu.Lock()
1302 if c.numWaiting == 0 {
1303 c.running--
1304 c.mu.Unlock()
1305 return
1306 }
1307 c.numWaiting--
1308 c.mu.Unlock()
1309 c.startParallel <- true
1310 }
1311
1312
1313
1314 var errMain = errors.New("testing: unexpected use of func Main")
1315
1316 type matchStringOnly func(pat, str string) (bool, error)
1317
1318 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
1319 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
1320 func (f matchStringOnly) StopCPUProfile() {}
1321 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
1322 func (f matchStringOnly) ImportPath() string { return "" }
1323 func (f matchStringOnly) StartTestLog(io.Writer) {}
1324 func (f matchStringOnly) StopTestLog() error { return errMain }
1325 func (f matchStringOnly) SetPanicOnExit0(bool) {}
1326
1327
1328
1329
1330
1331
1332
1333 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
1334 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, examples).Run())
1335 }
1336
1337
1338 type M struct {
1339 deps testDeps
1340 tests []InternalTest
1341 benchmarks []InternalBenchmark
1342 examples []InternalExample
1343
1344 timer *time.Timer
1345 afterOnce sync.Once
1346
1347 numRun int
1348
1349
1350
1351 exitCode int
1352 }
1353
1354
1355
1356
1357
1358 type testDeps interface {
1359 ImportPath() string
1360 MatchString(pat, str string) (bool, error)
1361 SetPanicOnExit0(bool)
1362 StartCPUProfile(io.Writer) error
1363 StopCPUProfile()
1364 StartTestLog(io.Writer)
1365 StopTestLog() error
1366 WriteProfileTo(string, io.Writer, int) error
1367 }
1368
1369
1370
1371
1372 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
1373 Init()
1374 return &M{
1375 deps: deps,
1376 tests: tests,
1377 benchmarks: benchmarks,
1378 examples: examples,
1379 }
1380 }
1381
1382
1383 func (m *M) Run() (code int) {
1384 defer func() {
1385 code = m.exitCode
1386 }()
1387
1388
1389
1390
1391
1392 m.numRun++
1393
1394
1395 if !flag.Parsed() {
1396 flag.Parse()
1397 }
1398
1399 if *parallel < 1 {
1400 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
1401 flag.Usage()
1402 m.exitCode = 2
1403 return
1404 }
1405
1406 if len(*matchList) != 0 {
1407 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.examples)
1408 m.exitCode = 0
1409 return
1410 }
1411
1412 parseCpuList()
1413
1414 m.before()
1415 defer m.after()
1416 deadline := m.startAlarm()
1417 haveExamples = len(m.examples) > 0
1418 testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
1419 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
1420 m.stopAlarm()
1421 if !testRan && !exampleRan && *matchBenchmarks == "" {
1422 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
1423 }
1424 if !testOk || !exampleOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
1425 fmt.Println("FAIL")
1426 m.exitCode = 1
1427 return
1428 }
1429
1430 fmt.Println("PASS")
1431 m.exitCode = 0
1432 return
1433 }
1434
1435 func (t *T) report() {
1436 if t.parent == nil {
1437 return
1438 }
1439 dstr := fmtDuration(t.duration)
1440 format := "--- %s: %s (%s)\n"
1441 if t.Failed() {
1442 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
1443 } else if t.chatty != nil {
1444 if t.Skipped() {
1445 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
1446 } else {
1447 t.flushToParent(t.name, format, "PASS", t.name, dstr)
1448 }
1449 }
1450 }
1451
1452 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
1453 if _, err := matchString(*matchList, "non-empty"); err != nil {
1454 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
1455 os.Exit(1)
1456 }
1457
1458 for _, test := range tests {
1459 if ok, _ := matchString(*matchList, test.Name); ok {
1460 fmt.Println(test.Name)
1461 }
1462 }
1463 for _, bench := range benchmarks {
1464 if ok, _ := matchString(*matchList, bench.Name); ok {
1465 fmt.Println(bench.Name)
1466 }
1467 }
1468 for _, example := range examples {
1469 if ok, _ := matchString(*matchList, example.Name); ok {
1470 fmt.Println(example.Name)
1471 }
1472 }
1473 }
1474
1475
1476
1477 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
1478 var deadline time.Time
1479 if *timeout > 0 {
1480 deadline = time.Now().Add(*timeout)
1481 }
1482 ran, ok := runTests(matchString, tests, deadline)
1483 if !ran && !haveExamples {
1484 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
1485 }
1486 return ok
1487 }
1488
1489 func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
1490 ok = true
1491 for _, procs := range cpuList {
1492 runtime.GOMAXPROCS(procs)
1493 for i := uint(0); i < *count; i++ {
1494 if shouldFailFast() {
1495 break
1496 }
1497 ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
1498 ctx.deadline = deadline
1499 t := &T{
1500 common: common{
1501 signal: make(chan bool),
1502 barrier: make(chan bool),
1503 w: os.Stdout,
1504 },
1505 context: ctx,
1506 }
1507 if Verbose() {
1508 t.chatty = newChattyPrinter(t.w)
1509 }
1510 tRunner(t, func(t *T) {
1511 for _, test := range tests {
1512 t.Run(test.Name, test.F)
1513 }
1514
1515
1516
1517 go func() { <-t.signal }()
1518 })
1519 ok = ok && !t.Failed()
1520 ran = ran || t.ran
1521 }
1522 }
1523 return ran, ok
1524 }
1525
1526
1527 func (m *M) before() {
1528 if *memProfileRate > 0 {
1529 runtime.MemProfileRate = *memProfileRate
1530 }
1531 if *cpuProfile != "" {
1532 f, err := os.Create(toOutputDir(*cpuProfile))
1533 if err != nil {
1534 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1535 return
1536 }
1537 if err := m.deps.StartCPUProfile(f); err != nil {
1538 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
1539 f.Close()
1540 return
1541 }
1542
1543 }
1544 if *traceFile != "" {
1545 f, err := os.Create(toOutputDir(*traceFile))
1546 if err != nil {
1547 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1548 return
1549 }
1550 if err := trace.Start(f); err != nil {
1551 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
1552 f.Close()
1553 return
1554 }
1555
1556 }
1557 if *blockProfile != "" && *blockProfileRate >= 0 {
1558 runtime.SetBlockProfileRate(*blockProfileRate)
1559 }
1560 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
1561 runtime.SetMutexProfileFraction(*mutexProfileFraction)
1562 }
1563 if *coverProfile != "" && cover.Mode == "" {
1564 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
1565 os.Exit(2)
1566 }
1567 if *testlog != "" {
1568
1569
1570 var f *os.File
1571 var err error
1572 if m.numRun == 1 {
1573 f, err = os.Create(*testlog)
1574 } else {
1575 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
1576 if err == nil {
1577 f.Seek(0, io.SeekEnd)
1578 }
1579 }
1580 if err != nil {
1581 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1582 os.Exit(2)
1583 }
1584 m.deps.StartTestLog(f)
1585 testlogFile = f
1586 }
1587 if *panicOnExit0 {
1588 m.deps.SetPanicOnExit0(true)
1589 }
1590 }
1591
1592
1593 func (m *M) after() {
1594 m.afterOnce.Do(func() {
1595 m.writeProfiles()
1596 })
1597
1598
1599
1600
1601 if *panicOnExit0 {
1602 m.deps.SetPanicOnExit0(false)
1603 }
1604 }
1605
1606 func (m *M) writeProfiles() {
1607 if *testlog != "" {
1608 if err := m.deps.StopTestLog(); err != nil {
1609 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
1610 os.Exit(2)
1611 }
1612 if err := testlogFile.Close(); err != nil {
1613 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
1614 os.Exit(2)
1615 }
1616 }
1617 if *cpuProfile != "" {
1618 m.deps.StopCPUProfile()
1619 }
1620 if *traceFile != "" {
1621 trace.Stop()
1622 }
1623 if *memProfile != "" {
1624 f, err := os.Create(toOutputDir(*memProfile))
1625 if err != nil {
1626 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1627 os.Exit(2)
1628 }
1629 runtime.GC()
1630 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
1631 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
1632 os.Exit(2)
1633 }
1634 f.Close()
1635 }
1636 if *blockProfile != "" && *blockProfileRate >= 0 {
1637 f, err := os.Create(toOutputDir(*blockProfile))
1638 if err != nil {
1639 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1640 os.Exit(2)
1641 }
1642 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
1643 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
1644 os.Exit(2)
1645 }
1646 f.Close()
1647 }
1648 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
1649 f, err := os.Create(toOutputDir(*mutexProfile))
1650 if err != nil {
1651 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
1652 os.Exit(2)
1653 }
1654 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
1655 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
1656 os.Exit(2)
1657 }
1658 f.Close()
1659 }
1660 if cover.Mode != "" {
1661 coverReport()
1662 }
1663 }
1664
1665
1666
1667 func toOutputDir(path string) string {
1668 if *outputDir == "" || path == "" {
1669 return path
1670 }
1671
1672
1673
1674
1675
1676
1677
1678 if runtime.GOOS == "windows" && len(path) >= 2 {
1679 letter, colon := path[0], path[1]
1680 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
1681
1682 return path
1683 }
1684 }
1685 if os.IsPathSeparator(path[0]) {
1686 return path
1687 }
1688 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
1689 }
1690
1691
1692 func (m *M) startAlarm() time.Time {
1693 if *timeout <= 0 {
1694 return time.Time{}
1695 }
1696
1697 deadline := time.Now().Add(*timeout)
1698 m.timer = time.AfterFunc(*timeout, func() {
1699 m.after()
1700 debug.SetTraceback("all")
1701 panic(fmt.Sprintf("test timed out after %v", *timeout))
1702 })
1703 return deadline
1704 }
1705
1706
1707 func (m *M) stopAlarm() {
1708 if *timeout > 0 {
1709 m.timer.Stop()
1710 }
1711 }
1712
1713 func parseCpuList() {
1714 for _, val := range strings.Split(*cpuListStr, ",") {
1715 val = strings.TrimSpace(val)
1716 if val == "" {
1717 continue
1718 }
1719 cpu, err := strconv.Atoi(val)
1720 if err != nil || cpu <= 0 {
1721 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
1722 os.Exit(1)
1723 }
1724 cpuList = append(cpuList, cpu)
1725 }
1726 if cpuList == nil {
1727 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
1728 }
1729 }
1730
1731 func shouldFailFast() bool {
1732 return *failFast && atomic.LoadUint32(&numFailed) > 0
1733 }
1734
View as plain text