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 }