go.etcd.io/etcd@v3.3.27+incompatible/clientv3/integration/kv_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  	"bytes"
    19  	"context"
    20  	"os"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/coreos/etcd/clientv3"
    27  	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
    28  	"github.com/coreos/etcd/integration"
    29  	"github.com/coreos/etcd/mvcc/mvccpb"
    30  	"github.com/coreos/etcd/pkg/testutil"
    31  
    32  	"google.golang.org/grpc"
    33  	"google.golang.org/grpc/codes"
    34  )
    35  
    36  func TestKVPutError(t *testing.T) {
    37  	defer testutil.AfterTest(t)
    38  
    39  	var (
    40  		maxReqBytes = 1.5 * 1024 * 1024 // hard coded max in v3_server.go
    41  		quota       = int64(int(maxReqBytes) + 8*os.Getpagesize())
    42  	)
    43  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1, QuotaBackendBytes: quota, ClientMaxCallSendMsgSize: 100 * 1024 * 1024})
    44  	defer clus.Terminate(t)
    45  
    46  	kv := clus.RandClient()
    47  	ctx := context.TODO()
    48  
    49  	_, err := kv.Put(ctx, "", "bar")
    50  	if err != rpctypes.ErrEmptyKey {
    51  		t.Fatalf("expected %v, got %v", rpctypes.ErrEmptyKey, err)
    52  	}
    53  
    54  	_, err = kv.Put(ctx, "key", strings.Repeat("a", int(maxReqBytes+100)))
    55  	if err != rpctypes.ErrRequestTooLarge {
    56  		t.Fatalf("expected %v, got %v", rpctypes.ErrRequestTooLarge, err)
    57  	}
    58  
    59  	_, err = kv.Put(ctx, "foo1", strings.Repeat("a", int(maxReqBytes-50)))
    60  	if err != nil { // below quota
    61  		t.Fatal(err)
    62  	}
    63  
    64  	time.Sleep(1 * time.Second) // give enough time for commit
    65  
    66  	_, err = kv.Put(ctx, "foo2", strings.Repeat("a", int(maxReqBytes-50)))
    67  	if err != rpctypes.ErrNoSpace { // over quota
    68  		t.Fatalf("expected %v, got %v", rpctypes.ErrNoSpace, err)
    69  	}
    70  }
    71  
    72  func TestKVPut(t *testing.T) {
    73  	defer testutil.AfterTest(t)
    74  
    75  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
    76  	defer clus.Terminate(t)
    77  
    78  	lapi := clus.RandClient()
    79  
    80  	kv := clus.RandClient()
    81  	ctx := context.TODO()
    82  
    83  	resp, err := lapi.Grant(context.Background(), 10)
    84  	if err != nil {
    85  		t.Fatalf("failed to create lease %v", err)
    86  	}
    87  
    88  	tests := []struct {
    89  		key, val string
    90  		leaseID  clientv3.LeaseID
    91  	}{
    92  		{"foo", "bar", clientv3.NoLease},
    93  		{"hello", "world", resp.ID},
    94  	}
    95  
    96  	for i, tt := range tests {
    97  		if _, err := kv.Put(ctx, tt.key, tt.val, clientv3.WithLease(tt.leaseID)); err != nil {
    98  			t.Fatalf("#%d: couldn't put %q (%v)", i, tt.key, err)
    99  		}
   100  		resp, err := kv.Get(ctx, tt.key)
   101  		if err != nil {
   102  			t.Fatalf("#%d: couldn't get key (%v)", i, err)
   103  		}
   104  		if len(resp.Kvs) != 1 {
   105  			t.Fatalf("#%d: expected 1 key, got %d", i, len(resp.Kvs))
   106  		}
   107  		if !bytes.Equal([]byte(tt.val), resp.Kvs[0].Value) {
   108  			t.Errorf("#%d: val = %s, want %s", i, tt.val, resp.Kvs[0].Value)
   109  		}
   110  		if tt.leaseID != clientv3.LeaseID(resp.Kvs[0].Lease) {
   111  			t.Errorf("#%d: val = %d, want %d", i, tt.leaseID, resp.Kvs[0].Lease)
   112  		}
   113  	}
   114  }
   115  
   116  // TestKVPutWithIgnoreValue ensures that Put with WithIgnoreValue does not clobber the old value.
   117  func TestKVPutWithIgnoreValue(t *testing.T) {
   118  	defer testutil.AfterTest(t)
   119  
   120  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   121  	defer clus.Terminate(t)
   122  
   123  	kv := clus.RandClient()
   124  
   125  	_, err := kv.Put(context.TODO(), "foo", "", clientv3.WithIgnoreValue())
   126  	if err != rpctypes.ErrKeyNotFound {
   127  		t.Fatalf("err expected %v, got %v", rpctypes.ErrKeyNotFound, err)
   128  	}
   129  
   130  	if _, err := kv.Put(context.TODO(), "foo", "bar"); err != nil {
   131  		t.Fatal(err)
   132  	}
   133  
   134  	if _, err := kv.Put(context.TODO(), "foo", "", clientv3.WithIgnoreValue()); err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	rr, rerr := kv.Get(context.TODO(), "foo")
   138  	if rerr != nil {
   139  		t.Fatal(rerr)
   140  	}
   141  	if len(rr.Kvs) != 1 {
   142  		t.Fatalf("len(rr.Kvs) expected 1, got %d", len(rr.Kvs))
   143  	}
   144  	if !bytes.Equal(rr.Kvs[0].Value, []byte("bar")) {
   145  		t.Fatalf("value expected 'bar', got %q", rr.Kvs[0].Value)
   146  	}
   147  }
   148  
   149  // TestKVPutWithIgnoreLease ensures that Put with WithIgnoreLease does not affect the existing lease for the key.
   150  func TestKVPutWithIgnoreLease(t *testing.T) {
   151  	defer testutil.AfterTest(t)
   152  
   153  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   154  	defer clus.Terminate(t)
   155  
   156  	kv := clus.RandClient()
   157  
   158  	lapi := clus.RandClient()
   159  
   160  	resp, err := lapi.Grant(context.Background(), 10)
   161  	if err != nil {
   162  		t.Errorf("failed to create lease %v", err)
   163  	}
   164  
   165  	if _, err := kv.Put(context.TODO(), "zoo", "bar", clientv3.WithIgnoreLease()); err != rpctypes.ErrKeyNotFound {
   166  		t.Fatalf("err expected %v, got %v", rpctypes.ErrKeyNotFound, err)
   167  	}
   168  
   169  	if _, err := kv.Put(context.TODO(), "zoo", "bar", clientv3.WithLease(resp.ID)); err != nil {
   170  		t.Fatal(err)
   171  	}
   172  
   173  	if _, err := kv.Put(context.TODO(), "zoo", "bar1", clientv3.WithIgnoreLease()); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  
   177  	rr, rerr := kv.Get(context.TODO(), "zoo")
   178  	if rerr != nil {
   179  		t.Fatal(rerr)
   180  	}
   181  	if len(rr.Kvs) != 1 {
   182  		t.Fatalf("len(rr.Kvs) expected 1, got %d", len(rr.Kvs))
   183  	}
   184  	if rr.Kvs[0].Lease != int64(resp.ID) {
   185  		t.Fatalf("lease expected %v, got %v", resp.ID, rr.Kvs[0].Lease)
   186  	}
   187  }
   188  
   189  func TestKVPutWithRequireLeader(t *testing.T) {
   190  	defer testutil.AfterTest(t)
   191  
   192  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   193  	defer clus.Terminate(t)
   194  
   195  	clus.Members[1].Stop(t)
   196  	clus.Members[2].Stop(t)
   197  
   198  	// wait for election timeout, then member[0] will not have a leader.
   199  	var (
   200  		electionTicks = 10
   201  		tickDuration  = 10 * time.Millisecond
   202  	)
   203  	time.Sleep(time.Duration(3*electionTicks) * tickDuration)
   204  
   205  	kv := clus.Client(0)
   206  	_, err := kv.Put(clientv3.WithRequireLeader(context.Background()), "foo", "bar")
   207  	if err != rpctypes.ErrNoLeader {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	// clients may give timeout errors since the members are stopped; take
   212  	// the clients so that terminating the cluster won't complain
   213  	clus.Client(1).Close()
   214  	clus.Client(2).Close()
   215  	clus.TakeClient(1)
   216  	clus.TakeClient(2)
   217  }
   218  
   219  func TestKVRange(t *testing.T) {
   220  	defer testutil.AfterTest(t)
   221  
   222  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   223  	defer clus.Terminate(t)
   224  
   225  	kv := clus.RandClient()
   226  	ctx := context.TODO()
   227  
   228  	keySet := []string{"a", "b", "c", "c", "c", "foo", "foo/abc", "fop"}
   229  	for i, key := range keySet {
   230  		if _, err := kv.Put(ctx, key, ""); err != nil {
   231  			t.Fatalf("#%d: couldn't put %q (%v)", i, key, err)
   232  		}
   233  	}
   234  	resp, err := kv.Get(ctx, keySet[0])
   235  	if err != nil {
   236  		t.Fatalf("couldn't get key (%v)", err)
   237  	}
   238  	wheader := resp.Header
   239  
   240  	tests := []struct {
   241  		begin, end string
   242  		rev        int64
   243  		opts       []clientv3.OpOption
   244  
   245  		wantSet []*mvccpb.KeyValue
   246  	}{
   247  		// range first two
   248  		{
   249  			"a", "c",
   250  			0,
   251  			nil,
   252  
   253  			[]*mvccpb.KeyValue{
   254  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   255  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   256  			},
   257  		},
   258  		// range first two with serializable
   259  		{
   260  			"a", "c",
   261  			0,
   262  			[]clientv3.OpOption{clientv3.WithSerializable()},
   263  
   264  			[]*mvccpb.KeyValue{
   265  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   266  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   267  			},
   268  		},
   269  		// range all with rev
   270  		{
   271  			"a", "x",
   272  			2,
   273  			nil,
   274  
   275  			[]*mvccpb.KeyValue{
   276  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   277  			},
   278  		},
   279  		// range all with countOnly
   280  		{
   281  			"a", "x",
   282  			2,
   283  			[]clientv3.OpOption{clientv3.WithCountOnly()},
   284  
   285  			nil,
   286  		},
   287  		// range all with SortByKey, SortAscend
   288  		{
   289  			"a", "x",
   290  			0,
   291  			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
   292  
   293  			[]*mvccpb.KeyValue{
   294  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   295  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   296  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   297  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   298  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   299  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   300  			},
   301  		},
   302  		// range all with SortByKey, missing sorting order (ASCEND by default)
   303  		{
   304  			"a", "x",
   305  			0,
   306  			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortNone)},
   307  
   308  			[]*mvccpb.KeyValue{
   309  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   310  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   311  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   312  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   313  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   314  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   315  			},
   316  		},
   317  		// range all with SortByCreateRevision, SortDescend
   318  		{
   319  			"a", "x",
   320  			0,
   321  			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortDescend)},
   322  
   323  			[]*mvccpb.KeyValue{
   324  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   325  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   326  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   327  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   328  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   329  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   330  			},
   331  		},
   332  		// range all with SortByCreateRevision, missing sorting order (ASCEND by default)
   333  		{
   334  			"a", "x",
   335  			0,
   336  			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortNone)},
   337  
   338  			[]*mvccpb.KeyValue{
   339  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   340  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   341  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   342  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   343  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   344  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   345  			},
   346  		},
   347  		// range all with SortByModRevision, SortDescend
   348  		{
   349  			"a", "x",
   350  			0,
   351  			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByModRevision, clientv3.SortDescend)},
   352  
   353  			[]*mvccpb.KeyValue{
   354  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   355  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   356  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   357  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   358  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   359  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   360  			},
   361  		},
   362  		// WithPrefix
   363  		{
   364  			"foo", "",
   365  			0,
   366  			[]clientv3.OpOption{clientv3.WithPrefix()},
   367  
   368  			[]*mvccpb.KeyValue{
   369  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   370  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   371  			},
   372  		},
   373  		// WithFromKey
   374  		{
   375  			"fo", "",
   376  			0,
   377  			[]clientv3.OpOption{clientv3.WithFromKey()},
   378  
   379  			[]*mvccpb.KeyValue{
   380  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   381  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   382  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   383  			},
   384  		},
   385  		// fetch entire keyspace using WithFromKey
   386  		{
   387  			"\x00", "",
   388  			0,
   389  			[]clientv3.OpOption{clientv3.WithFromKey(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
   390  
   391  			[]*mvccpb.KeyValue{
   392  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   393  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   394  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   395  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   396  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   397  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   398  			},
   399  		},
   400  		// fetch entire keyspace using WithPrefix
   401  		{
   402  			"", "",
   403  			0,
   404  			[]clientv3.OpOption{clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
   405  
   406  			[]*mvccpb.KeyValue{
   407  				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
   408  				{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
   409  				{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
   410  				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
   411  				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
   412  				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
   413  			},
   414  		},
   415  	}
   416  
   417  	for i, tt := range tests {
   418  		opts := []clientv3.OpOption{clientv3.WithRange(tt.end), clientv3.WithRev(tt.rev)}
   419  		opts = append(opts, tt.opts...)
   420  		resp, err := kv.Get(ctx, tt.begin, opts...)
   421  		if err != nil {
   422  			t.Fatalf("#%d: couldn't range (%v)", i, err)
   423  		}
   424  		if !reflect.DeepEqual(wheader, resp.Header) {
   425  			t.Fatalf("#%d: wheader expected %+v, got %+v", i, wheader, resp.Header)
   426  		}
   427  		if !reflect.DeepEqual(tt.wantSet, resp.Kvs) {
   428  			t.Fatalf("#%d: resp.Kvs expected %+v, got %+v", i, tt.wantSet, resp.Kvs)
   429  		}
   430  	}
   431  }
   432  
   433  func TestKVGetErrConnClosed(t *testing.T) {
   434  	defer testutil.AfterTest(t)
   435  
   436  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   437  	defer clus.Terminate(t)
   438  
   439  	cli := clus.Client(0)
   440  
   441  	donec := make(chan struct{})
   442  	go func() {
   443  		defer close(donec)
   444  		_, err := cli.Get(context.TODO(), "foo")
   445  		if err != nil && err != context.Canceled && err != grpc.ErrClientConnClosing {
   446  			t.Fatalf("expected %v or %v, got %v", context.Canceled, grpc.ErrClientConnClosing, err)
   447  		}
   448  	}()
   449  
   450  	if err := cli.Close(); err != nil {
   451  		t.Fatal(err)
   452  	}
   453  	clus.TakeClient(0)
   454  
   455  	select {
   456  	case <-time.After(integration.RequestWaitTimeout):
   457  		t.Fatal("kv.Get took too long")
   458  	case <-donec:
   459  	}
   460  }
   461  
   462  func TestKVNewAfterClose(t *testing.T) {
   463  	defer testutil.AfterTest(t)
   464  
   465  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   466  	defer clus.Terminate(t)
   467  
   468  	cli := clus.Client(0)
   469  	clus.TakeClient(0)
   470  	if err := cli.Close(); err != nil {
   471  		t.Fatal(err)
   472  	}
   473  
   474  	donec := make(chan struct{})
   475  	go func() {
   476  		_, err := cli.Get(context.TODO(), "foo")
   477  		if err != context.Canceled && err != grpc.ErrClientConnClosing {
   478  			t.Fatalf("expected %v or %v, got %v", context.Canceled, grpc.ErrClientConnClosing, err)
   479  		}
   480  		close(donec)
   481  	}()
   482  	select {
   483  	case <-time.After(integration.RequestWaitTimeout):
   484  		t.Fatal("kv.Get took too long")
   485  	case <-donec:
   486  	}
   487  }
   488  
   489  func TestKVDeleteRange(t *testing.T) {
   490  	defer testutil.AfterTest(t)
   491  
   492  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   493  	defer clus.Terminate(t)
   494  
   495  	kv := clus.RandClient()
   496  	ctx := context.TODO()
   497  
   498  	tests := []struct {
   499  		key  string
   500  		opts []clientv3.OpOption
   501  
   502  		wkeys []string
   503  	}{
   504  		// [a, c)
   505  		{
   506  			key:  "a",
   507  			opts: []clientv3.OpOption{clientv3.WithRange("c")},
   508  
   509  			wkeys: []string{"c", "c/abc", "d"},
   510  		},
   511  		// >= c
   512  		{
   513  			key:  "c",
   514  			opts: []clientv3.OpOption{clientv3.WithFromKey()},
   515  
   516  			wkeys: []string{"a", "b"},
   517  		},
   518  		// c*
   519  		{
   520  			key:  "c",
   521  			opts: []clientv3.OpOption{clientv3.WithPrefix()},
   522  
   523  			wkeys: []string{"a", "b", "d"},
   524  		},
   525  		// *
   526  		{
   527  			key:  "\x00",
   528  			opts: []clientv3.OpOption{clientv3.WithFromKey()},
   529  
   530  			wkeys: []string{},
   531  		},
   532  	}
   533  
   534  	for i, tt := range tests {
   535  		keySet := []string{"a", "b", "c", "c/abc", "d"}
   536  		for j, key := range keySet {
   537  			if _, err := kv.Put(ctx, key, ""); err != nil {
   538  				t.Fatalf("#%d: couldn't put %q (%v)", j, key, err)
   539  			}
   540  		}
   541  
   542  		_, err := kv.Delete(ctx, tt.key, tt.opts...)
   543  		if err != nil {
   544  			t.Fatalf("#%d: couldn't delete range (%v)", i, err)
   545  		}
   546  
   547  		resp, err := kv.Get(ctx, "a", clientv3.WithFromKey())
   548  		if err != nil {
   549  			t.Fatalf("#%d: couldn't get keys (%v)", i, err)
   550  		}
   551  		keys := []string{}
   552  		for _, kv := range resp.Kvs {
   553  			keys = append(keys, string(kv.Key))
   554  		}
   555  		if !reflect.DeepEqual(tt.wkeys, keys) {
   556  			t.Errorf("#%d: resp.Kvs got %v, expected %v", i, keys, tt.wkeys)
   557  		}
   558  	}
   559  }
   560  
   561  func TestKVDelete(t *testing.T) {
   562  	defer testutil.AfterTest(t)
   563  
   564  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   565  	defer clus.Terminate(t)
   566  
   567  	kv := clus.RandClient()
   568  	ctx := context.TODO()
   569  
   570  	presp, err := kv.Put(ctx, "foo", "")
   571  	if err != nil {
   572  		t.Fatalf("couldn't put 'foo' (%v)", err)
   573  	}
   574  	if presp.Header.Revision != 2 {
   575  		t.Fatalf("presp.Header.Revision got %d, want %d", presp.Header.Revision, 2)
   576  	}
   577  	resp, err := kv.Delete(ctx, "foo")
   578  	if err != nil {
   579  		t.Fatalf("couldn't delete key (%v)", err)
   580  	}
   581  	if resp.Header.Revision != 3 {
   582  		t.Fatalf("resp.Header.Revision got %d, want %d", resp.Header.Revision, 3)
   583  	}
   584  	gresp, err := kv.Get(ctx, "foo")
   585  	if err != nil {
   586  		t.Fatalf("couldn't get key (%v)", err)
   587  	}
   588  	if len(gresp.Kvs) > 0 {
   589  		t.Fatalf("gresp.Kvs got %+v, want none", gresp.Kvs)
   590  	}
   591  }
   592  
   593  func TestKVCompactError(t *testing.T) {
   594  	defer testutil.AfterTest(t)
   595  
   596  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   597  	defer clus.Terminate(t)
   598  
   599  	kv := clus.RandClient()
   600  	ctx := context.TODO()
   601  
   602  	for i := 0; i < 5; i++ {
   603  		if _, err := kv.Put(ctx, "foo", "bar"); err != nil {
   604  			t.Fatalf("couldn't put 'foo' (%v)", err)
   605  		}
   606  	}
   607  	_, err := kv.Compact(ctx, 6)
   608  	if err != nil {
   609  		t.Fatalf("couldn't compact 6 (%v)", err)
   610  	}
   611  
   612  	_, err = kv.Compact(ctx, 6)
   613  	if err != rpctypes.ErrCompacted {
   614  		t.Fatalf("expected %v, got %v", rpctypes.ErrCompacted, err)
   615  	}
   616  
   617  	_, err = kv.Compact(ctx, 100)
   618  	if err != rpctypes.ErrFutureRev {
   619  		t.Fatalf("expected %v, got %v", rpctypes.ErrFutureRev, err)
   620  	}
   621  }
   622  
   623  func TestKVCompact(t *testing.T) {
   624  	defer testutil.AfterTest(t)
   625  
   626  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   627  	defer clus.Terminate(t)
   628  
   629  	kv := clus.RandClient()
   630  	ctx := context.TODO()
   631  
   632  	for i := 0; i < 10; i++ {
   633  		if _, err := kv.Put(ctx, "foo", "bar"); err != nil {
   634  			t.Fatalf("couldn't put 'foo' (%v)", err)
   635  		}
   636  	}
   637  
   638  	_, err := kv.Compact(ctx, 7)
   639  	if err != nil {
   640  		t.Fatalf("couldn't compact kv space (%v)", err)
   641  	}
   642  	_, err = kv.Compact(ctx, 7)
   643  	if err == nil || err != rpctypes.ErrCompacted {
   644  		t.Fatalf("error got %v, want %v", err, rpctypes.ErrCompacted)
   645  	}
   646  
   647  	wcli := clus.RandClient()
   648  	// new watcher could precede receiving the compaction without quorum first
   649  	wcli.Get(ctx, "quorum-get")
   650  
   651  	wchan := wcli.Watch(ctx, "foo", clientv3.WithRev(3))
   652  
   653  	if wr := <-wchan; wr.CompactRevision != 7 {
   654  		t.Fatalf("wchan CompactRevision got %v, want 7", wr.CompactRevision)
   655  	}
   656  	if wr, ok := <-wchan; ok {
   657  		t.Fatalf("wchan got %v, expected closed", wr)
   658  	}
   659  
   660  	_, err = kv.Compact(ctx, 1000)
   661  	if err == nil || err != rpctypes.ErrFutureRev {
   662  		t.Fatalf("error got %v, want %v", err, rpctypes.ErrFutureRev)
   663  	}
   664  }
   665  
   666  // TestKVGetRetry ensures get will retry on disconnect.
   667  func TestKVGetRetry(t *testing.T) {
   668  	defer testutil.AfterTest(t)
   669  
   670  	clusterSize := 3
   671  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: clusterSize})
   672  	defer clus.Terminate(t)
   673  
   674  	// because killing leader and following election
   675  	// could give no other endpoints for client reconnection
   676  	fIdx := (clus.WaitLeader(t) + 1) % clusterSize
   677  
   678  	kv := clus.Client(fIdx)
   679  	ctx := context.TODO()
   680  
   681  	if _, err := kv.Put(ctx, "foo", "bar"); err != nil {
   682  		t.Fatal(err)
   683  	}
   684  
   685  	clus.Members[fIdx].Stop(t)
   686  
   687  	donec := make(chan struct{})
   688  	go func() {
   689  		// Get will fail, but reconnect will trigger
   690  		gresp, gerr := kv.Get(ctx, "foo")
   691  		if gerr != nil {
   692  			t.Fatal(gerr)
   693  		}
   694  		wkvs := []*mvccpb.KeyValue{
   695  			{
   696  				Key:            []byte("foo"),
   697  				Value:          []byte("bar"),
   698  				CreateRevision: 2,
   699  				ModRevision:    2,
   700  				Version:        1,
   701  			},
   702  		}
   703  		if !reflect.DeepEqual(gresp.Kvs, wkvs) {
   704  			t.Fatalf("bad get: got %v, want %v", gresp.Kvs, wkvs)
   705  		}
   706  		donec <- struct{}{}
   707  	}()
   708  
   709  	time.Sleep(100 * time.Millisecond)
   710  	clus.Members[fIdx].Restart(t)
   711  
   712  	select {
   713  	case <-time.After(5 * time.Second):
   714  		t.Fatalf("timed out waiting for get")
   715  	case <-donec:
   716  	}
   717  }
   718  
   719  // TestKVPutFailGetRetry ensures a get will retry following a failed put.
   720  func TestKVPutFailGetRetry(t *testing.T) {
   721  	defer testutil.AfterTest(t)
   722  
   723  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
   724  	defer clus.Terminate(t)
   725  
   726  	kv := clus.Client(0)
   727  	clus.Members[0].Stop(t)
   728  
   729  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
   730  	defer cancel()
   731  	_, err := kv.Put(ctx, "foo", "bar")
   732  	if err == nil {
   733  		t.Fatalf("got success on disconnected put, wanted error")
   734  	}
   735  
   736  	donec := make(chan struct{})
   737  	go func() {
   738  		// Get will fail, but reconnect will trigger
   739  		gresp, gerr := kv.Get(context.TODO(), "foo")
   740  		if gerr != nil {
   741  			t.Fatal(gerr)
   742  		}
   743  		if len(gresp.Kvs) != 0 {
   744  			t.Fatalf("bad get kvs: got %+v, want empty", gresp.Kvs)
   745  		}
   746  		donec <- struct{}{}
   747  	}()
   748  
   749  	time.Sleep(100 * time.Millisecond)
   750  	clus.Members[0].Restart(t)
   751  
   752  	select {
   753  	case <-time.After(5 * time.Second):
   754  		t.Fatalf("timed out waiting for get")
   755  	case <-donec:
   756  	}
   757  }
   758  
   759  // TestKVGetCancel tests that a context cancel on a Get terminates as expected.
   760  func TestKVGetCancel(t *testing.T) {
   761  	defer testutil.AfterTest(t)
   762  
   763  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   764  	defer clus.Terminate(t)
   765  
   766  	oldconn := clus.Client(0).ActiveConnection()
   767  	kv := clus.Client(0)
   768  
   769  	ctx, cancel := context.WithCancel(context.TODO())
   770  	cancel()
   771  
   772  	resp, err := kv.Get(ctx, "abc")
   773  	if err == nil {
   774  		t.Fatalf("cancel on get response %v, expected context error", resp)
   775  	}
   776  	newconn := clus.Client(0).ActiveConnection()
   777  	if oldconn != newconn {
   778  		t.Fatalf("cancel on get broke client connection")
   779  	}
   780  }
   781  
   782  // TestKVGetStoppedServerAndClose ensures closing after a failed Get works.
   783  func TestKVGetStoppedServerAndClose(t *testing.T) {
   784  	defer testutil.AfterTest(t)
   785  
   786  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   787  	defer clus.Terminate(t)
   788  
   789  	cli := clus.Client(0)
   790  	clus.Members[0].Stop(t)
   791  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
   792  	// this Get fails and triggers an asynchronous connection retry
   793  	_, err := cli.Get(ctx, "abc")
   794  	cancel()
   795  	if err != nil && err != context.DeadlineExceeded {
   796  		t.Fatal(err)
   797  	}
   798  }
   799  
   800  // TestKVPutStoppedServerAndClose ensures closing after a failed Put works.
   801  func TestKVPutStoppedServerAndClose(t *testing.T) {
   802  	defer testutil.AfterTest(t)
   803  
   804  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   805  	defer clus.Terminate(t)
   806  
   807  	cli := clus.Client(0)
   808  	clus.Members[0].Stop(t)
   809  
   810  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
   811  	// get retries on all errors.
   812  	// so here we use it to eat the potential broken pipe error for the next put.
   813  	// grpc client might see a broken pipe error when we issue the get request before
   814  	// grpc finds out the original connection is down due to the member shutdown.
   815  	_, err := cli.Get(ctx, "abc")
   816  	cancel()
   817  	if err != nil && err != context.DeadlineExceeded {
   818  		t.Fatal(err)
   819  	}
   820  
   821  	// this Put fails and triggers an asynchronous connection retry
   822  	_, err = cli.Put(ctx, "abc", "123")
   823  	cancel()
   824  	if err != nil && err != context.DeadlineExceeded {
   825  		t.Fatal(err)
   826  	}
   827  }
   828  
   829  // TestKVPutAtMostOnce ensures that a Put will only occur at most once
   830  // in the presence of network errors.
   831  func TestKVPutAtMostOnce(t *testing.T) {
   832  	defer testutil.AfterTest(t)
   833  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
   834  	defer clus.Terminate(t)
   835  
   836  	if _, err := clus.Client(0).Put(context.TODO(), "k", "1"); err != nil {
   837  		t.Fatal(err)
   838  	}
   839  
   840  	for i := 0; i < 10; i++ {
   841  		clus.Members[0].DropConnections()
   842  		donec := make(chan struct{})
   843  		go func() {
   844  			defer close(donec)
   845  			for i := 0; i < 10; i++ {
   846  				clus.Members[0].DropConnections()
   847  				time.Sleep(5 * time.Millisecond)
   848  			}
   849  		}()
   850  		_, err := clus.Client(0).Put(context.TODO(), "k", "v")
   851  		<-donec
   852  		if err != nil {
   853  			break
   854  		}
   855  	}
   856  
   857  	resp, err := clus.Client(0).Get(context.TODO(), "k")
   858  	if err != nil {
   859  		t.Fatal(err)
   860  	}
   861  	if resp.Kvs[0].Version > 11 {
   862  		t.Fatalf("expected version <= 10, got %+v", resp.Kvs[0])
   863  	}
   864  }
   865  
   866  // TestKVLargeRequests tests various client/server side request limits.
   867  func TestKVLargeRequests(t *testing.T) {
   868  	defer testutil.AfterTest(t)
   869  	tests := []struct {
   870  		// make sure that "MaxCallSendMsgSize" < server-side default send/recv limit
   871  		maxRequestBytesServer  uint
   872  		maxCallSendBytesClient int
   873  		maxCallRecvBytesClient int
   874  
   875  		valueSize   int
   876  		expectError error
   877  	}{
   878  		{
   879  			maxRequestBytesServer:  1,
   880  			maxCallSendBytesClient: 0,
   881  			maxCallRecvBytesClient: 0,
   882  			valueSize:              1024,
   883  			expectError:            rpctypes.ErrRequestTooLarge,
   884  		},
   885  
   886  		// without proper client-side receive size limit
   887  		// "code = ResourceExhausted desc = received message larger than max (5242929 vs. 4194304)"
   888  		{
   889  
   890  			maxRequestBytesServer:  7*1024*1024 + 512*1024,
   891  			maxCallSendBytesClient: 7 * 1024 * 1024,
   892  			maxCallRecvBytesClient: 0,
   893  			valueSize:              5 * 1024 * 1024,
   894  			expectError:            nil,
   895  		},
   896  
   897  		{
   898  			maxRequestBytesServer:  10 * 1024 * 1024,
   899  			maxCallSendBytesClient: 100 * 1024 * 1024,
   900  			maxCallRecvBytesClient: 0,
   901  			valueSize:              10 * 1024 * 1024,
   902  			expectError:            rpctypes.ErrRequestTooLarge,
   903  		},
   904  		{
   905  			maxRequestBytesServer:  10 * 1024 * 1024,
   906  			maxCallSendBytesClient: 10 * 1024 * 1024,
   907  			maxCallRecvBytesClient: 0,
   908  			valueSize:              10 * 1024 * 1024,
   909  			expectError:            grpc.Errorf(codes.ResourceExhausted, "trying to send message larger than max "),
   910  		},
   911  		{
   912  			maxRequestBytesServer:  10 * 1024 * 1024,
   913  			maxCallSendBytesClient: 100 * 1024 * 1024,
   914  			maxCallRecvBytesClient: 0,
   915  			valueSize:              10*1024*1024 + 5,
   916  			expectError:            rpctypes.ErrRequestTooLarge,
   917  		},
   918  		{
   919  			maxRequestBytesServer:  10 * 1024 * 1024,
   920  			maxCallSendBytesClient: 10 * 1024 * 1024,
   921  			maxCallRecvBytesClient: 0,
   922  			valueSize:              10*1024*1024 + 5,
   923  			expectError:            grpc.Errorf(codes.ResourceExhausted, "trying to send message larger than max "),
   924  		},
   925  	}
   926  	for i, test := range tests {
   927  		clus := integration.NewClusterV3(t,
   928  			&integration.ClusterConfig{
   929  				Size:                     1,
   930  				MaxRequestBytes:          test.maxRequestBytesServer,
   931  				ClientMaxCallSendMsgSize: test.maxCallSendBytesClient,
   932  				ClientMaxCallRecvMsgSize: test.maxCallRecvBytesClient,
   933  			},
   934  		)
   935  		cli := clus.Client(0)
   936  		_, err := cli.Put(context.TODO(), "foo", strings.Repeat("a", test.valueSize))
   937  
   938  		if _, ok := err.(rpctypes.EtcdError); ok {
   939  			if err != test.expectError {
   940  				t.Errorf("#%d: expected %v, got %v", i, test.expectError, err)
   941  			}
   942  		} else if err != nil && !strings.HasPrefix(err.Error(), test.expectError.Error()) {
   943  			t.Errorf("#%d: expected error starting with '%s', got '%s'", i, test.expectError.Error(), err.Error())
   944  		}
   945  
   946  		// put request went through, now expects large response back
   947  		if err == nil {
   948  			_, err = cli.Get(context.TODO(), "foo")
   949  			if err != nil {
   950  				t.Errorf("#%d: get expected no error, got %v", i, err)
   951  			}
   952  		}
   953  
   954  		clus.Terminate(t)
   955  	}
   956  }