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