Home | History | Annotate | Download | only in testdeps
      1 // Copyright 2016 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Package testdeps provides access to dependencies needed by test execution.
      6 //
      7 // This package is imported by the generated main package, which passes
      8 // TestDeps into testing.Main. This allows tests to use packages at run time
      9 // without making those packages direct dependencies of package testing.
     10 // Direct dependencies of package testing are harder to write tests for.
     11 package testdeps
     12 
     13 import (
     14 	"bufio"
     15 	"internal/testlog"
     16 	"io"
     17 	"regexp"
     18 	"runtime/pprof"
     19 	"strings"
     20 	"sync"
     21 )
     22 
     23 // TestDeps is an implementation of the testing.testDeps interface,
     24 // suitable for passing to testing.MainStart.
     25 type TestDeps struct{}
     26 
     27 var matchPat string
     28 var matchRe *regexp.Regexp
     29 
     30 func (TestDeps) MatchString(pat, str string) (result bool, err error) {
     31 	if matchRe == nil || matchPat != pat {
     32 		matchPat = pat
     33 		matchRe, err = regexp.Compile(matchPat)
     34 		if err != nil {
     35 			return
     36 		}
     37 	}
     38 	return matchRe.MatchString(str), nil
     39 }
     40 
     41 func (TestDeps) StartCPUProfile(w io.Writer) error {
     42 	return pprof.StartCPUProfile(w)
     43 }
     44 
     45 func (TestDeps) StopCPUProfile() {
     46 	pprof.StopCPUProfile()
     47 }
     48 
     49 func (TestDeps) WriteHeapProfile(w io.Writer) error {
     50 	return pprof.WriteHeapProfile(w)
     51 }
     52 
     53 func (TestDeps) WriteProfileTo(name string, w io.Writer, debug int) error {
     54 	return pprof.Lookup(name).WriteTo(w, debug)
     55 }
     56 
     57 // ImportPath is the import path of the testing binary, set by the generated main function.
     58 var ImportPath string
     59 
     60 func (TestDeps) ImportPath() string {
     61 	return ImportPath
     62 }
     63 
     64 // testLog implements testlog.Interface, logging actions by package os.
     65 type testLog struct {
     66 	mu  sync.Mutex
     67 	w   *bufio.Writer
     68 	set bool
     69 }
     70 
     71 func (l *testLog) Getenv(key string) {
     72 	l.add("getenv", key)
     73 }
     74 
     75 func (l *testLog) Open(name string) {
     76 	l.add("open", name)
     77 }
     78 
     79 func (l *testLog) Stat(name string) {
     80 	l.add("stat", name)
     81 }
     82 
     83 func (l *testLog) Chdir(name string) {
     84 	l.add("chdir", name)
     85 }
     86 
     87 // add adds the (op, name) pair to the test log.
     88 func (l *testLog) add(op, name string) {
     89 	if strings.Contains(name, "\n") || name == "" {
     90 		return
     91 	}
     92 
     93 	l.mu.Lock()
     94 	defer l.mu.Unlock()
     95 	if l.w == nil {
     96 		return
     97 	}
     98 	l.w.WriteString(op)
     99 	l.w.WriteByte(' ')
    100 	l.w.WriteString(name)
    101 	l.w.WriteByte('\n')
    102 }
    103 
    104 var log testLog
    105 var didSetLogger bool
    106 
    107 func (TestDeps) StartTestLog(w io.Writer) {
    108 	log.mu.Lock()
    109 	log.w = bufio.NewWriter(w)
    110 	if !log.set {
    111 		// Tests that define TestMain and then run m.Run multiple times
    112 		// will call StartTestLog/StopTestLog multiple times.
    113 		// Checking log.set avoids calling testlog.SetLogger multiple times
    114 		// (which will panic) and also avoids writing the header multiple times.
    115 		log.set = true
    116 		testlog.SetLogger(&log)
    117 		log.w.WriteString("# test log\n") // known to cmd/go/internal/test/test.go
    118 	}
    119 	log.mu.Unlock()
    120 }
    121 
    122 func (TestDeps) StopTestLog() error {
    123 	log.mu.Lock()
    124 	defer log.mu.Unlock()
    125 	err := log.w.Flush()
    126 	log.w = nil
    127 	return err
    128 }
    129