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