@@ -5,7 +5,10 @@ import (
55 "runtime"
66 "sync"
77 "testing"
8+ "testing/synctest"
89 "time"
10+
11+ "github.com/stretchr/testify/assert"
912)
1013
1114const timeout = 2 * time .Second
@@ -201,36 +204,43 @@ func TestGoexitFromHandler(t *testing.T) {
201204
202205func TestCancelInactiveHandler (t * testing.T ) {
203206 // The usual case of canceling a watch, where no handler is active at the time
204- // of cancellation. Once we cancel, no further handler calls should be made.
207+ // of cancellation.
208+ synctest .Test (t , func (t * testing.T ) {
209+ notify := make (chan string )
210+ v := NewValue ("alice" )
211+ w := v .Watch (func (x string ) { notify <- x })
212+
213+ // Deal with the initial notification. Then, wait for the handler goroutine
214+ // to exit before canceling the watch.
215+ assert .Equal (t , "alice" , <- notify )
216+ synctest .Wait ()
217+ w .Cancel ()
205218
206- v := NewValue ("alice" )
207- notify := make (chan string , 1 )
208- w := v .Watch (func (x string ) {
219+ // Set another value, and ensure that we're not notified even after
220+ // background goroutines have settled.
221+ v .Set ("bob" )
222+ synctest .Wait ()
209223 select {
210- case notify <- x :
224+ case <- notify :
225+ t .Error ("watcher notified after being canceled" )
211226 default :
212227 }
213228 })
214-
215- assertNextReceive (t , notify , "alice" )
216- forceRuntimeProgress () // Try to ensure the handler has fully terminated.
217-
218- w .Cancel ()
219- v .Set ("bob" )
220- assertBlockedAfter (forceRuntimeProgress , t , notify )
221229}
222230
223231func TestDoubleCancelInactiveHandler (t * testing.T ) {
224- // A specific test for calling Cancel twice on an inactive handler, and
225- // ensuring we don't panic.
226-
227- v := NewValue ("alice" )
228- w := v .Watch (func (x string ) {})
229- forceRuntimeProgress () // Try to ensure the initial handler has fully terminated.
230-
231- w .Cancel ()
232- w .Cancel ()
233- assertWatchTerminates (t , w )
232+ // A specific test for calling Cancel twice on an inactive handler.
233+ synctest .Test (t , func (t * testing.T ) {
234+ v := NewValue ("alice" )
235+ w := v .Watch (func (x string ) {})
236+
237+ // Wait for the initial handler to exit, then cancel the watch twice.
238+ // The goal is simply to not panic.
239+ synctest .Wait ()
240+ w .Cancel ()
241+ w .Cancel ()
242+ w .Wait ()
243+ })
234244}
235245
236246func TestCancelBlockedWatcher (t * testing.T ) {
@@ -299,29 +309,37 @@ func TestDoubleCancelFromHandler(t *testing.T) {
299309func TestWait (t * testing.T ) {
300310 // A specific test to ensure that Wait properly blocks until the watch has
301311 // terminated.
312+ synctest .Test (t , func (t * testing.T ) {
313+ notify := make (chan string )
314+ v := NewValue ("alice" )
315+ w := v .Watch (func (x string ) { notify <- x })
316+
317+ // Ensure that we have a handler in flight from the initial notification.
318+ synctest .Wait ()
319+
320+ // Start waiting in the background. We should remain blocked.
321+ done := make (chan struct {})
322+ go func () { defer close (done ); w .Wait () }()
323+ synctest .Wait ()
324+ select {
325+ case <- done :
326+ t .Fatal ("watcher finished waiting before cancellation" )
327+ default :
328+ }
302329
303- v := NewValue ("alice" )
330+ // Cancel the watch, and ensure that Wait is still blocked.
331+ w .Cancel ()
332+ synctest .Wait ()
333+ select {
334+ case <- done :
335+ t .Fatal ("watcher finished waiting before handler exit" )
336+ default :
337+ }
304338
305- block , notify := make (chan struct {}), make (chan string )
306- w := v .Watch (func (x string ) {
307- <- block
308- notify <- x
339+ // Allow the handler to finish. At this point, we should become unblocked.
340+ assert .Equal (t , "alice" , <- notify )
341+ <- done
309342 })
310-
311- // Ensure that we have a handler in flight.
312- block <- struct {}{}
313-
314- // Start waiting in the background. We should remain blocked.
315- done := makeWaitChannel (w )
316- assertBlockedAfter (forceRuntimeProgress , t , done )
317-
318- // Cancel the watch, and ensure that we are still blocked.
319- w .Cancel ()
320- assertBlockedAfter (forceRuntimeProgress , t , done )
321-
322- // Allow the handler to finish. At this point, we should become unblocked.
323- assertNextReceive (t , notify , "alice" )
324- assertWatchTerminates (t , w )
325343}
326344
327345// makeWaitChannel returns a channel that will be closed after w.Wait returns.
0 commit comments