go.etcd.io/etcd@v3.3.27+incompatible/integration/v3_grpc_inflight_test.go (about) 1 // Copyright 2016 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 package integration 16 17 import ( 18 "context" 19 "sync" 20 "testing" 21 "time" 22 23 "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes" 24 pb "github.com/coreos/etcd/etcdserver/etcdserverpb" 25 "github.com/coreos/etcd/pkg/testutil" 26 27 "google.golang.org/grpc" 28 "google.golang.org/grpc/codes" 29 "google.golang.org/grpc/status" 30 ) 31 32 // TestV3MaintenanceDefragmentInflightRange ensures inflight range requests 33 // does not panic the mvcc backend while defragment is running. 34 func TestV3MaintenanceDefragmentInflightRange(t *testing.T) { 35 defer testutil.AfterTest(t) 36 clus := NewClusterV3(t, &ClusterConfig{Size: 1}) 37 defer clus.Terminate(t) 38 39 cli := clus.RandClient() 40 kvc := toGRPC(cli).KV 41 if _, err := kvc.Put(context.Background(), &pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")}); err != nil { 42 t.Fatal(err) 43 } 44 45 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 46 47 donec := make(chan struct{}) 48 go func() { 49 defer close(donec) 50 kvc.Range(ctx, &pb.RangeRequest{Key: []byte("foo")}) 51 }() 52 53 mvc := toGRPC(cli).Maintenance 54 mvc.Defragment(context.Background(), &pb.DefragmentRequest{}) 55 cancel() 56 57 <-donec 58 } 59 60 // TestV3KVInflightRangeRequests ensures that inflight requests 61 // (sent before server shutdown) are gracefully handled by server-side. 62 // They are either finished or canceled, but never crash the backend. 63 // See https://github.com/etcd-io/etcd/issues/7322 for more detail. 64 func TestV3KVInflightRangeRequests(t *testing.T) { 65 defer testutil.AfterTest(t) 66 clus := NewClusterV3(t, &ClusterConfig{Size: 1}) 67 defer clus.Terminate(t) 68 69 cli := clus.RandClient() 70 kvc := toGRPC(cli).KV 71 72 if _, err := kvc.Put(context.Background(), &pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")}); err != nil { 73 t.Fatal(err) 74 } 75 76 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 77 78 reqN := 10 // use 500+ for fast machine 79 var wg sync.WaitGroup 80 wg.Add(reqN) 81 for i := 0; i < reqN; i++ { 82 go func() { 83 defer wg.Done() 84 _, err := kvc.Range(ctx, &pb.RangeRequest{Key: []byte("foo"), Serializable: true}, grpc.FailFast(false)) 85 if err != nil { 86 errCode := status.Convert(err).Code() 87 errDesc := rpctypes.ErrorDesc(err) 88 if err != nil && !(errDesc == context.Canceled.Error() || errCode == codes.Canceled || errCode == codes.Unavailable) { 89 t.Errorf("inflight request should be canceled with '%v' or code Canceled or Unavailable, got '%v' with code '%s'", context.Canceled.Error(), errDesc, errCode) 90 } 91 } 92 }() 93 } 94 95 clus.Members[0].Stop(t) 96 cancel() 97 98 wg.Wait() 99 }