go.etcd.io/etcd@v3.3.27+incompatible/clientv3/integration/watch_fragment_test.go (about) 1 // Copyright 2018 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !cluster_proxy 16 17 package integration 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/coreos/etcd/clientv3" 27 "github.com/coreos/etcd/integration" 28 "github.com/coreos/etcd/pkg/testutil" 29 ) 30 31 // TestWatchFragmentDisable ensures that large watch 32 // response exceeding server-side request limit can 33 // arrive even without watch response fragmentation. 34 func TestWatchFragmentDisable(t *testing.T) { 35 testWatchFragment(t, false, false) 36 } 37 38 // TestWatchFragmentDisableWithGRPCLimit verifies 39 // large watch response exceeding server-side request 40 // limit and client-side gRPC response receive limit 41 // cannot arrive without watch events fragmentation, 42 // because multiple events exceed client-side gRPC 43 // response receive limit. 44 func TestWatchFragmentDisableWithGRPCLimit(t *testing.T) { 45 testWatchFragment(t, false, true) 46 } 47 48 // TestWatchFragmentEnable ensures that large watch 49 // response exceeding server-side request limit arrive 50 // with watch response fragmentation. 51 func TestWatchFragmentEnable(t *testing.T) { 52 testWatchFragment(t, true, false) 53 } 54 55 // TestWatchFragmentEnableWithGRPCLimit verifies 56 // large watch response exceeding server-side request 57 // limit and client-side gRPC response receive limit 58 // can arrive only when watch events are fragmented. 59 func TestWatchFragmentEnableWithGRPCLimit(t *testing.T) { 60 testWatchFragment(t, true, true) 61 } 62 63 // testWatchFragment triggers watch response that spans over multiple 64 // revisions exceeding server request limits when combined. 65 func testWatchFragment(t *testing.T, fragment, exceedRecvLimit bool) { 66 cfg := &integration.ClusterConfig{ 67 Size: 1, 68 MaxRequestBytes: 1.5 * 1024 * 1024, 69 } 70 if exceedRecvLimit { 71 cfg.ClientMaxCallRecvMsgSize = 1.5 * 1024 * 1024 72 } 73 clus := integration.NewClusterV3(t, cfg) 74 defer clus.Terminate(t) 75 76 cli := clus.Client(0) 77 errc := make(chan error) 78 for i := 0; i < 10; i++ { 79 go func(i int) { 80 _, err := cli.Put(context.TODO(), 81 fmt.Sprint("foo", i), 82 strings.Repeat("a", 1024*1024), 83 ) 84 errc <- err 85 }(i) 86 } 87 for i := 0; i < 10; i++ { 88 if err := <-errc; err != nil { 89 t.Fatalf("failed to put: %v", err) 90 } 91 } 92 93 opts := []clientv3.OpOption{clientv3.WithPrefix(), clientv3.WithRev(1)} 94 if fragment { 95 opts = append(opts, clientv3.WithFragment()) 96 } 97 wch := cli.Watch(context.TODO(), "foo", opts...) 98 99 // expect 10 MiB watch response 100 select { 101 case ws := <-wch: 102 // without fragment, should exceed gRPC client receive limit 103 if !fragment && exceedRecvLimit { 104 if len(ws.Events) != 0 { 105 t.Fatalf("expected 0 events with watch fragmentation, got %d", len(ws.Events)) 106 } 107 exp := "code = ResourceExhausted desc = grpc: received message larger than max (" 108 if !strings.Contains(ws.Err().Error(), exp) { 109 t.Fatalf("expected 'ResourceExhausted' error, got %v", ws.Err()) 110 } 111 return 112 } 113 114 // still expect merged watch events 115 if len(ws.Events) != 10 { 116 t.Fatalf("expected 10 events with watch fragmentation, got %d", len(ws.Events)) 117 } 118 if ws.Err() != nil { 119 t.Fatalf("unexpected error %v", ws.Err()) 120 } 121 122 case <-time.After(testutil.RequestTimeout): 123 t.Fatalf("took too long to receive events") 124 } 125 }