7
7
"io/ioutil"
8
8
"net"
9
9
"os"
10
+ "runtime/pprof"
10
11
"strings"
11
12
"sync"
12
13
"syscall"
@@ -98,18 +99,19 @@ const parallelTestShutdownDeadlock = 20
98
99
99
100
func TestShutdownDeadlock (t * testing.T ) {
100
101
for i := 0 ; i < parallelTestShutdownDeadlock ; i ++ {
102
+ i := i
101
103
t .Run ("" , func (t * testing.T ) {
102
104
t .Parallel ()
103
- testShutdownDeadlock (t )
105
+ testShutdownDeadlock (t , i )
104
106
})
105
107
}
106
108
}
107
- func testShutdownDeadlock (t * testing.T ) {
109
+ func testShutdownDeadlock (t * testing.T , uuid int ) {
108
110
tempPath , err := ioutil .TempFile ("" , "" )
109
111
require .Nil (t , err )
110
112
defer os .Remove (tempPath .Name ())
111
113
112
- retUUID := osquery .ExtensionRouteUUID (0 )
114
+ retUUID := osquery .ExtensionRouteUUID (uuid )
113
115
mock := & MockExtensionManager {
114
116
RegisterExtensionFunc : func (info * osquery.InternalExtensionInfo , registry osquery.ExtensionRegistry ) (* osquery.ExtensionStatus , error ) {
115
117
return & osquery.ExtensionStatus {Code : 0 , UUID : retUUID }, nil
@@ -119,16 +121,22 @@ func testShutdownDeadlock(t *testing.T) {
119
121
},
120
122
CloseFunc : func () {},
121
123
}
122
- server := ExtensionManagerServer {serverClient : mock , sockPath : tempPath .Name ()}
124
+ server := ExtensionManagerServer {
125
+ serverClient : mock ,
126
+ sockPath : tempPath .Name (),
127
+ timeout : defaultTimeout ,
128
+ }
123
129
124
- wait := sync.WaitGroup {}
130
+ var wait sync.WaitGroup
125
131
126
- wait .Add (1 )
127
132
go func () {
133
+ // We do not wait for this routine to finish because thrift.TServer.Serve
134
+ // seems to sometimes hang after shutdowns. (This test is just testing
135
+ // the Shutdown doesn't hang.)
128
136
err := server .Start ()
129
- require .Nil (t , err )
130
- wait .Done ()
137
+ require .NoError (t , err )
131
138
}()
139
+
132
140
// Wait for server to be set up
133
141
server .waitStarted ()
134
142
@@ -138,10 +146,17 @@ func testShutdownDeadlock(t *testing.T) {
138
146
addr , err := net .ResolveUnixAddr ("unix" , listenPath )
139
147
require .Nil (t , err )
140
148
timeout := 500 * time .Millisecond
141
- trans := thrift .NewTSocketFromAddrTimeout (addr , timeout , timeout )
142
- err = trans .Open ()
143
- require .Nil (t , err )
144
- client := osquery .NewExtensionManagerClientFactory (trans ,
149
+ opened := false
150
+ attempt := 0
151
+ var transport * thrift.TSocket
152
+ for ! opened && attempt < 10 {
153
+ transport = thrift .NewTSocketFromAddrTimeout (addr , timeout , timeout )
154
+ err = transport .Open ()
155
+ opened = err == nil
156
+ attempt ++
157
+ }
158
+ require .NoError (t , err )
159
+ client := osquery .NewExtensionManagerClientFactory (transport ,
145
160
thrift .NewTBinaryProtocolFactoryDefault ())
146
161
147
162
// Simultaneously call shutdown through a request from the client and
@@ -156,7 +171,7 @@ func testShutdownDeadlock(t *testing.T) {
156
171
go func () {
157
172
defer wait .Done ()
158
173
err = server .Shutdown (context .Background ())
159
- require .Nil (t , err )
174
+ require .NoError (t , err )
160
175
}()
161
176
162
177
// Track whether shutdown completed
@@ -171,7 +186,8 @@ func testShutdownDeadlock(t *testing.T) {
171
186
select {
172
187
case <- completed :
173
188
// Success. Do nothing.
174
- case <- time .After (5 * time .Second ):
189
+ case <- time .After (10 * time .Second ):
190
+ pprof .Lookup ("goroutine" ).WriteTo (os .Stdout , 1 )
175
191
t .Fatal ("hung on shutdown" )
176
192
}
177
193
}
0 commit comments