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