github.hscsec.cn/hashicorp/consul@v1.4.5/api/kv_test.go (about) 1 package api 2 3 import ( 4 "bytes" 5 "path" 6 "strings" 7 "testing" 8 "time" 9 ) 10 11 func TestAPI_ClientPutGetDelete(t *testing.T) { 12 t.Parallel() 13 c, s := makeClient(t) 14 defer s.Stop() 15 16 kv := c.KV() 17 18 // Get a get without a key 19 key := testKey() 20 pair, _, err := kv.Get(key, nil) 21 if err != nil { 22 t.Fatalf("err: %v", err) 23 } 24 if pair != nil { 25 t.Fatalf("unexpected value: %#v", pair) 26 } 27 28 value := []byte("test") 29 30 // Put a key that begins with a '/', this should fail 31 invalidKey := "/test" 32 p := &KVPair{Key: invalidKey, Flags: 42, Value: value} 33 if _, err := kv.Put(p, nil); err == nil { 34 t.Fatalf("Invalid key not detected: %s", invalidKey) 35 } 36 37 // Put the key 38 p = &KVPair{Key: key, Flags: 42, Value: value} 39 if _, err := kv.Put(p, nil); err != nil { 40 t.Fatalf("err: %v", err) 41 } 42 43 // Get should work 44 pair, meta, err := kv.Get(key, nil) 45 if err != nil { 46 t.Fatalf("err: %v", err) 47 } 48 if pair == nil { 49 t.Fatalf("expected value: %#v", pair) 50 } 51 if !bytes.Equal(pair.Value, value) { 52 t.Fatalf("unexpected value: %#v", pair) 53 } 54 if pair.Flags != 42 { 55 t.Fatalf("unexpected value: %#v", pair) 56 } 57 if meta.LastIndex == 0 { 58 t.Fatalf("unexpected value: %#v", meta) 59 } 60 61 // Delete 62 if _, err := kv.Delete(key, nil); err != nil { 63 t.Fatalf("err: %v", err) 64 } 65 66 // Get should fail 67 pair, _, err = kv.Get(key, nil) 68 if err != nil { 69 t.Fatalf("err: %v", err) 70 } 71 if pair != nil { 72 t.Fatalf("unexpected value: %#v", pair) 73 } 74 } 75 76 func TestAPI_ClientList_DeleteRecurse(t *testing.T) { 77 t.Parallel() 78 c, s := makeClient(t) 79 defer s.Stop() 80 81 kv := c.KV() 82 83 // Generate some test keys 84 prefix := testKey() 85 var keys []string 86 for i := 0; i < 100; i++ { 87 keys = append(keys, path.Join(prefix, testKey())) 88 } 89 90 // Set values 91 value := []byte("test") 92 for _, key := range keys { 93 p := &KVPair{Key: key, Value: value} 94 if _, err := kv.Put(p, nil); err != nil { 95 t.Fatalf("err: %v", err) 96 } 97 } 98 99 // List the values 100 pairs, meta, err := kv.List(prefix, nil) 101 if err != nil { 102 t.Fatalf("err: %v", err) 103 } 104 if len(pairs) != len(keys) { 105 t.Fatalf("got %d keys", len(pairs)) 106 } 107 for _, pair := range pairs { 108 if !bytes.Equal(pair.Value, value) { 109 t.Fatalf("unexpected value: %#v", pair) 110 } 111 } 112 if meta.LastIndex == 0 { 113 t.Fatalf("unexpected value: %#v", meta) 114 } 115 116 // Delete all 117 if _, err := kv.DeleteTree(prefix, nil); err != nil { 118 t.Fatalf("err: %v", err) 119 } 120 121 // List the values 122 pairs, _, err = kv.List(prefix, nil) 123 if err != nil { 124 t.Fatalf("err: %v", err) 125 } 126 if len(pairs) != 0 { 127 t.Fatalf("got %d keys", len(pairs)) 128 } 129 } 130 131 func TestAPI_ClientDeleteCAS(t *testing.T) { 132 t.Parallel() 133 c, s := makeClient(t) 134 defer s.Stop() 135 136 kv := c.KV() 137 138 // Put the key 139 key := testKey() 140 value := []byte("test") 141 p := &KVPair{Key: key, Value: value} 142 if work, _, err := kv.CAS(p, nil); err != nil { 143 t.Fatalf("err: %v", err) 144 } else if !work { 145 t.Fatalf("CAS failure") 146 } 147 148 // Get should work 149 pair, meta, err := kv.Get(key, nil) 150 if err != nil { 151 t.Fatalf("err: %v", err) 152 } 153 if pair == nil { 154 t.Fatalf("expected value: %#v", pair) 155 } 156 if meta.LastIndex == 0 { 157 t.Fatalf("unexpected value: %#v", meta) 158 } 159 160 // CAS update with bad index 161 p.ModifyIndex = 1 162 if work, _, err := kv.DeleteCAS(p, nil); err != nil { 163 t.Fatalf("err: %v", err) 164 } else if work { 165 t.Fatalf("unexpected CAS") 166 } 167 168 // CAS update with valid index 169 p.ModifyIndex = meta.LastIndex 170 if work, _, err := kv.DeleteCAS(p, nil); err != nil { 171 t.Fatalf("err: %v", err) 172 } else if !work { 173 t.Fatalf("unexpected CAS failure") 174 } 175 } 176 177 func TestAPI_ClientCAS(t *testing.T) { 178 t.Parallel() 179 c, s := makeClient(t) 180 defer s.Stop() 181 182 kv := c.KV() 183 184 // Put the key 185 key := testKey() 186 value := []byte("test") 187 p := &KVPair{Key: key, Value: value} 188 if work, _, err := kv.CAS(p, nil); err != nil { 189 t.Fatalf("err: %v", err) 190 } else if !work { 191 t.Fatalf("CAS failure") 192 } 193 194 // Get should work 195 pair, meta, err := kv.Get(key, nil) 196 if err != nil { 197 t.Fatalf("err: %v", err) 198 } 199 if pair == nil { 200 t.Fatalf("expected value: %#v", pair) 201 } 202 if meta.LastIndex == 0 { 203 t.Fatalf("unexpected value: %#v", meta) 204 } 205 206 // CAS update with bad index 207 newVal := []byte("foo") 208 p.Value = newVal 209 p.ModifyIndex = 1 210 if work, _, err := kv.CAS(p, nil); err != nil { 211 t.Fatalf("err: %v", err) 212 } else if work { 213 t.Fatalf("unexpected CAS") 214 } 215 216 // CAS update with valid index 217 p.ModifyIndex = meta.LastIndex 218 if work, _, err := kv.CAS(p, nil); err != nil { 219 t.Fatalf("err: %v", err) 220 } else if !work { 221 t.Fatalf("unexpected CAS failure") 222 } 223 } 224 225 func TestAPI_ClientWatchGet(t *testing.T) { 226 t.Parallel() 227 c, s := makeClient(t) 228 defer s.Stop() 229 230 kv := c.KV() 231 232 // Get a get without a key 233 key := testKey() 234 pair, meta, err := kv.Get(key, nil) 235 if err != nil { 236 t.Fatalf("err: %v", err) 237 } 238 if pair != nil { 239 t.Fatalf("unexpected value: %#v", pair) 240 } 241 if meta.LastIndex == 0 { 242 t.Fatalf("unexpected value: %#v", meta) 243 } 244 245 // Put the key 246 value := []byte("test") 247 doneCh := make(chan struct{}) 248 go func() { 249 kv := c.KV() 250 251 time.Sleep(100 * time.Millisecond) 252 p := &KVPair{Key: key, Flags: 42, Value: value} 253 if _, err := kv.Put(p, nil); err != nil { 254 t.Fatalf("err: %v", err) 255 } 256 doneCh <- struct{}{} 257 }() 258 259 // Get should work 260 options := &QueryOptions{WaitIndex: meta.LastIndex} 261 pair, meta2, err := kv.Get(key, options) 262 if err != nil { 263 t.Fatalf("err: %v", err) 264 } 265 if pair == nil { 266 t.Fatalf("expected value: %#v", pair) 267 } 268 if !bytes.Equal(pair.Value, value) { 269 t.Fatalf("unexpected value: %#v", pair) 270 } 271 if pair.Flags != 42 { 272 t.Fatalf("unexpected value: %#v", pair) 273 } 274 if meta2.LastIndex <= meta.LastIndex { 275 t.Fatalf("unexpected value: %#v", meta2) 276 } 277 278 // Block until put finishes to avoid a race between it and deferred s.Stop() 279 <-doneCh 280 } 281 282 func TestAPI_ClientWatchList(t *testing.T) { 283 t.Parallel() 284 c, s := makeClient(t) 285 defer s.Stop() 286 287 kv := c.KV() 288 289 // Get a get without a key 290 prefix := testKey() 291 key := path.Join(prefix, testKey()) 292 pairs, meta, err := kv.List(prefix, nil) 293 if err != nil { 294 t.Fatalf("err: %v", err) 295 } 296 if len(pairs) != 0 { 297 t.Fatalf("unexpected value: %#v", pairs) 298 } 299 if meta.LastIndex == 0 { 300 t.Fatalf("unexpected value: %#v", meta) 301 } 302 303 // Put the key 304 value := []byte("test") 305 doneCh := make(chan struct{}) 306 go func() { 307 kv := c.KV() 308 309 time.Sleep(100 * time.Millisecond) 310 p := &KVPair{Key: key, Flags: 42, Value: value} 311 if _, err := kv.Put(p, nil); err != nil { 312 t.Fatalf("err: %v", err) 313 } 314 doneCh <- struct{}{} 315 }() 316 317 // Get should work 318 options := &QueryOptions{WaitIndex: meta.LastIndex} 319 pairs, meta2, err := kv.List(prefix, options) 320 if err != nil { 321 t.Fatalf("err: %v", err) 322 } 323 if len(pairs) != 1 { 324 t.Fatalf("expected value: %#v", pairs) 325 } 326 if !bytes.Equal(pairs[0].Value, value) { 327 t.Fatalf("unexpected value: %#v", pairs) 328 } 329 if pairs[0].Flags != 42 { 330 t.Fatalf("unexpected value: %#v", pairs) 331 } 332 if meta2.LastIndex <= meta.LastIndex { 333 t.Fatalf("unexpected value: %#v", meta2) 334 } 335 336 // Block until put finishes to avoid a race between it and deferred s.Stop() 337 <-doneCh 338 } 339 340 func TestAPI_ClientKeys_DeleteRecurse(t *testing.T) { 341 t.Parallel() 342 c, s := makeClient(t) 343 defer s.Stop() 344 345 kv := c.KV() 346 347 // Generate some test keys 348 prefix := testKey() 349 var keys []string 350 for i := 0; i < 100; i++ { 351 keys = append(keys, path.Join(prefix, testKey())) 352 } 353 354 // Set values 355 value := []byte("test") 356 for _, key := range keys { 357 p := &KVPair{Key: key, Value: value} 358 if _, err := kv.Put(p, nil); err != nil { 359 t.Fatalf("err: %v", err) 360 } 361 } 362 363 // List the values 364 out, meta, err := kv.Keys(prefix, "", nil) 365 if err != nil { 366 t.Fatalf("err: %v", err) 367 } 368 if len(out) != len(keys) { 369 t.Fatalf("got %d keys", len(out)) 370 } 371 if meta.LastIndex == 0 { 372 t.Fatalf("unexpected value: %#v", meta) 373 } 374 375 // Delete all 376 if _, err := kv.DeleteTree(prefix, nil); err != nil { 377 t.Fatalf("err: %v", err) 378 } 379 380 // List the values 381 out, _, err = kv.Keys(prefix, "", nil) 382 if err != nil { 383 t.Fatalf("err: %v", err) 384 } 385 if len(out) != 0 { 386 t.Fatalf("got %d keys", len(out)) 387 } 388 } 389 390 func TestAPI_ClientAcquireRelease(t *testing.T) { 391 t.Parallel() 392 c, s := makeClient(t) 393 defer s.Stop() 394 395 session := c.Session() 396 kv := c.KV() 397 398 // Make a session 399 id, _, err := session.CreateNoChecks(nil, nil) 400 if err != nil { 401 t.Fatalf("err: %v", err) 402 } 403 defer session.Destroy(id, nil) 404 405 // Acquire the key 406 key := testKey() 407 value := []byte("test") 408 p := &KVPair{Key: key, Value: value, Session: id} 409 if work, _, err := kv.Acquire(p, nil); err != nil { 410 t.Fatalf("err: %v", err) 411 } else if !work { 412 t.Fatalf("Lock failure") 413 } 414 415 // Get should work 416 pair, meta, err := kv.Get(key, nil) 417 if err != nil { 418 t.Fatalf("err: %v", err) 419 } 420 if pair == nil { 421 t.Fatalf("expected value: %#v", pair) 422 } 423 if pair.LockIndex != 1 { 424 t.Fatalf("Expected lock: %v", pair) 425 } 426 if pair.Session != id { 427 t.Fatalf("Expected lock: %v", pair) 428 } 429 if meta.LastIndex == 0 { 430 t.Fatalf("unexpected value: %#v", meta) 431 } 432 433 // Release 434 if work, _, err := kv.Release(p, nil); err != nil { 435 t.Fatalf("err: %v", err) 436 } else if !work { 437 t.Fatalf("Release fail") 438 } 439 440 // Get should work 441 pair, meta, err = kv.Get(key, nil) 442 if err != nil { 443 t.Fatalf("err: %v", err) 444 } 445 if pair == nil { 446 t.Fatalf("expected value: %#v", pair) 447 } 448 if pair.LockIndex != 1 { 449 t.Fatalf("Expected lock: %v", pair) 450 } 451 if pair.Session != "" { 452 t.Fatalf("Expected unlock: %v", pair) 453 } 454 if meta.LastIndex == 0 { 455 t.Fatalf("unexpected value: %#v", meta) 456 } 457 } 458 459 func TestAPI_KVClientTxn(t *testing.T) { 460 t.Parallel() 461 c, s := makeClient(t) 462 defer s.Stop() 463 464 session := c.Session() 465 kv := c.KV() 466 467 // Make a session. 468 id, _, err := session.CreateNoChecks(nil, nil) 469 if err != nil { 470 t.Fatalf("err: %v", err) 471 } 472 defer session.Destroy(id, nil) 473 474 // Acquire and get the key via a transaction, but don't supply a valid 475 // session. 476 key := testKey() 477 value := []byte("test") 478 txn := KVTxnOps{ 479 &KVTxnOp{ 480 Verb: KVLock, 481 Key: key, 482 Value: value, 483 }, 484 &KVTxnOp{ 485 Verb: KVGet, 486 Key: key, 487 }, 488 } 489 ok, ret, _, err := kv.Txn(txn, nil) 490 if err != nil { 491 t.Fatalf("err: %v", err) 492 } else if ok { 493 t.Fatalf("transaction should have failed") 494 } 495 496 if ret == nil || len(ret.Errors) != 2 || len(ret.Results) != 0 { 497 t.Fatalf("bad: %v", ret) 498 } 499 if ret.Errors[0].OpIndex != 0 || 500 !strings.Contains(ret.Errors[0].What, "missing session") || 501 !strings.Contains(ret.Errors[1].What, "doesn't exist") { 502 t.Fatalf("bad: %v", ret.Errors[0]) 503 } 504 505 // Now poke in a real session and try again. 506 txn[0].Session = id 507 ok, ret, _, err = kv.Txn(txn, nil) 508 if err != nil { 509 t.Fatalf("err: %v", err) 510 } else if !ok { 511 t.Fatalf("transaction failure") 512 } 513 514 if ret == nil || len(ret.Errors) != 0 || len(ret.Results) != 2 { 515 t.Fatalf("bad: %v", ret) 516 } 517 for i, result := range ret.Results { 518 var expected []byte 519 if i == 1 { 520 expected = value 521 } 522 523 if result.Key != key || 524 !bytes.Equal(result.Value, expected) || 525 result.Session != id || 526 result.LockIndex != 1 { 527 t.Fatalf("bad: %v", result) 528 } 529 } 530 531 // Run a read-only transaction. 532 txn = KVTxnOps{ 533 &KVTxnOp{ 534 Verb: KVGet, 535 Key: key, 536 }, 537 } 538 ok, ret, _, err = kv.Txn(txn, nil) 539 if err != nil { 540 t.Fatalf("err: %v", err) 541 } else if !ok { 542 t.Fatalf("transaction failure") 543 } 544 545 if ret == nil || len(ret.Errors) != 0 || len(ret.Results) != 1 { 546 t.Fatalf("bad: %v", ret) 547 } 548 for _, result := range ret.Results { 549 if result.Key != key || 550 !bytes.Equal(result.Value, value) || 551 result.Session != id || 552 result.LockIndex != 1 { 553 t.Fatalf("bad: %v", result) 554 } 555 } 556 557 // Sanity check using the regular GET API. 558 pair, meta, err := kv.Get(key, nil) 559 if err != nil { 560 t.Fatalf("err: %v", err) 561 } 562 if pair == nil { 563 t.Fatalf("expected value: %#v", pair) 564 } 565 if pair.LockIndex != 1 { 566 t.Fatalf("Expected lock: %v", pair) 567 } 568 if pair.Session != id { 569 t.Fatalf("Expected lock: %v", pair) 570 } 571 if meta.LastIndex == 0 { 572 t.Fatalf("unexpected value: %#v", meta) 573 } 574 }