-
Notifications
You must be signed in to change notification settings - Fork 19
/
util.go
116 lines (100 loc) · 2.32 KB
/
util.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package ssh
import (
"fmt"
"regexp"
"runtime"
"strings"
"testing"
"time"
)
// utilities, error types, and debugging machinery.
// xtestLeakCheckOn controls leak checking.
//
// change this to true to check for goroutine leaks
// in the tests. Turn to off (false) when not in
// use because it slows down each test by
// 1 second to let the final goroutine
// count stabilize after the test.
const xtestLeakCheckOn = false
// errWhere satisfies net.Error
type errWhere struct {
msg string
who *idleTimer
when time.Time
where string
}
func newErrTimeout(msg string, who *idleTimer) *errWhere {
return newErrWhere("timeout:"+msg, who)
}
var regexTestname = regexp.MustCompile(`Test[^\s\(]+`)
type xtraTestState struct {
name string
numStartingGoroutines int
}
// Testbegin example:
//
// At the top of each test put this line:
//
// defer xtestend(xtestbegin(t))
//
func xtestbegin(t *testing.T) *xtraTestState {
if xtestLeakCheckOn {
ct := testname()
return &xtraTestState{
name: ct,
numStartingGoroutines: runtime.NumGoroutine(),
}
}
return nil
}
func xtestend(x *xtraTestState) {
if xtestLeakCheckOn {
time.Sleep(time.Second)
endCount := runtime.NumGoroutine()
if endCount != x.numStartingGoroutines {
panic(fmt.Sprintf("test leaks goroutines: '%s': ended with %v >= started with %v",
x.name, endCount, x.numStartingGoroutines))
}
}
}
func testname() string {
s := stacktrace()
slc := regexTestname.FindAllString(s, -1)
n := len(slc)
if n == 0 {
return ""
}
return slc[n-1]
}
func stacktrace() string {
sz := 512
var stack []byte
for {
stack = make([]byte, sz)
nw := runtime.Stack(stack, false)
if nw >= sz {
sz = sz * 2
} else {
stack = stack[:nw]
break
}
}
return string(stack)
}
func newErrWhere(msg string, who *idleTimer) *errWhere {
return &errWhere{msg: msg, who: who, when: time.Now()}
}
func newErrWhereWithStack(msg string, who *idleTimer) *errWhere {
return &errWhere{msg: msg, who: who, when: time.Now(), where: stacktrace()}
}
func (e errWhere) Error() string {
return fmt.Sprintf("%s, from idleTimer %p, generated at '%v'. stack='\n%v\n'",
e.msg, e.who, e.when, string(e.where))
}
func (e errWhere) Timeout() bool {
return strings.HasPrefix(e.msg, "timeout:")
}
func (e errWhere) Temporary() bool {
// Is the error temporary?
return true
}