@@ -185,3 +185,148 @@ func (s) TestStreamWorkers_GracefulStopAndStop(t *testing.T) {
185185
186186 ss .S .GracefulStop ()
187187}
188+
189+ // Tests the WaitForHandlers ServerOption by leaving an RPC running while Stop
190+ // is called, and ensures Stop doesn't return until the handler returns.
191+ func (s ) TestServer_WaitForHandlers (t * testing.T ) {
192+ started := grpcsync .NewEvent ()
193+ blockCalls := grpcsync .NewEvent ()
194+
195+ // This stub server does not properly respect the stream context, so it will
196+ // not exit when the context is canceled.
197+ ss := stubserver.StubServer {
198+ FullDuplexCallF : func (stream testgrpc.TestService_FullDuplexCallServer ) error {
199+ started .Fire ()
200+ <- blockCalls .Done ()
201+ return nil
202+ },
203+ }
204+ if err := ss .Start ([]grpc.ServerOption {grpc .WaitForHandlers (true )}); err != nil {
205+ t .Fatal ("Error starting server:" , err )
206+ }
207+ defer ss .Stop ()
208+
209+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
210+ defer cancel ()
211+
212+ // Start one RPC to the server.
213+ ctx1 , cancel1 := context .WithCancel (ctx )
214+ _ , err := ss .Client .FullDuplexCall (ctx1 )
215+ if err != nil {
216+ t .Fatal ("Error staring call:" , err )
217+ }
218+
219+ // Wait for the handler to be invoked.
220+ select {
221+ case <- started .Done ():
222+ case <- ctx .Done ():
223+ t .Fatalf ("Timed out waiting for RPC to start on server." )
224+ }
225+
226+ // Cancel it on the client. The server handler will still be running.
227+ cancel1 ()
228+
229+ // Close the connection. This might be sufficient to allow the server to
230+ // return if it doesn't properly wait for outstanding method handlers to
231+ // return.
232+ ss .CC .Close ()
233+
234+ // Try to Stop() the server, which should block indefinitely (until
235+ // blockCalls is fired).
236+ stopped := grpcsync .NewEvent ()
237+ go func () {
238+ ss .S .Stop ()
239+ stopped .Fire ()
240+ }()
241+
242+ // Wait 100ms and ensure stopped does not fire.
243+ select {
244+ case <- stopped .Done ():
245+ trace := make ([]byte , 4096 )
246+ trace = trace [0 :runtime .Stack (trace , true )]
247+ blockCalls .Fire ()
248+ t .Fatalf ("Server returned from Stop() illegally. Stack trace:\n %v" , string (trace ))
249+ case <- time .After (100 * time .Millisecond ):
250+ // Success; unblock the call and wait for stopped.
251+ blockCalls .Fire ()
252+ }
253+
254+ select {
255+ case <- stopped .Done ():
256+ case <- ctx .Done ():
257+ t .Fatalf ("Timed out waiting for second RPC to start on server." )
258+ }
259+ }
260+
261+ // Tests that GracefulStop will wait for all method handlers to return by
262+ // blocking a handler and ensuring GracefulStop doesn't return until after it is
263+ // unblocked.
264+ func (s ) TestServer_GracefulStopWaits (t * testing.T ) {
265+ started := grpcsync .NewEvent ()
266+ blockCalls := grpcsync .NewEvent ()
267+
268+ // This stub server does not properly respect the stream context, so it will
269+ // not exit when the context is canceled.
270+ ss := stubserver.StubServer {
271+ FullDuplexCallF : func (stream testgrpc.TestService_FullDuplexCallServer ) error {
272+ started .Fire ()
273+ <- blockCalls .Done ()
274+ return nil
275+ },
276+ }
277+ if err := ss .Start (nil ); err != nil {
278+ t .Fatal ("Error starting server:" , err )
279+ }
280+ defer ss .Stop ()
281+
282+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
283+ defer cancel ()
284+
285+ // Start one RPC to the server.
286+ ctx1 , cancel1 := context .WithCancel (ctx )
287+ _ , err := ss .Client .FullDuplexCall (ctx1 )
288+ if err != nil {
289+ t .Fatal ("Error staring call:" , err )
290+ }
291+
292+ // Wait for the handler to be invoked.
293+ select {
294+ case <- started .Done ():
295+ case <- ctx .Done ():
296+ t .Fatalf ("Timed out waiting for RPC to start on server." )
297+ }
298+
299+ // Cancel it on the client. The server handler will still be running.
300+ cancel1 ()
301+
302+ // Close the connection. This might be sufficient to allow the server to
303+ // return if it doesn't properly wait for outstanding method handlers to
304+ // return.
305+ ss .CC .Close ()
306+
307+ // Try to Stop() the server, which should block indefinitely (until
308+ // blockCalls is fired).
309+ stopped := grpcsync .NewEvent ()
310+ go func () {
311+ ss .S .GracefulStop ()
312+ stopped .Fire ()
313+ }()
314+
315+ // Wait 100ms and ensure stopped does not fire.
316+ select {
317+ case <- stopped .Done ():
318+ trace := make ([]byte , 4096 )
319+ trace = trace [0 :runtime .Stack (trace , true )]
320+ blockCalls .Fire ()
321+ t .Fatalf ("Server returned from Stop() illegally. Stack trace:\n %v" , string (trace ))
322+ case <- time .After (100 * time .Millisecond ):
323+ // Success; unblock the call and wait for stopped.
324+ blockCalls .Fire ()
325+ }
326+
327+ select {
328+ case <- stopped .Done ():
329+ case <- ctx .Done ():
330+ t .Fatalf ("Timed out waiting for second RPC to start on server." )
331+ }
332+ }
0 commit comments