Source file src/pkg/testing/testing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 package testing
95
96 import (
97 "bytes"
98 "flag"
99 "fmt"
100 "os"
101 "runtime"
102 "runtime/pprof"
103 "strconv"
104 "strings"
105 "sync"
106 "time"
107 )
108
109 var (
110
111
112
113
114
115 short = flag.Bool("test.short", false, "run smaller test suite to save time")
116
117
118 chatty = flag.Bool("test.v", false, "verbose: print additional output")
119 match = flag.String("test.run", "", "regular expression to select tests and examples to run")
120 memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
121 memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
122 cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
123 blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution")
124 blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()")
125 timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
126 cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
127 parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
128
129 haveExamples bool
130
131 cpuList []int
132 )
133
134
135
136 type common struct {
137 mu sync.RWMutex
138 output []byte
139 failed bool
140 skipped bool
141
142 start time.Time
143 duration time.Duration
144 self interface{}
145 signal chan interface{}
146 }
147
148
149 func Short() bool {
150 return *short
151 }
152
153
154 func Verbose() bool {
155 return *chatty
156 }
157
158
159
160 func decorate(s string) string {
161 _, file, line, ok := runtime.Caller(3)
162 if ok {
163
164 if index := strings.LastIndex(file, "/"); index >= 0 {
165 file = file[index+1:]
166 } else if index = strings.LastIndex(file, "\\"); index >= 0 {
167 file = file[index+1:]
168 }
169 } else {
170 file = "???"
171 line = 1
172 }
173 buf := new(bytes.Buffer)
174
175 buf.WriteByte('\t')
176 fmt.Fprintf(buf, "%s:%d: ", file, line)
177 lines := strings.Split(s, "\n")
178 if l := len(lines); l > 1 && lines[l-1] == "" {
179 lines = lines[:l-1]
180 }
181 for i, line := range lines {
182 if i > 0 {
183
184 buf.WriteString("\n\t\t")
185 }
186 buf.WriteString(line)
187 }
188 buf.WriteByte('\n')
189 return buf.String()
190 }
191
192
193
194 type T struct {
195 common
196 name string
197 startParallel chan bool
198 }
199
200
201 func (c *common) Fail() {
202 c.mu.Lock()
203 defer c.mu.Unlock()
204 c.failed = true
205 }
206
207
208 func (c *common) Failed() bool {
209 c.mu.RLock()
210 defer c.mu.RUnlock()
211 return c.failed
212 }
213
214
215
216
217
218
219
220 func (c *common) FailNow() {
221 c.Fail()
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 runtime.Goexit()
243 }
244
245
246 func (c *common) log(s string) {
247 c.mu.Lock()
248 defer c.mu.Unlock()
249 c.output = append(c.output, decorate(s)...)
250 }
251
252
253
254
255 func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
256
257
258
259
260 func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
261
262
263 func (c *common) Error(args ...interface{}) {
264 c.log(fmt.Sprintln(args...))
265 c.Fail()
266 }
267
268
269 func (c *common) Errorf(format string, args ...interface{}) {
270 c.log(fmt.Sprintf(format, args...))
271 c.Fail()
272 }
273
274
275 func (c *common) Fatal(args ...interface{}) {
276 c.log(fmt.Sprintln(args...))
277 c.FailNow()
278 }
279
280
281 func (c *common) Fatalf(format string, args ...interface{}) {
282 c.log(fmt.Sprintf(format, args...))
283 c.FailNow()
284 }
285
286
287 func (c *common) Skip(args ...interface{}) {
288 c.log(fmt.Sprintln(args...))
289 c.SkipNow()
290 }
291
292
293 func (c *common) Skipf(format string, args ...interface{}) {
294 c.log(fmt.Sprintf(format, args...))
295 c.SkipNow()
296 }
297
298
299
300
301
302
303 func (c *common) SkipNow() {
304 c.skip()
305 runtime.Goexit()
306 }
307
308 func (c *common) skip() {
309 c.mu.Lock()
310 defer c.mu.Unlock()
311 c.skipped = true
312 }
313
314
315 func (c *common) Skipped() bool {
316 c.mu.RLock()
317 defer c.mu.RUnlock()
318 return c.skipped
319 }
320
321
322
323 func (t *T) Parallel() {
324 t.signal <- (*T)(nil)
325 <-t.startParallel
326 }
327
328
329
330 type InternalTest struct {
331 Name string
332 F func(*T)
333 }
334
335 func tRunner(t *T, test *InternalTest) {
336 t.start = time.Now()
337
338
339
340
341
342 defer func() {
343 t.duration = time.Now().Sub(t.start)
344
345 if err := recover(); err != nil {
346 t.Fail()
347 t.report()
348 panic(err)
349 }
350 t.signal <- t
351 }()
352
353 test.F(t)
354 }
355
356
357
358 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
359 flag.Parse()
360 parseCpuList()
361
362 before()
363 startAlarm()
364 haveExamples = len(examples) > 0
365 testOk := RunTests(matchString, tests)
366 exampleOk := RunExamples(matchString, examples)
367 if !testOk || !exampleOk {
368 fmt.Println("FAIL")
369 os.Exit(1)
370 }
371 fmt.Println("PASS")
372 stopAlarm()
373 RunBenchmarks(matchString, benchmarks)
374 after()
375 }
376
377 func (t *T) report() {
378 tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
379 format := "--- %s: %s %s\n%s"
380 if t.Failed() {
381 fmt.Printf(format, "FAIL", t.name, tstr, t.output)
382 } else if *chatty {
383 if t.Skipped() {
384 fmt.Printf(format, "SKIP", t.name, tstr, t.output)
385 } else {
386 fmt.Printf(format, "PASS", t.name, tstr, t.output)
387 }
388 }
389 }
390
391 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
392 ok = true
393 if len(tests) == 0 && !haveExamples {
394 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
395 return
396 }
397 for _, procs := range cpuList {
398 runtime.GOMAXPROCS(procs)
399
400
401
402
403
404 var collector = make(chan interface{})
405
406 numParallel := 0
407 startParallel := make(chan bool)
408
409 for i := 0; i < len(tests); i++ {
410 matched, err := matchString(*match, tests[i].Name)
411 if err != nil {
412 fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
413 os.Exit(1)
414 }
415 if !matched {
416 continue
417 }
418 testName := tests[i].Name
419 if procs != 1 {
420 testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
421 }
422 t := &T{
423 common: common{
424 signal: make(chan interface{}),
425 },
426 name: testName,
427 startParallel: startParallel,
428 }
429 t.self = t
430 if *chatty {
431 fmt.Printf("=== RUN %s\n", t.name)
432 }
433 go tRunner(t, &tests[i])
434 out := (<-t.signal).(*T)
435 if out == nil {
436 go func() {
437 collector <- <-t.signal
438 }()
439 numParallel++
440 continue
441 }
442 t.report()
443 ok = ok && !out.Failed()
444 }
445
446 running := 0
447 for numParallel+running > 0 {
448 if running < *parallel && numParallel > 0 {
449 startParallel <- true
450 running++
451 numParallel--
452 continue
453 }
454 t := (<-collector).(*T)
455 t.report()
456 ok = ok && !t.Failed()
457 running--
458 }
459 }
460 return
461 }
462
463
464 func before() {
465 if *memProfileRate > 0 {
466 runtime.MemProfileRate = *memProfileRate
467 }
468 if *cpuProfile != "" {
469 f, err := os.Create(*cpuProfile)
470 if err != nil {
471 fmt.Fprintf(os.Stderr, "testing: %s", err)
472 return
473 }
474 if err := pprof.StartCPUProfile(f); err != nil {
475 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
476 f.Close()
477 return
478 }
479
480 }
481 if *blockProfile != "" && *blockProfileRate >= 0 {
482 runtime.SetBlockProfileRate(*blockProfileRate)
483 }
484 }
485
486
487 func after() {
488 if *cpuProfile != "" {
489 pprof.StopCPUProfile()
490 }
491 if *memProfile != "" {
492 f, err := os.Create(*memProfile)
493 if err != nil {
494 fmt.Fprintf(os.Stderr, "testing: %s", err)
495 return
496 }
497 if err = pprof.WriteHeapProfile(f); err != nil {
498 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err)
499 }
500 f.Close()
501 }
502 if *blockProfile != "" && *blockProfileRate >= 0 {
503 f, err := os.Create(*blockProfile)
504 if err != nil {
505 fmt.Fprintf(os.Stderr, "testing: %s", err)
506 return
507 }
508 if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {
509 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *blockProfile, err)
510 }
511 f.Close()
512 }
513 }
514
515 var timer *time.Timer
516
517
518 func startAlarm() {
519 if *timeout > 0 {
520 timer = time.AfterFunc(*timeout, alarm)
521 }
522 }
523
524
525 func stopAlarm() {
526 if *timeout > 0 {
527 timer.Stop()
528 }
529 }
530
531
532 func alarm() {
533 panic("test timed out")
534 }
535
536 func parseCpuList() {
537 if len(*cpuListStr) == 0 {
538 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
539 } else {
540 for _, val := range strings.Split(*cpuListStr, ",") {
541 cpu, err := strconv.Atoi(val)
542 if err != nil || cpu <= 0 {
543 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu", val)
544 os.Exit(1)
545 }
546 cpuList = append(cpuList, cpu)
547 }
548 }
549 }
View as plain text