@@ -2,7 +2,9 @@ package concurrent
22
33import (
44 "context"
5+ "fmt"
56 "testing"
7+ "time"
68
79 "go.uber.org/mock/gomock"
810 mock "go.uber.org/mock/sample/concurrent/mock"
@@ -22,6 +24,26 @@ func call(ctx context.Context, m Math) (int, error) {
2224 }
2325}
2426
27+ func waitForMocks (ctx context.Context , ctrl * gomock.Controller ) error {
28+ ticker := time .NewTicker (1 * time .Millisecond )
29+ defer ticker .Stop ()
30+
31+ timeout := time .After (3 * time .Millisecond )
32+
33+ for {
34+ select {
35+ case <- ticker .C :
36+ if ctrl .Satisfied () {
37+ return nil
38+ }
39+ case <- timeout :
40+ return fmt .Errorf ("timeout waiting for mocks to be satisfied" )
41+ case <- ctx .Done ():
42+ return fmt .Errorf ("context cancelled" )
43+ }
44+ }
45+ }
46+
2547// TestConcurrentFails is expected to fail (and is disabled). It
2648// demonstrates how to use gomock.WithContext to interrupt the test
2749// from a different goroutine.
@@ -42,3 +64,26 @@ func TestConcurrentWorks(t *testing.T) {
4264 t .Error ("call failed:" , err )
4365 }
4466}
67+
68+ func TestCancelWhenMocksSatisfied (t * testing.T ) {
69+ ctrl , ctx := gomock .WithContext (context .Background (), t )
70+ m := mock .NewMockMath (ctrl )
71+ m .EXPECT ().Sum (1 , 2 ).Return (3 ).MinTimes (1 )
72+
73+ // This goroutine calls the mock and then waits for the context to be done.
74+ go func () {
75+ for {
76+ m .Sum (1 , 2 )
77+ select {
78+ case <- ctx .Done ():
79+ return
80+ }
81+ }
82+ }()
83+
84+ // waitForMocks spawns another goroutine which blocks until ctrl.Satisfied() is true.
85+ if err := waitForMocks (ctx , ctrl ); err != nil {
86+ t .Error ("call failed:" , err )
87+ }
88+ ctrl .Finish ()
89+ }
0 commit comments