@@ -25,6 +25,7 @@ import (
2525 "testing"
2626 "time"
2727
28+ "github.com/google/go-cmp/cmp"
2829 "github.com/stretchr/testify/require"
2930 "google.golang.org/grpc/metadata"
3031
@@ -1133,3 +1134,80 @@ func testWatchClose(t *testing.T, wctx *watchctx) {
11331134 wresp , ok := <- wch
11341135 require .Falsef (t , ok , "read wch got %v; expected closed channel" , wresp )
11351136}
1137+
1138+ func TestWatch (t * testing.T ) {
1139+ integration2 .BeforeTest (t )
1140+ clus := integration2 .NewCluster (t , & integration2.ClusterConfig {Size : 1 })
1141+ t .Cleanup (func () { clus .Terminate (t ) })
1142+ client := clus .Client (0 )
1143+
1144+ tcs := []struct {
1145+ name string
1146+ key string
1147+ opts []clientv3.OpOption
1148+ wantError error
1149+ wantEvents []* clientv3.Event
1150+ }{
1151+ {
1152+ name : "Watch with negative revision" ,
1153+ key : "/" ,
1154+ opts : []clientv3.OpOption {clientv3 .WithRev (- 1 )},
1155+ wantError : rpctypes .ErrCompacted ,
1156+ },
1157+ {
1158+ name : "Watch with zero revision" ,
1159+ key : "/" ,
1160+ opts : []clientv3.OpOption {clientv3 .WithRev (0 )},
1161+ },
1162+ {
1163+ name : "Watch with positive revision" ,
1164+ key : "/" ,
1165+ opts : []clientv3.OpOption {clientv3 .WithRev (1 )},
1166+ },
1167+ }
1168+ ctx := t .Context ()
1169+
1170+ t .Log ("Open watches" )
1171+ watches := make ([]clientv3.WatchChan , len (tcs ))
1172+ for i , tc := range tcs {
1173+ watchCtx , cancel := context .WithTimeout (ctx , time .Second )
1174+ defer cancel ()
1175+ watches [i ] = client .Watch (watchCtx , tc .key , tc .opts ... )
1176+ }
1177+
1178+ t .Log ("Validate" )
1179+ for i , tc := range tcs {
1180+ t .Run (tc .name , func (t * testing.T ) {
1181+ events , err := collectEvents (ctx , watches [i ])
1182+ if tc .wantError == nil {
1183+ require .NoError (t , err )
1184+ } else {
1185+ require .ErrorContains (t , err , tc .wantError .Error ())
1186+ }
1187+ if diff := cmp .Diff (tc .wantEvents , events ); diff != "" {
1188+ t .Errorf ("unexpected events (-want +got):\n %s" , diff )
1189+ }
1190+ })
1191+ }
1192+ }
1193+
1194+ func collectEvents (ctx context.Context , watch clientv3.WatchChan ) (events []* clientv3.Event , err error ) {
1195+ for {
1196+ select {
1197+ case resp , ok := <- watch :
1198+ if ! ok {
1199+ return events , nil
1200+ }
1201+ err := resp .Err ()
1202+ if err != nil {
1203+ return events , err
1204+ }
1205+ events = append (events , resp .Events ... )
1206+ case <- ctx .Done ():
1207+ return events , ctx .Err ()
1208+ // Watch resync interval * 1.5
1209+ case <- time .After (150 * time .Millisecond ):
1210+ return events , nil
1211+ }
1212+ }
1213+ }
0 commit comments