github.com/hashicorp/vault/sdk@v0.13.0/physical/testing.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package physical 5 6 import ( 7 "context" 8 "reflect" 9 "sort" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 ) 15 16 func ExerciseBackend(t testing.TB, b Backend) { 17 t.Helper() 18 ctx := context.Background() 19 20 // Should be empty 21 keys, err := b.List(ctx, "") 22 if err != nil { 23 t.Fatalf("initial list failed: %v", err) 24 } 25 if len(keys) != 0 { 26 t.Errorf("initial not empty: %v", keys) 27 } 28 29 // Delete should work if it does not exist 30 err = b.Delete(ctx, "foo") 31 if err != nil { 32 t.Fatalf("idempotent delete: %v", err) 33 } 34 35 // Get should not fail, but be nil 36 out, err := b.Get(ctx, "foo") 37 if err != nil { 38 t.Fatalf("initial get failed: %v", err) 39 } 40 if out != nil { 41 t.Errorf("initial get was not nil: %v", out) 42 } 43 44 // Make an entry 45 e := &Entry{Key: "foo", Value: []byte("test")} 46 err = b.Put(ctx, e) 47 if err != nil { 48 t.Fatalf("put failed: %v", err) 49 } 50 51 // Get should work 52 out, err = b.Get(ctx, "foo") 53 if err != nil { 54 t.Fatalf("get failed: %v", err) 55 } 56 if !reflect.DeepEqual(out, e) { 57 t.Errorf("bad: %v expected: %v", out, e) 58 } 59 60 // List should not be empty 61 keys, err = b.List(ctx, "") 62 if err != nil { 63 t.Fatalf("list failed: %v", err) 64 } 65 if len(keys) != 1 || keys[0] != "foo" { 66 t.Errorf("keys[0] did not equal foo: %v", keys) 67 } 68 69 // Delete should work 70 err = b.Delete(ctx, "foo") 71 if err != nil { 72 t.Fatalf("delete: %v", err) 73 } 74 75 // Should be empty 76 keys, err = b.List(ctx, "") 77 if err != nil { 78 t.Fatalf("list after delete: %v", err) 79 } 80 if len(keys) != 0 { 81 t.Errorf("list after delete not empty: %v", keys) 82 } 83 84 // Get should fail 85 out, err = b.Get(ctx, "foo") 86 if err != nil { 87 t.Fatalf("get after delete: %v", err) 88 } 89 if out != nil { 90 t.Errorf("get after delete not nil: %v", out) 91 } 92 93 // Multiple Puts should work; GH-189 94 e = &Entry{Key: "foo", Value: []byte("test")} 95 err = b.Put(ctx, e) 96 if err != nil { 97 t.Fatalf("multi put 1 failed: %v", err) 98 } 99 e = &Entry{Key: "foo", Value: []byte("test")} 100 err = b.Put(ctx, e) 101 if err != nil { 102 t.Fatalf("multi put 2 failed: %v", err) 103 } 104 105 // Make a nested entry 106 e = &Entry{Key: "foo/bar", Value: []byte("baz")} 107 err = b.Put(ctx, e) 108 if err != nil { 109 t.Fatalf("nested put failed: %v", err) 110 } 111 112 // Get should work 113 out, err = b.Get(ctx, "foo/bar") 114 if err != nil { 115 t.Fatalf("get failed: %v", err) 116 } 117 if !reflect.DeepEqual(out, e) { 118 t.Errorf("bad: %v expected: %v", out, e) 119 } 120 121 keys, err = b.List(ctx, "") 122 if err != nil { 123 t.Fatalf("list multi failed: %v", err) 124 } 125 sort.Strings(keys) 126 if len(keys) != 2 || keys[0] != "foo" || keys[1] != "foo/" { 127 t.Errorf("expected 2 keys [foo, foo/]: %v", keys) 128 } 129 130 // Delete with children should work 131 err = b.Delete(ctx, "foo") 132 if err != nil { 133 t.Fatalf("delete after multi: %v", err) 134 } 135 136 // Get should return the child 137 out, err = b.Get(ctx, "foo/bar") 138 if err != nil { 139 t.Fatalf("get after multi delete: %v", err) 140 } 141 if out == nil { 142 t.Errorf("get after multi delete not nil: %v", out) 143 } 144 145 // Removal of nested secret should not leave artifacts 146 e = &Entry{Key: "foo/nested1/nested2/nested3", Value: []byte("baz")} 147 err = b.Put(ctx, e) 148 if err != nil { 149 t.Fatalf("deep nest: %v", err) 150 } 151 152 err = b.Delete(ctx, "foo/nested1/nested2/nested3") 153 if err != nil { 154 t.Fatalf("failed to remove deep nest: %v", err) 155 } 156 157 keys, err = b.List(ctx, "foo/") 158 if err != nil { 159 t.Fatalf("err: %v", err) 160 } 161 if len(keys) != 1 || keys[0] != "bar" { 162 t.Errorf("should be exactly 1 key == bar: %v", keys) 163 } 164 165 // Make a second nested entry to test prefix removal 166 e = &Entry{Key: "foo/zip", Value: []byte("zap")} 167 err = b.Put(ctx, e) 168 if err != nil { 169 t.Fatalf("failed to create second nested: %v", err) 170 } 171 172 // Delete should not remove the prefix 173 err = b.Delete(ctx, "foo/bar") 174 if err != nil { 175 t.Fatalf("failed to delete nested prefix: %v", err) 176 } 177 178 keys, err = b.List(ctx, "") 179 if err != nil { 180 t.Fatalf("list nested prefix: %v", err) 181 } 182 if len(keys) != 1 || keys[0] != "foo/" { 183 t.Errorf("should be exactly 1 key == foo/: %v", keys) 184 } 185 186 // Delete should remove the prefix 187 err = b.Delete(ctx, "foo/zip") 188 if err != nil { 189 t.Fatalf("failed to delete second prefix: %v", err) 190 } 191 192 keys, err = b.List(ctx, "") 193 if err != nil { 194 t.Fatalf("listing after second delete failed: %v", err) 195 } 196 if len(keys) != 0 { 197 t.Errorf("should be empty at end: %v", keys) 198 } 199 200 // When the root path is empty, adding and removing deep nested values should not break listing 201 e = &Entry{Key: "foo/nested1/nested2/value1", Value: []byte("baz")} 202 err = b.Put(ctx, e) 203 if err != nil { 204 t.Fatalf("deep nest: %v", err) 205 } 206 207 e = &Entry{Key: "foo/nested1/nested2/value2", Value: []byte("baz")} 208 err = b.Put(ctx, e) 209 if err != nil { 210 t.Fatalf("deep nest: %v", err) 211 } 212 213 err = b.Delete(ctx, "foo/nested1/nested2/value2") 214 if err != nil { 215 t.Fatalf("failed to remove deep nest: %v", err) 216 } 217 218 keys, err = b.List(ctx, "") 219 if err != nil { 220 t.Fatalf("listing of root failed after deletion: %v", err) 221 } 222 if len(keys) == 0 { 223 t.Errorf("root is returning empty after deleting a single nested value, expected nested1/: %v", keys) 224 keys, err = b.List(ctx, "foo/nested1") 225 if err != nil { 226 t.Fatalf("listing of expected nested path 'foo/nested1' failed: %v", err) 227 } 228 // prove that the root should not be empty and that foo/nested1 exists 229 if len(keys) != 0 { 230 t.Logf(" keys can still be listed from nested1/ so it's not empty, expected nested2/: %v", keys) 231 } 232 } 233 234 // cleanup left over listing bug test value 235 err = b.Delete(ctx, "foo/nested1/nested2/value1") 236 if err != nil { 237 t.Fatalf("failed to remove deep nest: %v", err) 238 } 239 240 keys, err = b.List(ctx, "") 241 if err != nil { 242 t.Fatalf("listing of root failed after delete of deep nest: %v", err) 243 } 244 if len(keys) != 0 { 245 t.Errorf("should be empty at end: %v", keys) 246 } 247 } 248 249 func ExerciseBackend_ListPrefix(t testing.TB, b Backend) { 250 t.Helper() 251 ctx := context.Background() 252 253 e1 := &Entry{Key: "foo", Value: []byte("test")} 254 e2 := &Entry{Key: "foo/bar", Value: []byte("test")} 255 e3 := &Entry{Key: "foo/bar/baz", Value: []byte("test")} 256 257 defer func() { 258 _ = b.Delete(ctx, "foo") 259 _ = b.Delete(ctx, "foo/bar") 260 _ = b.Delete(ctx, "foo/bar/baz") 261 }() 262 263 err := b.Put(ctx, e1) 264 if err != nil { 265 t.Fatalf("failed to put entry 1: %v", err) 266 } 267 err = b.Put(ctx, e2) 268 if err != nil { 269 t.Fatalf("failed to put entry 2: %v", err) 270 } 271 err = b.Put(ctx, e3) 272 if err != nil { 273 t.Fatalf("failed to put entry 3: %v", err) 274 } 275 276 // Scan the root 277 keys, err := b.List(ctx, "") 278 if err != nil { 279 t.Fatalf("list root: %v", err) 280 } 281 sort.Strings(keys) 282 if len(keys) != 2 || keys[0] != "foo" || keys[1] != "foo/" { 283 t.Errorf("root expected [foo foo/]: %v", keys) 284 } 285 286 // Scan foo/ 287 keys, err = b.List(ctx, "foo/") 288 if err != nil { 289 t.Fatalf("list level 1: %v", err) 290 } 291 sort.Strings(keys) 292 if len(keys) != 2 || keys[0] != "bar" || keys[1] != "bar/" { 293 t.Errorf("level 1 expected [bar bar/]: %v", keys) 294 } 295 296 // Scan foo/bar/ 297 keys, err = b.List(ctx, "foo/bar/") 298 if err != nil { 299 t.Fatalf("list level 2: %v", err) 300 } 301 sort.Strings(keys) 302 if len(keys) != 1 || keys[0] != "baz" { 303 t.Errorf("level 1 expected [baz]: %v", keys) 304 } 305 } 306 307 func ExerciseHABackend(t testing.TB, b HABackend, b2 HABackend) { 308 t.Helper() 309 310 // Get the lock 311 lock, err := b.LockWith("foo", "bar") 312 if err != nil { 313 t.Fatalf("initial lock: %v", err) 314 } 315 316 // Attempt to lock 317 leaderCh, err := lock.Lock(nil) 318 if err != nil { 319 t.Fatalf("lock attempt 1: %v", err) 320 } 321 if leaderCh == nil { 322 t.Fatalf("missing leaderCh") 323 } 324 325 // Check the value 326 held, val, err := lock.Value() 327 if err != nil { 328 t.Fatalf("err: %v", err) 329 } 330 if !held { 331 t.Errorf("should be held") 332 } 333 if val != "bar" { 334 t.Errorf("expected value bar: %v", err) 335 } 336 337 // Check if it's fencing that we can register the lock 338 if fba, ok := b.(FencingHABackend); ok { 339 require.NoError(t, fba.RegisterActiveNodeLock(lock)) 340 } 341 342 // Second acquisition should fail 343 lock2, err := b2.LockWith("foo", "baz") 344 if err != nil { 345 t.Fatalf("lock 2: %v", err) 346 } 347 348 // Checking the lock from b2 should discover that the lock is held since held 349 // implies only that there is _some_ leader not that b2 is leader (this was 350 // not clear before so we make it explicit with this assertion). 351 held2, val2, err := lock2.Value() 352 require.NoError(t, err) 353 require.Equal(t, "bar", val2) 354 require.True(t, held2) 355 356 // Cancel attempt in 50 msec 357 stopCh := make(chan struct{}) 358 time.AfterFunc(50*time.Millisecond, func() { 359 close(stopCh) 360 }) 361 362 // Attempt to lock 363 leaderCh2, err := lock2.Lock(stopCh) 364 if err != nil { 365 t.Fatalf("stop lock 2: %v", err) 366 } 367 if leaderCh2 != nil { 368 t.Errorf("should not have gotten leaderCh: %v", leaderCh2) 369 } 370 371 // Release the first lock 372 lock.Unlock() 373 374 // Attempt to lock should work 375 leaderCh2, err = lock2.Lock(nil) 376 if err != nil { 377 t.Fatalf("lock 2 lock: %v", err) 378 } 379 if leaderCh2 == nil { 380 t.Errorf("should get leaderCh") 381 } 382 383 // Check if it's fencing that we can register the lock 384 if fba2, ok := b2.(FencingHABackend); ok { 385 require.NoError(t, fba2.RegisterActiveNodeLock(lock)) 386 } 387 388 // Check the value 389 held, val, err = lock2.Value() 390 if err != nil { 391 t.Fatalf("value: %v", err) 392 } 393 if !held { 394 t.Errorf("should still be held") 395 } 396 if val != "baz" { 397 t.Errorf("expected: baz, got: %v", val) 398 } 399 400 // Cleanup 401 lock2.Unlock() 402 } 403 404 func ExerciseTransactionalBackend(t testing.TB, b Backend) { 405 t.Helper() 406 ctx := context.Background() 407 408 tb, ok := b.(Transactional) 409 if !ok { 410 t.Fatal("Not a transactional backend") 411 } 412 413 txns := SetupTestingTransactions(t, b) 414 415 if err := tb.Transaction(ctx, txns); err != nil { 416 t.Fatal(err) 417 } 418 419 keys, err := b.List(ctx, "") 420 if err != nil { 421 t.Fatal(err) 422 } 423 424 expected := []string{"foo", "zip"} 425 426 sort.Strings(keys) 427 sort.Strings(expected) 428 if !reflect.DeepEqual(keys, expected) { 429 t.Fatalf("mismatch: expected\n%#v\ngot\n%#v\n", expected, keys) 430 } 431 432 entry, err := b.Get(ctx, "foo") 433 if err != nil { 434 t.Fatal(err) 435 } 436 if entry == nil { 437 t.Fatal("got nil entry") 438 } 439 if entry.Value == nil { 440 t.Fatal("got nil value") 441 } 442 if string(entry.Value) != "bar3" { 443 t.Fatal("updates did not apply correctly") 444 } 445 446 entry, err = b.Get(ctx, "zip") 447 if err != nil { 448 t.Fatal(err) 449 } 450 if entry == nil { 451 t.Fatal("got nil entry") 452 } 453 if entry.Value == nil { 454 t.Fatal("got nil value") 455 } 456 if string(entry.Value) != "zap3" { 457 t.Fatal("updates did not apply correctly") 458 } 459 } 460 461 func SetupTestingTransactions(t testing.TB, b Backend) []*TxnEntry { 462 t.Helper() 463 ctx := context.Background() 464 465 // Add a few keys so that we test rollback with deletion 466 if err := b.Put(ctx, &Entry{ 467 Key: "foo", 468 Value: []byte("bar"), 469 }); err != nil { 470 t.Fatal(err) 471 } 472 if err := b.Put(ctx, &Entry{ 473 Key: "zip", 474 Value: []byte("zap"), 475 }); err != nil { 476 t.Fatal(err) 477 } 478 if err := b.Put(ctx, &Entry{ 479 Key: "deleteme", 480 }); err != nil { 481 t.Fatal(err) 482 } 483 if err := b.Put(ctx, &Entry{ 484 Key: "deleteme2", 485 }); err != nil { 486 t.Fatal(err) 487 } 488 489 txns := []*TxnEntry{ 490 { 491 Operation: PutOperation, 492 Entry: &Entry{ 493 Key: "foo", 494 Value: []byte("bar2"), 495 }, 496 }, 497 { 498 Operation: DeleteOperation, 499 Entry: &Entry{ 500 Key: "deleteme", 501 }, 502 }, 503 { 504 Operation: PutOperation, 505 Entry: &Entry{ 506 Key: "foo", 507 Value: []byte("bar3"), 508 }, 509 }, 510 { 511 Operation: DeleteOperation, 512 Entry: &Entry{ 513 Key: "deleteme2", 514 }, 515 }, 516 { 517 Operation: PutOperation, 518 Entry: &Entry{ 519 Key: "zip", 520 Value: []byte("zap3"), 521 }, 522 }, 523 } 524 525 return txns 526 } 527 528 // Several tests across packages have to test logic with a few variations of 529 // transactional backends. Make some suitable for testing limits support that 530 // can be re-used. 531 532 type TestTransactionalNonLimitBackend struct{} 533 534 var _ Transactional = (*TestTransactionalNonLimitBackend)(nil) 535 536 func (b *TestTransactionalNonLimitBackend) Put(ctx context.Context, entry *Entry) error { 537 return nil 538 } 539 540 func (b *TestTransactionalNonLimitBackend) Get(ctx context.Context, key string) (*Entry, error) { 541 return nil, nil 542 } 543 544 func (b *TestTransactionalNonLimitBackend) Delete(ctx context.Context, key string) error { 545 return nil 546 } 547 548 func (b *TestTransactionalNonLimitBackend) List(ctx context.Context, prefix string) ([]string, error) { 549 return nil, nil 550 } 551 552 func (b *TestTransactionalNonLimitBackend) Transaction(ctx context.Context, txns []*TxnEntry) error { 553 return nil 554 } 555 556 type TestTransactionalLimitBackend struct { 557 TestTransactionalNonLimitBackend 558 559 MaxEntries, MaxSize int 560 } 561 562 var _ TransactionalLimits = (*TestTransactionalLimitBackend)(nil) 563 564 func (b *TestTransactionalLimitBackend) TransactionLimits() (int, int) { 565 return b.MaxEntries, b.MaxSize 566 }