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