github.com/glycerine/xcryptossh@v7.0.4+incompatible/util.go (about) 1 package ssh 2 3 import ( 4 "fmt" 5 "regexp" 6 "runtime" 7 "strings" 8 "testing" 9 "time" 10 ) 11 12 // utilities, error types, and debugging machinery. 13 14 // xtestLeakCheckOn controls leak checking. 15 // 16 // change this to true to check for goroutine leaks 17 // in the tests. Turn to off (false) when not in 18 // use because it slows down each test by 19 // 1 second to let the final goroutine 20 // count stabilize after the test. 21 const xtestLeakCheckOn = false 22 23 // errWhere satisfies net.Error 24 type errWhere struct { 25 msg string 26 who *IdleTimer 27 when time.Time 28 where string 29 } 30 31 func newErrTimeout(msg string, who *IdleTimer) *errWhere { 32 return newErrWhere("timeout:"+msg, who) 33 } 34 35 var regexTestname = regexp.MustCompile(`Test[^\s\(]+`) 36 37 type xtraTestState struct { 38 name string 39 numStartingGoroutines int 40 } 41 42 // Testbegin example: 43 // 44 // At the top of each test put this line: 45 // 46 // defer xtestend(xtestbegin(t)) 47 // 48 func xtestbegin(t *testing.T) *xtraTestState { 49 if xtestLeakCheckOn { 50 ct := testname() 51 return &xtraTestState{ 52 name: ct, 53 numStartingGoroutines: runtime.NumGoroutine(), 54 } 55 } 56 return nil 57 } 58 59 func xtestend(x *xtraTestState) { 60 if xtestLeakCheckOn { 61 time.Sleep(time.Second) 62 endCount := runtime.NumGoroutine() 63 if endCount != x.numStartingGoroutines { 64 panic(fmt.Sprintf("test leaks goroutines: '%s': ended with %v >= started with %v", 65 x.name, endCount, x.numStartingGoroutines)) 66 } 67 } 68 } 69 70 func testname() string { 71 s := stacktrace() 72 slc := regexTestname.FindAllString(s, -1) 73 n := len(slc) 74 if n == 0 { 75 return "" 76 } 77 return slc[n-1] 78 } 79 80 func stacktrace() string { 81 sz := 512 82 var stack []byte 83 for { 84 stack = make([]byte, sz) 85 nw := runtime.Stack(stack, false) 86 if nw >= sz { 87 sz = sz * 2 88 } else { 89 stack = stack[:nw] 90 break 91 } 92 } 93 return string(stack) 94 } 95 96 func newErrWhere(msg string, who *IdleTimer) *errWhere { 97 return &errWhere{msg: msg, who: who, when: time.Now()} 98 } 99 100 func newErrWhereWithStack(msg string, who *IdleTimer) *errWhere { 101 return &errWhere{msg: msg, who: who, when: time.Now(), where: stacktrace()} 102 } 103 104 func (e errWhere) Error() string { 105 return fmt.Sprintf("%s, from IdleTimer %p, generated at '%v'. stack='\n%v\n'", 106 e.msg, e.who, e.when, string(e.where)) 107 } 108 109 func (e errWhere) Timeout() bool { 110 return strings.HasPrefix(e.msg, "timeout:") 111 } 112 113 func (e errWhere) Temporary() bool { 114 // Is the error temporary? 115 return true 116 }