github.com/ava-labs/avalanchego@v1.11.11/database/dbtest/dbtest.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package dbtest 5 6 import ( 7 "bytes" 8 "io" 9 "math" 10 "math/rand" 11 "slices" 12 "testing" 13 14 "github.com/stretchr/testify/require" 15 "go.uber.org/mock/gomock" 16 "golang.org/x/exp/maps" 17 "golang.org/x/sync/errgroup" 18 19 "github.com/ava-labs/avalanchego/database" 20 "github.com/ava-labs/avalanchego/database/databasemock" 21 "github.com/ava-labs/avalanchego/utils" 22 "github.com/ava-labs/avalanchego/utils/units" 23 ) 24 25 // Tests is a list of all database tests 26 var Tests = map[string]func(t *testing.T, db database.Database){ 27 "SimpleKeyValue": TestSimpleKeyValue, 28 "OverwriteKeyValue": TestOverwriteKeyValue, 29 "EmptyKey": TestEmptyKey, 30 "KeyEmptyValue": TestKeyEmptyValue, 31 "SimpleKeyValueClosed": TestSimpleKeyValueClosed, 32 "NewBatchClosed": TestNewBatchClosed, 33 "BatchPut": TestBatchPut, 34 "BatchDelete": TestBatchDelete, 35 "BatchReset": TestBatchReset, 36 "BatchReuse": TestBatchReuse, 37 "BatchRewrite": TestBatchRewrite, 38 "BatchReplay": TestBatchReplay, 39 "BatchReplayPropagateError": TestBatchReplayPropagateError, 40 "BatchInner": TestBatchInner, 41 "BatchLargeSize": TestBatchLargeSize, 42 "IteratorSnapshot": TestIteratorSnapshot, 43 "Iterator": TestIterator, 44 "IteratorStart": TestIteratorStart, 45 "IteratorPrefix": TestIteratorPrefix, 46 "IteratorStartPrefix": TestIteratorStartPrefix, 47 "IteratorMemorySafety": TestIteratorMemorySafety, 48 "IteratorClosed": TestIteratorClosed, 49 "IteratorError": TestIteratorError, 50 "IteratorErrorAfterRelease": TestIteratorErrorAfterRelease, 51 "CompactNoPanic": TestCompactNoPanic, 52 "MemorySafetyDatabase": TestMemorySafetyDatabase, 53 "MemorySafetyBatch": TestMemorySafetyBatch, 54 "AtomicClear": TestAtomicClear, 55 "Clear": TestClear, 56 "AtomicClearPrefix": TestAtomicClearPrefix, 57 "ClearPrefix": TestClearPrefix, 58 "ModifyValueAfterPut": TestModifyValueAfterPut, 59 "ModifyValueAfterBatchPut": TestModifyValueAfterBatchPut, 60 "ModifyValueAfterBatchPutReplay": TestModifyValueAfterBatchPutReplay, 61 "ConcurrentBatches": TestConcurrentBatches, 62 "ManySmallConcurrentKVPairBatches": TestManySmallConcurrentKVPairBatches, 63 "PutGetEmpty": TestPutGetEmpty, 64 } 65 66 // TestSimpleKeyValue tests to make sure that simple Put + Get + Delete + Has 67 // calls return the expected values. 68 func TestSimpleKeyValue(t *testing.T, db database.Database) { 69 require := require.New(t) 70 71 key := []byte("hello") 72 value := []byte("world") 73 74 has, err := db.Has(key) 75 require.NoError(err) 76 require.False(has) 77 78 _, err = db.Get(key) 79 require.Equal(database.ErrNotFound, err) 80 81 require.NoError(db.Delete(key)) 82 require.NoError(db.Put(key, value)) 83 84 has, err = db.Has(key) 85 require.NoError(err) 86 require.True(has) 87 88 v, err := db.Get(key) 89 require.NoError(err) 90 require.Equal(value, v) 91 92 require.NoError(db.Delete(key)) 93 94 has, err = db.Has(key) 95 require.NoError(err) 96 require.False(has) 97 98 _, err = db.Get(key) 99 require.Equal(database.ErrNotFound, err) 100 101 require.NoError(db.Delete(key)) 102 } 103 104 func TestOverwriteKeyValue(t *testing.T, db database.Database) { 105 require := require.New(t) 106 107 key := []byte("hello") 108 value1 := []byte("world1") 109 value2 := []byte("world2") 110 111 require.NoError(db.Put(key, value1)) 112 113 require.NoError(db.Put(key, value2)) 114 115 gotValue, err := db.Get(key) 116 require.NoError(err) 117 require.Equal(value2, gotValue) 118 } 119 120 func TestKeyEmptyValue(t *testing.T, db database.Database) { 121 require := require.New(t) 122 123 key := []byte("hello") 124 val := []byte(nil) 125 126 _, err := db.Get(key) 127 require.Equal(database.ErrNotFound, err) 128 129 require.NoError(db.Put(key, val)) 130 131 value, err := db.Get(key) 132 require.NoError(err) 133 require.Empty(value) 134 } 135 136 func TestEmptyKey(t *testing.T, db database.Database) { 137 require := require.New(t) 138 139 var ( 140 nilKey = []byte(nil) 141 emptyKey = []byte{} 142 val1 = []byte("hi") 143 val2 = []byte("hello") 144 ) 145 146 // Test that nil key can be retrieved by empty key 147 _, err := db.Get(nilKey) 148 require.Equal(database.ErrNotFound, err) 149 150 require.NoError(db.Put(nilKey, val1)) 151 152 value, err := db.Get(emptyKey) 153 require.NoError(err) 154 require.Equal(value, val1) 155 156 // Test that empty key can be retrieved by nil key 157 require.NoError(db.Put(emptyKey, val2)) 158 159 value, err = db.Get(nilKey) 160 require.NoError(err) 161 require.Equal(value, val2) 162 } 163 164 // TestSimpleKeyValueClosed tests to make sure that Put + Get + Delete + Has 165 // calls return the correct error when the database has been closed. 166 func TestSimpleKeyValueClosed(t *testing.T, db database.Database) { 167 require := require.New(t) 168 169 key := []byte("hello") 170 value := []byte("world") 171 172 has, err := db.Has(key) 173 require.NoError(err) 174 require.False(has) 175 176 _, err = db.Get(key) 177 require.Equal(database.ErrNotFound, err) 178 179 require.NoError(db.Delete(key)) 180 require.NoError(db.Put(key, value)) 181 182 has, err = db.Has(key) 183 require.NoError(err) 184 require.True(has) 185 186 v, err := db.Get(key) 187 require.NoError(err) 188 require.Equal(value, v) 189 190 require.NoError(db.Close()) 191 192 _, err = db.Has(key) 193 require.Equal(database.ErrClosed, err) 194 195 _, err = db.Get(key) 196 require.Equal(database.ErrClosed, err) 197 198 require.Equal(database.ErrClosed, db.Put(key, value)) 199 require.Equal(database.ErrClosed, db.Delete(key)) 200 require.Equal(database.ErrClosed, db.Close()) 201 } 202 203 // TestMemorySafetyDatabase ensures it is safe to modify a key after passing it 204 // to Database.Put and Database.Get. 205 func TestMemorySafetyDatabase(t *testing.T, db database.Database) { 206 require := require.New(t) 207 208 key := []byte("1key") 209 keyCopy := slices.Clone(key) 210 value := []byte("value") 211 key2 := []byte("2key") 212 value2 := []byte("value2") 213 214 // Put both K/V pairs in the database 215 require.NoError(db.Put(key, value)) 216 require.NoError(db.Put(key2, value2)) 217 218 // Get the value for [key] 219 gotVal, err := db.Get(key) 220 require.NoError(err) 221 require.Equal(value, gotVal) 222 223 // Modify [key]; make sure the value we got before hasn't changed 224 key[0] = key2[0] 225 gotVal2, err := db.Get(key) 226 require.NoError(err) 227 require.Equal(value2, gotVal2) 228 require.Equal(value, gotVal) 229 230 // Reset [key] to its original value and make sure it's correct 231 key[0] = keyCopy[0] 232 gotVal, err = db.Get(key) 233 require.NoError(err) 234 require.Equal(value, gotVal) 235 } 236 237 // TestNewBatchClosed tests to make sure that calling NewBatch on a closed 238 // database returns a batch that errors correctly. 239 func TestNewBatchClosed(t *testing.T, db database.Database) { 240 require := require.New(t) 241 242 require.NoError(db.Close()) 243 244 batch := db.NewBatch() 245 require.NotNil(batch) 246 247 key := []byte("hello") 248 value := []byte("world") 249 250 require.NoError(batch.Put(key, value)) 251 require.Positive(batch.Size()) 252 require.Equal(database.ErrClosed, batch.Write()) 253 } 254 255 // TestBatchPut tests to make sure that batched writes work as expected. 256 func TestBatchPut(t *testing.T, db database.Database) { 257 require := require.New(t) 258 259 key := []byte("hello") 260 value := []byte("world") 261 262 batch := db.NewBatch() 263 require.NotNil(batch) 264 265 require.NoError(batch.Put(key, value)) 266 require.Positive(batch.Size()) 267 require.NoError(batch.Write()) 268 269 has, err := db.Has(key) 270 require.NoError(err) 271 require.True(has) 272 273 v, err := db.Get(key) 274 require.NoError(err) 275 require.Equal(value, v) 276 277 require.NoError(db.Delete(key)) 278 279 batch = db.NewBatch() 280 require.NotNil(batch) 281 282 require.NoError(batch.Put(key, value)) 283 require.NoError(db.Close()) 284 require.Equal(database.ErrClosed, batch.Write()) 285 } 286 287 // TestBatchDelete tests to make sure that batched deletes work as expected. 288 func TestBatchDelete(t *testing.T, db database.Database) { 289 require := require.New(t) 290 291 key := []byte("hello") 292 value := []byte("world") 293 294 require.NoError(db.Put(key, value)) 295 296 batch := db.NewBatch() 297 require.NotNil(batch) 298 299 require.NoError(batch.Delete(key)) 300 require.NoError(batch.Write()) 301 302 has, err := db.Has(key) 303 require.NoError(err) 304 require.False(has) 305 306 _, err = db.Get(key) 307 require.Equal(database.ErrNotFound, err) 308 309 require.NoError(db.Delete(key)) 310 } 311 312 // TestMemorySafetyBatch ensures it is safe to modify a key after passing it 313 // to Batch.Put. 314 func TestMemorySafetyBatch(t *testing.T, db database.Database) { 315 require := require.New(t) 316 317 key := []byte("hello") 318 keyCopy := slices.Clone(key) 319 value := []byte("world") 320 valueCopy := slices.Clone(value) 321 322 batch := db.NewBatch() 323 require.NotNil(batch) 324 325 // Put a key in the batch 326 require.NoError(batch.Put(key, value)) 327 require.Positive(batch.Size()) 328 329 // Modify the key 330 key[0] = 'j' 331 require.NoError(batch.Write()) 332 333 // Make sure the original key was written to the database 334 has, err := db.Has(keyCopy) 335 require.NoError(err) 336 require.True(has) 337 338 v, err := db.Get(keyCopy) 339 require.NoError(err) 340 require.Equal(valueCopy, v) 341 342 // Make sure the new key wasn't written to the database 343 has, err = db.Has(key) 344 require.NoError(err) 345 require.False(has) 346 } 347 348 // TestBatchReset tests to make sure that a batch drops un-written operations 349 // when it is reset. 350 func TestBatchReset(t *testing.T, db database.Database) { 351 require := require.New(t) 352 353 key := []byte("hello") 354 value := []byte("world") 355 356 require.NoError(db.Put(key, value)) 357 358 batch := db.NewBatch() 359 require.NotNil(batch) 360 361 require.NoError(batch.Delete(key)) 362 363 batch.Reset() 364 365 require.Zero(batch.Size()) 366 require.NoError(batch.Write()) 367 368 has, err := db.Has(key) 369 require.NoError(err) 370 require.True(has) 371 372 v, err := db.Get(key) 373 require.NoError(err) 374 require.Equal(value, v) 375 } 376 377 // TestBatchReuse tests to make sure that a batch can be reused once it is 378 // reset. 379 func TestBatchReuse(t *testing.T, db database.Database) { 380 require := require.New(t) 381 382 key1 := []byte("hello1") 383 value1 := []byte("world1") 384 385 key2 := []byte("hello2") 386 value2 := []byte("world2") 387 388 batch := db.NewBatch() 389 require.NotNil(batch) 390 391 require.NoError(batch.Put(key1, value1)) 392 require.NoError(batch.Write()) 393 require.NoError(db.Delete(key1)) 394 395 has, err := db.Has(key1) 396 require.NoError(err) 397 require.False(has) 398 399 batch.Reset() 400 401 require.Zero(batch.Size()) 402 require.NoError(batch.Put(key2, value2)) 403 require.NoError(batch.Write()) 404 405 has, err = db.Has(key1) 406 require.NoError(err) 407 require.False(has) 408 409 has, err = db.Has(key2) 410 require.NoError(err) 411 require.True(has) 412 413 v, err := db.Get(key2) 414 require.NoError(err) 415 require.Equal(value2, v) 416 } 417 418 // TestBatchRewrite tests to make sure that write can be called multiple times 419 // on a batch and the values will be updated correctly. 420 func TestBatchRewrite(t *testing.T, db database.Database) { 421 require := require.New(t) 422 423 key := []byte("hello1") 424 value := []byte("world1") 425 426 batch := db.NewBatch() 427 require.NotNil(batch) 428 429 require.NoError(batch.Put(key, value)) 430 require.NoError(batch.Write()) 431 require.NoError(db.Delete(key)) 432 433 has, err := db.Has(key) 434 require.NoError(err) 435 require.False(has) 436 437 require.NoError(batch.Write()) 438 439 has, err = db.Has(key) 440 require.NoError(err) 441 require.True(has) 442 443 v, err := db.Get(key) 444 require.NoError(err) 445 require.Equal(value, v) 446 } 447 448 // TestBatchReplay tests to make sure that batches will correctly replay their 449 // contents. 450 func TestBatchReplay(t *testing.T, db database.Database) { 451 ctrl := gomock.NewController(t) 452 require := require.New(t) 453 454 key1 := []byte("hello1") 455 value1 := []byte("world1") 456 457 key2 := []byte("hello2") 458 value2 := []byte("world2") 459 460 batch := db.NewBatch() 461 require.NotNil(batch) 462 463 require.NoError(batch.Put(key1, value1)) 464 require.NoError(batch.Put(key2, value2)) 465 require.NoError(batch.Delete(key1)) 466 require.NoError(batch.Delete(key2)) 467 require.NoError(batch.Put(key1, value2)) 468 469 for i := 0; i < 2; i++ { 470 mockBatch := databasemock.NewBatch(ctrl) 471 gomock.InOrder( 472 mockBatch.EXPECT().Put(key1, value1).Times(1), 473 mockBatch.EXPECT().Put(key2, value2).Times(1), 474 mockBatch.EXPECT().Delete(key1).Times(1), 475 mockBatch.EXPECT().Delete(key2).Times(1), 476 mockBatch.EXPECT().Put(key1, value2).Times(1), 477 ) 478 479 require.NoError(batch.Replay(mockBatch)) 480 } 481 } 482 483 // TestBatchReplayPropagateError tests to make sure that batches will correctly 484 // propagate any returned error during Replay. 485 func TestBatchReplayPropagateError(t *testing.T, db database.Database) { 486 ctrl := gomock.NewController(t) 487 require := require.New(t) 488 489 key1 := []byte("hello1") 490 value1 := []byte("world1") 491 492 key2 := []byte("hello2") 493 value2 := []byte("world2") 494 495 batch := db.NewBatch() 496 require.NotNil(batch) 497 498 require.NoError(batch.Put(key1, value1)) 499 require.NoError(batch.Put(key2, value2)) 500 501 mockBatch := databasemock.NewBatch(ctrl) 502 gomock.InOrder( 503 mockBatch.EXPECT().Put(key1, value1).Return(database.ErrClosed).Times(1), 504 ) 505 require.Equal(database.ErrClosed, batch.Replay(mockBatch)) 506 507 mockBatch = databasemock.NewBatch(ctrl) 508 gomock.InOrder( 509 mockBatch.EXPECT().Put(key1, value1).Return(io.ErrClosedPipe).Times(1), 510 ) 511 require.Equal(io.ErrClosedPipe, batch.Replay(mockBatch)) 512 } 513 514 // TestBatchInner tests to make sure that inner can be used to write to the 515 // database. 516 func TestBatchInner(t *testing.T, db database.Database) { 517 require := require.New(t) 518 519 key1 := []byte("hello1") 520 value1 := []byte("world1") 521 522 key2 := []byte("hello2") 523 value2 := []byte("world2") 524 525 firstBatch := db.NewBatch() 526 require.NotNil(firstBatch) 527 528 require.NoError(firstBatch.Put(key1, value1)) 529 530 secondBatch := db.NewBatch() 531 require.NotNil(firstBatch) 532 533 require.NoError(secondBatch.Put(key2, value2)) 534 535 innerFirstBatch := firstBatch.Inner() 536 require.NotNil(innerFirstBatch) 537 538 innerSecondBatch := secondBatch.Inner() 539 require.NotNil(innerSecondBatch) 540 541 require.NoError(innerFirstBatch.Replay(innerSecondBatch)) 542 require.NoError(innerSecondBatch.Write()) 543 544 has, err := db.Has(key1) 545 require.NoError(err) 546 require.True(has) 547 548 v, err := db.Get(key1) 549 require.NoError(err) 550 require.Equal(value1, v) 551 552 has, err = db.Has(key2) 553 require.NoError(err) 554 require.True(has) 555 556 v, err = db.Get(key2) 557 require.NoError(err) 558 require.Equal(value2, v) 559 } 560 561 // TestBatchLargeSize tests to make sure that the batch can support a large 562 // amount of entries. 563 func TestBatchLargeSize(t *testing.T, db database.Database) { 564 require := require.New(t) 565 566 totalSize := 8 * units.MiB 567 elementSize := 4 * units.KiB 568 pairSize := 2 * elementSize // 8 KiB 569 570 bytes := utils.RandomBytes(totalSize) 571 572 batch := db.NewBatch() 573 require.NotNil(batch) 574 575 for len(bytes) > pairSize { 576 key := bytes[:elementSize] 577 bytes = bytes[elementSize:] 578 579 value := bytes[:elementSize] 580 bytes = bytes[elementSize:] 581 582 require.NoError(batch.Put(key, value)) 583 } 584 585 require.NoError(batch.Write()) 586 } 587 588 // TestIteratorSnapshot tests to make sure the database iterates over a snapshot 589 // of the database at the time of the iterator creation. 590 func TestIteratorSnapshot(t *testing.T, db database.Database) { 591 require := require.New(t) 592 593 key1 := []byte("hello1") 594 value1 := []byte("world1") 595 596 key2 := []byte("hello2") 597 value2 := []byte("world2") 598 599 require.NoError(db.Put(key1, value1)) 600 601 iterator := db.NewIterator() 602 require.NotNil(iterator) 603 604 defer iterator.Release() 605 606 require.NoError(db.Put(key2, value2)) 607 require.True(iterator.Next()) 608 require.Equal(key1, iterator.Key()) 609 require.Equal(value1, iterator.Value()) 610 611 require.False(iterator.Next()) 612 require.Nil(iterator.Key()) 613 require.Nil(iterator.Value()) 614 require.NoError(iterator.Error()) 615 } 616 617 // TestIterator tests to make sure the database iterates over the database 618 // contents lexicographically. 619 func TestIterator(t *testing.T, db database.Database) { 620 require := require.New(t) 621 622 key1 := []byte("hello1") 623 value1 := []byte("world1") 624 625 key2 := []byte("hello2") 626 value2 := []byte("world2") 627 628 require.NoError(db.Put(key1, value1)) 629 require.NoError(db.Put(key2, value2)) 630 631 iterator := db.NewIterator() 632 require.NotNil(iterator) 633 634 defer iterator.Release() 635 636 require.True(iterator.Next()) 637 require.Equal(key1, iterator.Key()) 638 require.Equal(value1, iterator.Value()) 639 640 require.True(iterator.Next()) 641 require.Equal(key2, iterator.Key()) 642 require.Equal(value2, iterator.Value()) 643 644 require.False(iterator.Next()) 645 require.Nil(iterator.Key()) 646 require.Nil(iterator.Value()) 647 require.NoError(iterator.Error()) 648 } 649 650 // TestIteratorStart tests to make sure the iterator can be configured to 651 // start mid way through the database. 652 func TestIteratorStart(t *testing.T, db database.Database) { 653 require := require.New(t) 654 655 key1 := []byte("hello1") 656 value1 := []byte("world1") 657 658 key2 := []byte("hello2") 659 value2 := []byte("world2") 660 661 require.NoError(db.Put(key1, value1)) 662 require.NoError(db.Put(key2, value2)) 663 664 iterator := db.NewIteratorWithStart(key2) 665 require.NotNil(iterator) 666 667 defer iterator.Release() 668 669 require.True(iterator.Next()) 670 require.Equal(key2, iterator.Key()) 671 require.Equal(value2, iterator.Value()) 672 673 require.False(iterator.Next()) 674 require.Nil(iterator.Key()) 675 require.Nil(iterator.Value()) 676 require.NoError(iterator.Error()) 677 } 678 679 // TestIteratorPrefix tests to make sure the iterator can be configured to skip 680 // keys missing the provided prefix. 681 func TestIteratorPrefix(t *testing.T, db database.Database) { 682 require := require.New(t) 683 684 key1 := []byte("hello") 685 value1 := []byte("world1") 686 687 key2 := []byte("goodbye") 688 value2 := []byte("world2") 689 690 key3 := []byte("joy") 691 value3 := []byte("world3") 692 693 require.NoError(db.Put(key1, value1)) 694 require.NoError(db.Put(key2, value2)) 695 require.NoError(db.Put(key3, value3)) 696 697 iterator := db.NewIteratorWithPrefix([]byte("h")) 698 require.NotNil(iterator) 699 700 defer iterator.Release() 701 702 require.True(iterator.Next()) 703 require.Equal(key1, iterator.Key()) 704 require.Equal(value1, iterator.Value()) 705 706 require.False(iterator.Next()) 707 require.Nil(iterator.Key()) 708 require.Nil(iterator.Value()) 709 require.NoError(iterator.Error()) 710 } 711 712 // TestIteratorStartPrefix tests to make sure that the iterator can start mid 713 // way through the database while skipping a prefix. 714 func TestIteratorStartPrefix(t *testing.T, db database.Database) { 715 require := require.New(t) 716 717 key1 := []byte("hello1") 718 value1 := []byte("world1") 719 720 key2 := []byte("z") 721 value2 := []byte("world2") 722 723 key3 := []byte("hello3") 724 value3 := []byte("world3") 725 726 require.NoError(db.Put(key1, value1)) 727 require.NoError(db.Put(key2, value2)) 728 require.NoError(db.Put(key3, value3)) 729 730 iterator := db.NewIteratorWithStartAndPrefix(key1, []byte("h")) 731 require.NotNil(iterator) 732 733 defer iterator.Release() 734 735 require.True(iterator.Next()) 736 require.Equal(key1, iterator.Key()) 737 require.Equal(value1, iterator.Value()) 738 739 require.True(iterator.Next()) 740 require.Equal(key3, iterator.Key()) 741 require.Equal(value3, iterator.Value()) 742 743 require.False(iterator.Next()) 744 require.Nil(iterator.Key()) 745 require.Nil(iterator.Value()) 746 require.NoError(iterator.Error()) 747 } 748 749 // TestIteratorMemorySafety tests to make sure that keys can values are able to 750 // be modified from the returned iterator. 751 func TestIteratorMemorySafety(t *testing.T, db database.Database) { 752 require := require.New(t) 753 754 key1 := []byte("hello1") 755 value1 := []byte("world1") 756 757 key2 := []byte("z") 758 value2 := []byte("world2") 759 760 key3 := []byte("hello3") 761 value3 := []byte("world3") 762 763 require.NoError(db.Put(key1, value1)) 764 require.NoError(db.Put(key2, value2)) 765 require.NoError(db.Put(key3, value3)) 766 767 iterator := db.NewIterator() 768 require.NotNil(iterator) 769 770 defer iterator.Release() 771 772 keys := [][]byte{} 773 values := [][]byte{} 774 for iterator.Next() { 775 keys = append(keys, iterator.Key()) 776 values = append(values, iterator.Value()) 777 } 778 779 expectedKeys := [][]byte{ 780 key1, 781 key3, 782 key2, 783 } 784 expectedValues := [][]byte{ 785 value1, 786 value3, 787 value2, 788 } 789 790 for i, key := range keys { 791 value := values[i] 792 expectedKey := expectedKeys[i] 793 expectedValue := expectedValues[i] 794 795 require.Equal(expectedKey, key) 796 require.Equal(expectedValue, value) 797 } 798 } 799 800 // TestIteratorClosed tests to make sure that an iterator that was created with 801 // a closed database will report a closed error correctly. 802 func TestIteratorClosed(t *testing.T, db database.Database) { 803 require := require.New(t) 804 805 key1 := []byte("hello1") 806 value1 := []byte("world1") 807 808 require.NoError(db.Put(key1, value1)) 809 require.NoError(db.Close()) 810 811 { 812 iterator := db.NewIterator() 813 require.NotNil(iterator) 814 815 defer iterator.Release() 816 817 require.False(iterator.Next()) 818 require.Nil(iterator.Key()) 819 require.Nil(iterator.Value()) 820 require.Equal(database.ErrClosed, iterator.Error()) 821 } 822 823 { 824 iterator := db.NewIteratorWithPrefix(nil) 825 require.NotNil(iterator) 826 827 defer iterator.Release() 828 829 require.False(iterator.Next()) 830 require.Nil(iterator.Key()) 831 require.Nil(iterator.Value()) 832 require.Equal(database.ErrClosed, iterator.Error()) 833 } 834 835 { 836 iterator := db.NewIteratorWithStart(nil) 837 require.NotNil(iterator) 838 839 defer iterator.Release() 840 841 require.False(iterator.Next()) 842 require.Nil(iterator.Key()) 843 require.Nil(iterator.Value()) 844 require.Equal(database.ErrClosed, iterator.Error()) 845 } 846 847 { 848 iterator := db.NewIteratorWithStartAndPrefix(nil, nil) 849 require.NotNil(iterator) 850 851 defer iterator.Release() 852 853 require.False(iterator.Next()) 854 require.Nil(iterator.Key()) 855 require.Nil(iterator.Value()) 856 require.Equal(database.ErrClosed, iterator.Error()) 857 } 858 } 859 860 // TestIteratorError tests to make sure that an iterator on a database will report 861 // itself as being exhausted and return [database.ErrClosed] to indicate that the iteration 862 // was not successful. 863 // Additionally tests that an iterator that has already called Next() can still serve 864 // its current value after the underlying DB was closed. 865 func TestIteratorError(t *testing.T, db database.Database) { 866 require := require.New(t) 867 868 key1 := []byte("hello1") 869 value1 := []byte("world1") 870 871 key2 := []byte("hello2") 872 value2 := []byte("world2") 873 874 require.NoError(db.Put(key1, value1)) 875 require.NoError(db.Put(key2, value2)) 876 877 iterator := db.NewIterator() 878 require.NotNil(iterator) 879 880 defer iterator.Release() 881 882 // Call Next() and ensure that if the database is closed, the iterator 883 // can still report the current contents. 884 require.True(iterator.Next()) 885 require.NoError(db.Close()) 886 require.Equal(key1, iterator.Key()) 887 require.Equal(value1, iterator.Value()) 888 889 // Subsequent calls to the iterator should return false and report an error 890 require.False(iterator.Next()) 891 require.Nil(iterator.Key()) 892 require.Nil(iterator.Value()) 893 require.Equal(database.ErrClosed, iterator.Error()) 894 } 895 896 // TestIteratorErrorAfterRelease tests to make sure that an iterator that was 897 // released still reports the error correctly. 898 func TestIteratorErrorAfterRelease(t *testing.T, db database.Database) { 899 require := require.New(t) 900 901 key := []byte("hello1") 902 value := []byte("world1") 903 904 require.NoError(db.Put(key, value)) 905 require.NoError(db.Close()) 906 907 iterator := db.NewIterator() 908 require.NotNil(iterator) 909 910 iterator.Release() 911 912 require.False(iterator.Next()) 913 require.Nil(iterator.Key()) 914 require.Nil(iterator.Value()) 915 require.Equal(database.ErrClosed, iterator.Error()) 916 } 917 918 // TestCompactNoPanic tests to make sure compact never panics. 919 func TestCompactNoPanic(t *testing.T, db database.Database) { 920 require := require.New(t) 921 922 key1 := []byte("hello1") 923 value1 := []byte("world1") 924 925 key2 := []byte("z") 926 value2 := []byte("world2") 927 928 key3 := []byte("hello3") 929 value3 := []byte("world3") 930 931 require.NoError(db.Put(key1, value1)) 932 require.NoError(db.Put(key2, value2)) 933 require.NoError(db.Put(key3, value3)) 934 935 // Test compacting with nil bounds 936 require.NoError(db.Compact(nil, nil)) 937 938 // Test compacting when start > end 939 require.NoError(db.Compact([]byte{2}, []byte{1})) 940 941 // Test compacting when start > largest key 942 require.NoError(db.Compact([]byte{255}, nil)) 943 944 require.NoError(db.Close()) 945 err := db.Compact(nil, nil) 946 require.ErrorIs(err, database.ErrClosed) 947 } 948 949 func TestAtomicClear(t *testing.T, db database.Database) { 950 testClear(t, db, func(db database.Database) error { 951 return database.AtomicClear(db, db) 952 }) 953 } 954 955 func TestClear(t *testing.T, db database.Database) { 956 testClear(t, db, func(db database.Database) error { 957 return database.Clear(db, math.MaxInt) 958 }) 959 } 960 961 // testClear tests to make sure the deletion helper works as expected. 962 func testClear(t *testing.T, db database.Database, clearF func(database.Database) error) { 963 require := require.New(t) 964 965 key1 := []byte("hello1") 966 value1 := []byte("world1") 967 968 key2 := []byte("z") 969 value2 := []byte("world2") 970 971 key3 := []byte("hello3") 972 value3 := []byte("world3") 973 974 require.NoError(db.Put(key1, value1)) 975 require.NoError(db.Put(key2, value2)) 976 require.NoError(db.Put(key3, value3)) 977 978 count, err := database.Count(db) 979 require.NoError(err) 980 require.Equal(3, count) 981 982 require.NoError(clearF(db)) 983 984 count, err = database.Count(db) 985 require.NoError(err) 986 require.Zero(count) 987 988 require.NoError(db.Close()) 989 } 990 991 func TestAtomicClearPrefix(t *testing.T, db database.Database) { 992 testClearPrefix(t, db, func(db database.Database, prefix []byte) error { 993 return database.AtomicClearPrefix(db, db, prefix) 994 }) 995 } 996 997 func TestClearPrefix(t *testing.T, db database.Database) { 998 testClearPrefix(t, db, func(db database.Database, prefix []byte) error { 999 return database.ClearPrefix(db, prefix, math.MaxInt) 1000 }) 1001 } 1002 1003 // testClearPrefix tests to make sure prefix deletion works as expected. 1004 func testClearPrefix(t *testing.T, db database.Database, clearF func(database.Database, []byte) error) { 1005 require := require.New(t) 1006 1007 key1 := []byte("hello1") 1008 value1 := []byte("world1") 1009 1010 key2 := []byte("z") 1011 value2 := []byte("world2") 1012 1013 key3 := []byte("hello3") 1014 value3 := []byte("world3") 1015 1016 require.NoError(db.Put(key1, value1)) 1017 require.NoError(db.Put(key2, value2)) 1018 require.NoError(db.Put(key3, value3)) 1019 1020 count, err := database.Count(db) 1021 require.NoError(err) 1022 require.Equal(3, count) 1023 1024 require.NoError(clearF(db, []byte("hello"))) 1025 1026 count, err = database.Count(db) 1027 require.NoError(err) 1028 require.Equal(1, count) 1029 1030 has, err := db.Has(key1) 1031 require.NoError(err) 1032 require.False(has) 1033 1034 has, err = db.Has(key2) 1035 require.NoError(err) 1036 require.True(has) 1037 1038 has, err = db.Has(key3) 1039 require.NoError(err) 1040 require.False(has) 1041 1042 require.NoError(db.Close()) 1043 } 1044 1045 func TestModifyValueAfterPut(t *testing.T, db database.Database) { 1046 require := require.New(t) 1047 1048 key := []byte{1} 1049 value := []byte{1, 2} 1050 originalValue := slices.Clone(value) 1051 1052 require.NoError(db.Put(key, value)) 1053 1054 // Modify the value that was Put into the database 1055 // to see if the database copied the value correctly. 1056 value[0] = 2 1057 retrievedValue, err := db.Get(key) 1058 require.NoError(err) 1059 require.Equal(originalValue, retrievedValue) 1060 } 1061 1062 func TestModifyValueAfterBatchPut(t *testing.T, db database.Database) { 1063 require := require.New(t) 1064 1065 key := []byte{1} 1066 value := []byte{1, 2} 1067 originalValue := slices.Clone(value) 1068 1069 batch := db.NewBatch() 1070 require.NoError(batch.Put(key, value)) 1071 1072 // Modify the value that was Put into the Batch and then Write the 1073 // batch to the database. 1074 value[0] = 2 1075 require.NoError(batch.Write()) 1076 1077 // Verify that the value written to the database contains matches the original 1078 // value of the byte slice when Put was called. 1079 retrievedValue, err := db.Get(key) 1080 require.NoError(err) 1081 require.Equal(originalValue, retrievedValue) 1082 } 1083 1084 func TestModifyValueAfterBatchPutReplay(t *testing.T, db database.Database) { 1085 require := require.New(t) 1086 1087 key := []byte{1} 1088 value := []byte{1, 2} 1089 originalValue := slices.Clone(value) 1090 1091 batch := db.NewBatch() 1092 require.NoError(batch.Put(key, value)) 1093 1094 // Modify the value that was Put into the Batch and then Write the 1095 // batch to the database. 1096 value[0] = 2 1097 1098 // Create a new batch and replay the batch onto this one before writing it to the DB. 1099 replayBatch := db.NewBatch() 1100 require.NoError(batch.Replay(replayBatch)) 1101 require.NoError(replayBatch.Write()) 1102 1103 // Verify that the value written to the database contains matches the original 1104 // value of the byte slice when Put was called. 1105 retrievedValue, err := db.Get(key) 1106 require.NoError(err) 1107 require.Equal(originalValue, retrievedValue) 1108 } 1109 1110 func TestConcurrentBatches(t *testing.T, db database.Database) { 1111 numBatches := 10 1112 keysPerBatch := 50 1113 keySize := 32 1114 valueSize := units.KiB 1115 1116 require.NoError(t, runConcurrentBatches( 1117 db, 1118 numBatches, 1119 keysPerBatch, 1120 keySize, 1121 valueSize, 1122 )) 1123 } 1124 1125 func TestManySmallConcurrentKVPairBatches(t *testing.T, db database.Database) { 1126 numBatches := 100 1127 keysPerBatch := 10 1128 keySize := 10 1129 valueSize := 10 1130 1131 require.NoError(t, runConcurrentBatches( 1132 db, 1133 numBatches, 1134 keysPerBatch, 1135 keySize, 1136 valueSize, 1137 )) 1138 } 1139 1140 func runConcurrentBatches( 1141 db database.Database, 1142 numBatches, 1143 keysPerBatch, 1144 keySize, 1145 valueSize int, 1146 ) error { 1147 batches := make([]database.Batch, 0, numBatches) 1148 for i := 0; i < numBatches; i++ { 1149 batches = append(batches, db.NewBatch()) 1150 } 1151 1152 for _, batch := range batches { 1153 for i := 0; i < keysPerBatch; i++ { 1154 key := utils.RandomBytes(keySize) 1155 value := utils.RandomBytes(valueSize) 1156 if err := batch.Put(key, value); err != nil { 1157 return err 1158 } 1159 } 1160 } 1161 1162 var eg errgroup.Group 1163 for _, batch := range batches { 1164 eg.Go(batch.Write) 1165 } 1166 return eg.Wait() 1167 } 1168 1169 func TestPutGetEmpty(t *testing.T, db database.Database) { 1170 require := require.New(t) 1171 1172 key := []byte("hello") 1173 1174 require.NoError(db.Put(key, nil)) 1175 1176 value, err := db.Get(key) 1177 require.NoError(err) 1178 require.Empty(value) // May be nil or empty byte slice. 1179 1180 require.NoError(db.Put(key, []byte{})) 1181 1182 value, err = db.Get(key) 1183 require.NoError(err) 1184 require.Empty(value) // May be nil or empty byte slice. 1185 } 1186 1187 func FuzzKeyValue(f *testing.F, db database.Database) { 1188 f.Fuzz(func(t *testing.T, key []byte, value []byte) { 1189 require := require.New(t) 1190 1191 require.NoError(db.Put(key, value)) 1192 1193 exists, err := db.Has(key) 1194 require.NoError(err) 1195 require.True(exists) 1196 1197 gotVal, err := db.Get(key) 1198 require.NoError(err) 1199 require.True(bytes.Equal(value, gotVal)) 1200 1201 require.NoError(db.Delete(key)) 1202 1203 exists, err = db.Has(key) 1204 require.NoError(err) 1205 require.False(exists) 1206 1207 _, err = db.Get(key) 1208 require.Equal(database.ErrNotFound, err) 1209 }) 1210 } 1211 1212 func FuzzNewIteratorWithPrefix(f *testing.F, db database.Database) { 1213 const ( 1214 maxKeyLen = 32 1215 maxValueLen = 32 1216 ) 1217 1218 f.Fuzz(func( 1219 t *testing.T, 1220 randSeed int64, 1221 prefix []byte, 1222 numKeyValues uint, 1223 ) { 1224 require := require.New(t) 1225 r := rand.New(rand.NewSource(randSeed)) // #nosec G404 1226 1227 // Put a bunch of key-values 1228 expected := map[string][]byte{} 1229 for i := 0; i < int(numKeyValues); i++ { 1230 key := make([]byte, r.Intn(maxKeyLen)) 1231 _, _ = r.Read(key) // #nosec G404 1232 1233 value := make([]byte, r.Intn(maxValueLen)) 1234 _, _ = r.Read(value) // #nosec G404 1235 1236 if len(value) == 0 { 1237 // Consistently treat zero length values as nil 1238 // so that we can compare [expected] and [got] with 1239 // require.Equal, which treats nil and empty byte 1240 // as being unequal, whereas the database treats 1241 // them as being equal. 1242 value = nil 1243 } 1244 1245 if bytes.HasPrefix(key, prefix) { 1246 expected[string(key)] = value 1247 } 1248 1249 require.NoError(db.Put(key, value)) 1250 } 1251 expectedList := maps.Keys(expected) 1252 slices.Sort(expectedList) 1253 1254 iter := db.NewIteratorWithPrefix(prefix) 1255 defer iter.Release() 1256 1257 // Assert the iterator returns the expected key-values. 1258 numIterElts := 0 1259 for iter.Next() { 1260 val := iter.Value() 1261 if len(val) == 0 { 1262 val = nil 1263 } 1264 require.Equal(expectedList[numIterElts], string(iter.Key())) 1265 require.Equal(expected[string(iter.Key())], val) 1266 numIterElts++ 1267 } 1268 require.Len(expectedList, numIterElts) 1269 1270 // Clear the database for the next fuzz iteration. 1271 require.NoError(database.AtomicClear(db, db)) 1272 }) 1273 } 1274 1275 func FuzzNewIteratorWithStartAndPrefix(f *testing.F, db database.Database) { 1276 const ( 1277 maxKeyLen = 32 1278 maxValueLen = 32 1279 ) 1280 1281 f.Fuzz(func( 1282 t *testing.T, 1283 randSeed int64, 1284 start []byte, 1285 prefix []byte, 1286 numKeyValues uint, 1287 ) { 1288 require := require.New(t) 1289 r := rand.New(rand.NewSource(randSeed)) // #nosec G404 1290 1291 expected := map[string][]byte{} 1292 1293 // Put a bunch of key-values 1294 for i := 0; i < int(numKeyValues); i++ { 1295 key := make([]byte, r.Intn(maxKeyLen)) 1296 _, _ = r.Read(key) // #nosec G404 1297 1298 value := make([]byte, r.Intn(maxValueLen)) 1299 _, _ = r.Read(value) // #nosec G404 1300 1301 if len(value) == 0 { 1302 // Consistently treat zero length values as nil 1303 // so that we can compare [expected] and [got] with 1304 // require.Equal, which treats nil and empty byte 1305 // as being unequal, whereas the database treats 1306 // them as being equal. 1307 value = nil 1308 } 1309 1310 if bytes.HasPrefix(key, prefix) && bytes.Compare(key, start) >= 0 { 1311 expected[string(key)] = value 1312 } 1313 1314 require.NoError(db.Put(key, value)) 1315 } 1316 1317 expectedList := maps.Keys(expected) 1318 slices.Sort(expectedList) 1319 1320 iter := db.NewIteratorWithStartAndPrefix(start, prefix) 1321 defer iter.Release() 1322 1323 // Assert the iterator returns the expected key-values. 1324 numIterElts := 0 1325 for iter.Next() { 1326 val := iter.Value() 1327 if len(val) == 0 { 1328 val = nil 1329 } 1330 keyStr := string(iter.Key()) 1331 require.Equal(expectedList[numIterElts], keyStr) 1332 require.Equal(expected[keyStr], val) 1333 numIterElts++ 1334 } 1335 require.Len(expectedList, numIterElts) 1336 1337 // Clear the database for the next fuzz iteration. 1338 require.NoError(database.AtomicClear(db, db)) 1339 }) 1340 }