github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/shed/index_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package shed 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "sort" 24 "testing" 25 "time" 26 27 "github.com/syndtr/goleveldb/leveldb" 28 ) 29 30 // Index functions for the index that is used in tests in this file. 31 var retrievalIndexFuncs = IndexFuncs{ 32 EncodeKey: func(fields Item) (key []byte, err error) { 33 return fields.Address, nil 34 }, 35 DecodeKey: func(key []byte) (e Item, err error) { 36 e.Address = key 37 return e, nil 38 }, 39 EncodeValue: func(fields Item) (value []byte, err error) { 40 b := make([]byte, 8) 41 binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) 42 value = append(b, fields.Data...) 43 return value, nil 44 }, 45 DecodeValue: func(keyItem Item, value []byte) (e Item, err error) { 46 e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) 47 e.Data = value[8:] 48 return e, nil 49 }, 50 } 51 52 // TestIndex validates put, get, has and delete functions of the Index implementation. 53 func TestIndex(t *testing.T) { 54 db, cleanupFunc := newTestDB(t) 55 defer cleanupFunc() 56 57 index, err := db.NewIndex("retrieval", retrievalIndexFuncs) 58 if err != nil { 59 t.Fatal(err) 60 } 61 62 t.Run("put", func(t *testing.T) { 63 want := Item{ 64 Address: []byte("put-hash"), 65 Data: []byte("DATA"), 66 StoreTimestamp: time.Now().UTC().UnixNano(), 67 } 68 69 err := index.Put(want) 70 if err != nil { 71 t.Fatal(err) 72 } 73 got, err := index.Get(Item{ 74 Address: want.Address, 75 }) 76 if err != nil { 77 t.Fatal(err) 78 } 79 checkItem(t, got, want) 80 81 t.Run("overwrite", func(t *testing.T) { 82 want := Item{ 83 Address: []byte("put-hash"), 84 Data: []byte("New DATA"), 85 StoreTimestamp: time.Now().UTC().UnixNano(), 86 } 87 88 err = index.Put(want) 89 if err != nil { 90 t.Fatal(err) 91 } 92 got, err := index.Get(Item{ 93 Address: want.Address, 94 }) 95 if err != nil { 96 t.Fatal(err) 97 } 98 checkItem(t, got, want) 99 }) 100 }) 101 102 t.Run("put in batch", func(t *testing.T) { 103 want := Item{ 104 Address: []byte("put-in-batch-hash"), 105 Data: []byte("DATA"), 106 StoreTimestamp: time.Now().UTC().UnixNano(), 107 } 108 109 batch := new(leveldb.Batch) 110 index.PutInBatch(batch, want) 111 err := db.WriteBatch(batch) 112 if err != nil { 113 t.Fatal(err) 114 } 115 got, err := index.Get(Item{ 116 Address: want.Address, 117 }) 118 if err != nil { 119 t.Fatal(err) 120 } 121 checkItem(t, got, want) 122 123 t.Run("overwrite", func(t *testing.T) { 124 want := Item{ 125 Address: []byte("put-in-batch-hash"), 126 Data: []byte("New DATA"), 127 StoreTimestamp: time.Now().UTC().UnixNano(), 128 } 129 130 batch := new(leveldb.Batch) 131 index.PutInBatch(batch, want) 132 db.WriteBatch(batch) 133 if err != nil { 134 t.Fatal(err) 135 } 136 got, err := index.Get(Item{ 137 Address: want.Address, 138 }) 139 if err != nil { 140 t.Fatal(err) 141 } 142 checkItem(t, got, want) 143 }) 144 }) 145 146 t.Run("put in batch twice", func(t *testing.T) { 147 // ensure that the last item of items with the same db keys 148 // is actually saved 149 batch := new(leveldb.Batch) 150 address := []byte("put-in-batch-twice-hash") 151 152 // put the first item 153 index.PutInBatch(batch, Item{ 154 Address: address, 155 Data: []byte("DATA"), 156 StoreTimestamp: time.Now().UTC().UnixNano(), 157 }) 158 159 want := Item{ 160 Address: address, 161 Data: []byte("New DATA"), 162 StoreTimestamp: time.Now().UTC().UnixNano(), 163 } 164 // then put the item that will produce the same key 165 // but different value in the database 166 index.PutInBatch(batch, want) 167 db.WriteBatch(batch) 168 if err != nil { 169 t.Fatal(err) 170 } 171 got, err := index.Get(Item{ 172 Address: address, 173 }) 174 if err != nil { 175 t.Fatal(err) 176 } 177 checkItem(t, got, want) 178 }) 179 180 t.Run("has", func(t *testing.T) { 181 want := Item{ 182 Address: []byte("has-hash"), 183 Data: []byte("DATA"), 184 StoreTimestamp: time.Now().UTC().UnixNano(), 185 } 186 187 dontWant := Item{ 188 Address: []byte("do-not-has-hash"), 189 Data: []byte("DATA"), 190 StoreTimestamp: time.Now().UTC().UnixNano(), 191 } 192 193 err := index.Put(want) 194 if err != nil { 195 t.Fatal(err) 196 } 197 198 has, err := index.Has(want) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if !has { 203 t.Error("item is not found") 204 } 205 206 has, err = index.Has(dontWant) 207 if err != nil { 208 t.Fatal(err) 209 } 210 if has { 211 t.Error("unwanted item is found") 212 } 213 }) 214 215 t.Run("delete", func(t *testing.T) { 216 want := Item{ 217 Address: []byte("delete-hash"), 218 Data: []byte("DATA"), 219 StoreTimestamp: time.Now().UTC().UnixNano(), 220 } 221 222 err := index.Put(want) 223 if err != nil { 224 t.Fatal(err) 225 } 226 got, err := index.Get(Item{ 227 Address: want.Address, 228 }) 229 if err != nil { 230 t.Fatal(err) 231 } 232 checkItem(t, got, want) 233 234 err = index.Delete(Item{ 235 Address: want.Address, 236 }) 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 wantErr := leveldb.ErrNotFound 242 got, err = index.Get(Item{ 243 Address: want.Address, 244 }) 245 if err != wantErr { 246 t.Fatalf("got error %v, want %v", err, wantErr) 247 } 248 }) 249 250 t.Run("delete in batch", func(t *testing.T) { 251 want := Item{ 252 Address: []byte("delete-in-batch-hash"), 253 Data: []byte("DATA"), 254 StoreTimestamp: time.Now().UTC().UnixNano(), 255 } 256 257 err := index.Put(want) 258 if err != nil { 259 t.Fatal(err) 260 } 261 got, err := index.Get(Item{ 262 Address: want.Address, 263 }) 264 if err != nil { 265 t.Fatal(err) 266 } 267 checkItem(t, got, want) 268 269 batch := new(leveldb.Batch) 270 index.DeleteInBatch(batch, Item{ 271 Address: want.Address, 272 }) 273 err = db.WriteBatch(batch) 274 if err != nil { 275 t.Fatal(err) 276 } 277 278 wantErr := leveldb.ErrNotFound 279 got, err = index.Get(Item{ 280 Address: want.Address, 281 }) 282 if err != wantErr { 283 t.Fatalf("got error %v, want %v", err, wantErr) 284 } 285 }) 286 } 287 288 // TestIndex_Iterate validates index Iterate 289 // functions for correctness. 290 func TestIndex_Iterate(t *testing.T) { 291 db, cleanupFunc := newTestDB(t) 292 defer cleanupFunc() 293 294 index, err := db.NewIndex("retrieval", retrievalIndexFuncs) 295 if err != nil { 296 t.Fatal(err) 297 } 298 299 items := []Item{ 300 { 301 Address: []byte("iterate-hash-01"), 302 Data: []byte("data80"), 303 }, 304 { 305 Address: []byte("iterate-hash-03"), 306 Data: []byte("data22"), 307 }, 308 { 309 Address: []byte("iterate-hash-05"), 310 Data: []byte("data41"), 311 }, 312 { 313 Address: []byte("iterate-hash-02"), 314 Data: []byte("data84"), 315 }, 316 { 317 Address: []byte("iterate-hash-06"), 318 Data: []byte("data1"), 319 }, 320 } 321 batch := new(leveldb.Batch) 322 for _, i := range items { 323 index.PutInBatch(batch, i) 324 } 325 err = db.WriteBatch(batch) 326 if err != nil { 327 t.Fatal(err) 328 } 329 item04 := Item{ 330 Address: []byte("iterate-hash-04"), 331 Data: []byte("data0"), 332 } 333 err = index.Put(item04) 334 if err != nil { 335 t.Fatal(err) 336 } 337 items = append(items, item04) 338 339 sort.SliceStable(items, func(i, j int) bool { 340 return bytes.Compare(items[i].Address, items[j].Address) < 0 341 }) 342 343 t.Run("all", func(t *testing.T) { 344 var i int 345 err := index.Iterate(func(item Item) (stop bool, err error) { 346 if i > len(items)-1 { 347 return true, fmt.Errorf("got unexpected index item: %#v", item) 348 } 349 want := items[i] 350 checkItem(t, item, want) 351 i++ 352 return false, nil 353 }, nil) 354 if err != nil { 355 t.Fatal(err) 356 } 357 }) 358 359 t.Run("start from", func(t *testing.T) { 360 startIndex := 2 361 i := startIndex 362 err := index.Iterate(func(item Item) (stop bool, err error) { 363 if i > len(items)-1 { 364 return true, fmt.Errorf("got unexpected index item: %#v", item) 365 } 366 want := items[i] 367 checkItem(t, item, want) 368 i++ 369 return false, nil 370 }, &IterateOptions{ 371 StartFrom: &items[startIndex], 372 }) 373 if err != nil { 374 t.Fatal(err) 375 } 376 }) 377 378 t.Run("skip start from", func(t *testing.T) { 379 startIndex := 2 380 i := startIndex + 1 381 err := index.Iterate(func(item Item) (stop bool, err error) { 382 if i > len(items)-1 { 383 return true, fmt.Errorf("got unexpected index item: %#v", item) 384 } 385 want := items[i] 386 checkItem(t, item, want) 387 i++ 388 return false, nil 389 }, &IterateOptions{ 390 StartFrom: &items[startIndex], 391 SkipStartFromItem: true, 392 }) 393 if err != nil { 394 t.Fatal(err) 395 } 396 }) 397 398 t.Run("stop", func(t *testing.T) { 399 var i int 400 stopIndex := 3 401 var count int 402 err := index.Iterate(func(item Item) (stop bool, err error) { 403 if i > len(items)-1 { 404 return true, fmt.Errorf("got unexpected index item: %#v", item) 405 } 406 want := items[i] 407 checkItem(t, item, want) 408 count++ 409 if i == stopIndex { 410 return true, nil 411 } 412 i++ 413 return false, nil 414 }, nil) 415 if err != nil { 416 t.Fatal(err) 417 } 418 wantItemsCount := stopIndex + 1 419 if count != wantItemsCount { 420 t.Errorf("got %v items, expected %v", count, wantItemsCount) 421 } 422 }) 423 424 t.Run("no overflow", func(t *testing.T) { 425 secondIndex, err := db.NewIndex("second-index", retrievalIndexFuncs) 426 if err != nil { 427 t.Fatal(err) 428 } 429 430 secondItem := Item{ 431 Address: []byte("iterate-hash-10"), 432 Data: []byte("data-second"), 433 } 434 err = secondIndex.Put(secondItem) 435 if err != nil { 436 t.Fatal(err) 437 } 438 439 var i int 440 err = index.Iterate(func(item Item) (stop bool, err error) { 441 if i > len(items)-1 { 442 return true, fmt.Errorf("got unexpected index item: %#v", item) 443 } 444 want := items[i] 445 checkItem(t, item, want) 446 i++ 447 return false, nil 448 }, nil) 449 if err != nil { 450 t.Fatal(err) 451 } 452 453 i = 0 454 err = secondIndex.Iterate(func(item Item) (stop bool, err error) { 455 if i > 1 { 456 return true, fmt.Errorf("got unexpected index item: %#v", item) 457 } 458 checkItem(t, item, secondItem) 459 i++ 460 return false, nil 461 }, nil) 462 if err != nil { 463 t.Fatal(err) 464 } 465 }) 466 } 467 468 // TestIndex_Iterate_withPrefix validates index Iterate 469 // function for correctness. 470 func TestIndex_Iterate_withPrefix(t *testing.T) { 471 db, cleanupFunc := newTestDB(t) 472 defer cleanupFunc() 473 474 index, err := db.NewIndex("retrieval", retrievalIndexFuncs) 475 if err != nil { 476 t.Fatal(err) 477 } 478 479 allItems := []Item{ 480 {Address: []byte("want-hash-00"), Data: []byte("data80")}, 481 {Address: []byte("skip-hash-01"), Data: []byte("data81")}, 482 {Address: []byte("skip-hash-02"), Data: []byte("data82")}, 483 {Address: []byte("skip-hash-03"), Data: []byte("data83")}, 484 {Address: []byte("want-hash-04"), Data: []byte("data84")}, 485 {Address: []byte("want-hash-05"), Data: []byte("data85")}, 486 {Address: []byte("want-hash-06"), Data: []byte("data86")}, 487 {Address: []byte("want-hash-07"), Data: []byte("data87")}, 488 {Address: []byte("want-hash-08"), Data: []byte("data88")}, 489 {Address: []byte("want-hash-09"), Data: []byte("data89")}, 490 {Address: []byte("skip-hash-10"), Data: []byte("data90")}, 491 } 492 batch := new(leveldb.Batch) 493 for _, i := range allItems { 494 index.PutInBatch(batch, i) 495 } 496 err = db.WriteBatch(batch) 497 if err != nil { 498 t.Fatal(err) 499 } 500 501 prefix := []byte("want") 502 503 items := make([]Item, 0) 504 for _, item := range allItems { 505 if bytes.HasPrefix(item.Address, prefix) { 506 items = append(items, item) 507 } 508 } 509 sort.SliceStable(items, func(i, j int) bool { 510 return bytes.Compare(items[i].Address, items[j].Address) < 0 511 }) 512 513 t.Run("with prefix", func(t *testing.T) { 514 var i int 515 err := index.Iterate(func(item Item) (stop bool, err error) { 516 if i > len(items)-1 { 517 return true, fmt.Errorf("got unexpected index item: %#v", item) 518 } 519 want := items[i] 520 checkItem(t, item, want) 521 i++ 522 return false, nil 523 }, &IterateOptions{ 524 Prefix: prefix, 525 }) 526 if err != nil { 527 t.Fatal(err) 528 } 529 if i != len(items) { 530 t.Errorf("got %v items, want %v", i, len(items)) 531 } 532 }) 533 534 t.Run("with prefix and start from", func(t *testing.T) { 535 startIndex := 2 536 var count int 537 i := startIndex 538 err := index.Iterate(func(item Item) (stop bool, err error) { 539 if i > len(items)-1 { 540 return true, fmt.Errorf("got unexpected index item: %#v", item) 541 } 542 want := items[i] 543 checkItem(t, item, want) 544 i++ 545 count++ 546 return false, nil 547 }, &IterateOptions{ 548 StartFrom: &items[startIndex], 549 Prefix: prefix, 550 }) 551 if err != nil { 552 t.Fatal(err) 553 } 554 wantCount := len(items) - startIndex 555 if count != wantCount { 556 t.Errorf("got %v items, want %v", count, wantCount) 557 } 558 }) 559 560 t.Run("with prefix and skip start from", func(t *testing.T) { 561 startIndex := 2 562 var count int 563 i := startIndex + 1 564 err := index.Iterate(func(item Item) (stop bool, err error) { 565 if i > len(items)-1 { 566 return true, fmt.Errorf("got unexpected index item: %#v", item) 567 } 568 want := items[i] 569 checkItem(t, item, want) 570 i++ 571 count++ 572 return false, nil 573 }, &IterateOptions{ 574 StartFrom: &items[startIndex], 575 SkipStartFromItem: true, 576 Prefix: prefix, 577 }) 578 if err != nil { 579 t.Fatal(err) 580 } 581 wantCount := len(items) - startIndex - 1 582 if count != wantCount { 583 t.Errorf("got %v items, want %v", count, wantCount) 584 } 585 }) 586 587 t.Run("stop", func(t *testing.T) { 588 var i int 589 stopIndex := 3 590 var count int 591 err := index.Iterate(func(item Item) (stop bool, err error) { 592 if i > len(items)-1 { 593 return true, fmt.Errorf("got unexpected index item: %#v", item) 594 } 595 want := items[i] 596 checkItem(t, item, want) 597 count++ 598 if i == stopIndex { 599 return true, nil 600 } 601 i++ 602 return false, nil 603 }, &IterateOptions{ 604 Prefix: prefix, 605 }) 606 if err != nil { 607 t.Fatal(err) 608 } 609 wantItemsCount := stopIndex + 1 610 if count != wantItemsCount { 611 t.Errorf("got %v items, expected %v", count, wantItemsCount) 612 } 613 }) 614 615 t.Run("no overflow", func(t *testing.T) { 616 secondIndex, err := db.NewIndex("second-index", retrievalIndexFuncs) 617 if err != nil { 618 t.Fatal(err) 619 } 620 621 secondItem := Item{ 622 Address: []byte("iterate-hash-10"), 623 Data: []byte("data-second"), 624 } 625 err = secondIndex.Put(secondItem) 626 if err != nil { 627 t.Fatal(err) 628 } 629 630 var i int 631 err = index.Iterate(func(item Item) (stop bool, err error) { 632 if i > len(items)-1 { 633 return true, fmt.Errorf("got unexpected index item: %#v", item) 634 } 635 want := items[i] 636 checkItem(t, item, want) 637 i++ 638 return false, nil 639 }, &IterateOptions{ 640 Prefix: prefix, 641 }) 642 if err != nil { 643 t.Fatal(err) 644 } 645 if i != len(items) { 646 t.Errorf("got %v items, want %v", i, len(items)) 647 } 648 }) 649 } 650 651 // TestIndex_count tests if Index.Count and Index.CountFrom 652 // returns the correct number of items. 653 func TestIndex_count(t *testing.T) { 654 db, cleanupFunc := newTestDB(t) 655 defer cleanupFunc() 656 657 index, err := db.NewIndex("retrieval", retrievalIndexFuncs) 658 if err != nil { 659 t.Fatal(err) 660 } 661 662 items := []Item{ 663 { 664 Address: []byte("iterate-hash-01"), 665 Data: []byte("data80"), 666 }, 667 { 668 Address: []byte("iterate-hash-02"), 669 Data: []byte("data84"), 670 }, 671 { 672 Address: []byte("iterate-hash-03"), 673 Data: []byte("data22"), 674 }, 675 { 676 Address: []byte("iterate-hash-04"), 677 Data: []byte("data41"), 678 }, 679 { 680 Address: []byte("iterate-hash-05"), 681 Data: []byte("data1"), 682 }, 683 } 684 batch := new(leveldb.Batch) 685 for _, i := range items { 686 index.PutInBatch(batch, i) 687 } 688 err = db.WriteBatch(batch) 689 if err != nil { 690 t.Fatal(err) 691 } 692 693 t.Run("Count", func(t *testing.T) { 694 got, err := index.Count() 695 if err != nil { 696 t.Fatal(err) 697 } 698 699 want := len(items) 700 if got != want { 701 t.Errorf("got %v items count, want %v", got, want) 702 } 703 }) 704 705 t.Run("CountFrom", func(t *testing.T) { 706 got, err := index.CountFrom(Item{ 707 Address: items[1].Address, 708 }) 709 if err != nil { 710 t.Fatal(err) 711 } 712 713 want := len(items) - 1 714 if got != want { 715 t.Errorf("got %v items count, want %v", got, want) 716 } 717 }) 718 719 // update the index with another item 720 t.Run("add item", func(t *testing.T) { 721 item04 := Item{ 722 Address: []byte("iterate-hash-06"), 723 Data: []byte("data0"), 724 } 725 err = index.Put(item04) 726 if err != nil { 727 t.Fatal(err) 728 } 729 730 count := len(items) + 1 731 732 t.Run("Count", func(t *testing.T) { 733 got, err := index.Count() 734 if err != nil { 735 t.Fatal(err) 736 } 737 738 want := count 739 if got != want { 740 t.Errorf("got %v items count, want %v", got, want) 741 } 742 }) 743 744 t.Run("CountFrom", func(t *testing.T) { 745 got, err := index.CountFrom(Item{ 746 Address: items[1].Address, 747 }) 748 if err != nil { 749 t.Fatal(err) 750 } 751 752 want := count - 1 753 if got != want { 754 t.Errorf("got %v items count, want %v", got, want) 755 } 756 }) 757 }) 758 759 // delete some items 760 t.Run("delete items", func(t *testing.T) { 761 deleteCount := 3 762 763 for _, item := range items[:deleteCount] { 764 err := index.Delete(item) 765 if err != nil { 766 t.Fatal(err) 767 } 768 } 769 770 count := len(items) + 1 - deleteCount 771 772 t.Run("Count", func(t *testing.T) { 773 got, err := index.Count() 774 if err != nil { 775 t.Fatal(err) 776 } 777 778 want := count 779 if got != want { 780 t.Errorf("got %v items count, want %v", got, want) 781 } 782 }) 783 784 t.Run("CountFrom", func(t *testing.T) { 785 got, err := index.CountFrom(Item{ 786 Address: items[deleteCount+1].Address, 787 }) 788 if err != nil { 789 t.Fatal(err) 790 } 791 792 want := count - 1 793 if got != want { 794 t.Errorf("got %v items count, want %v", got, want) 795 } 796 }) 797 }) 798 } 799 800 // checkItem is a test helper function that compares if two Index items are the same. 801 func checkItem(t *testing.T, got, want Item) { 802 t.Helper() 803 804 if !bytes.Equal(got.Address, want.Address) { 805 t.Errorf("got hash %q, expected %q", string(got.Address), string(want.Address)) 806 } 807 if !bytes.Equal(got.Data, want.Data) { 808 t.Errorf("got data %q, expected %q", string(got.Data), string(want.Data)) 809 } 810 if got.StoreTimestamp != want.StoreTimestamp { 811 t.Errorf("got store timestamp %v, expected %v", got.StoreTimestamp, want.StoreTimestamp) 812 } 813 if got.AccessTimestamp != want.AccessTimestamp { 814 t.Errorf("got access timestamp %v, expected %v", got.AccessTimestamp, want.AccessTimestamp) 815 } 816 } 817 818 // TestIndex_firstAndLast validates that index First and Last methods 819 // are returning expected results based on the provided prefix. 820 func TestIndex_firstAndLast(t *testing.T) { 821 db, cleanupFunc := newTestDB(t) 822 defer cleanupFunc() 823 824 index, err := db.NewIndex("retrieval", retrievalIndexFuncs) 825 if err != nil { 826 t.Fatal(err) 827 } 828 829 addrs := [][]byte{ 830 {0, 0, 0, 0, 0}, 831 {0, 1}, 832 {0, 1, 0, 0, 0}, 833 {0, 1, 0, 0, 1}, 834 {0, 1, 0, 0, 2}, 835 {0, 2, 0, 0, 1}, 836 {0, 4, 0, 0, 0}, 837 {0, 10, 0, 0, 10}, 838 {0, 10, 0, 0, 11}, 839 {0, 10, 0, 0, 20}, 840 {1, 32, 255, 0, 1}, 841 {1, 32, 255, 0, 2}, 842 {1, 32, 255, 0, 3}, 843 {255, 255, 255, 255, 32}, 844 {255, 255, 255, 255, 64}, 845 {255, 255, 255, 255, 255}, 846 } 847 848 // ensure that the addresses are sorted for 849 // validation of nil prefix 850 sort.Slice(addrs, func(i, j int) (less bool) { 851 return bytes.Compare(addrs[i], addrs[j]) == -1 852 }) 853 854 batch := new(leveldb.Batch) 855 for _, addr := range addrs { 856 index.PutInBatch(batch, Item{ 857 Address: addr, 858 }) 859 } 860 err = db.WriteBatch(batch) 861 if err != nil { 862 t.Fatal(err) 863 } 864 865 for _, tc := range []struct { 866 prefix []byte 867 first []byte 868 last []byte 869 err error 870 }{ 871 { 872 prefix: nil, 873 first: addrs[0], 874 last: addrs[len(addrs)-1], 875 }, 876 { 877 prefix: []byte{0, 0}, 878 first: []byte{0, 0, 0, 0, 0}, 879 last: []byte{0, 0, 0, 0, 0}, 880 }, 881 { 882 prefix: []byte{0}, 883 first: []byte{0, 0, 0, 0, 0}, 884 last: []byte{0, 10, 0, 0, 20}, 885 }, 886 { 887 prefix: []byte{0, 1}, 888 first: []byte{0, 1}, 889 last: []byte{0, 1, 0, 0, 2}, 890 }, 891 { 892 prefix: []byte{0, 10}, 893 first: []byte{0, 10, 0, 0, 10}, 894 last: []byte{0, 10, 0, 0, 20}, 895 }, 896 { 897 prefix: []byte{1, 32, 255}, 898 first: []byte{1, 32, 255, 0, 1}, 899 last: []byte{1, 32, 255, 0, 3}, 900 }, 901 { 902 prefix: []byte{255}, 903 first: []byte{255, 255, 255, 255, 32}, 904 last: []byte{255, 255, 255, 255, 255}, 905 }, 906 { 907 prefix: []byte{255, 255, 255, 255, 255}, 908 first: []byte{255, 255, 255, 255, 255}, 909 last: []byte{255, 255, 255, 255, 255}, 910 }, 911 { 912 prefix: []byte{0, 3}, 913 err: leveldb.ErrNotFound, 914 }, 915 { 916 prefix: []byte{222}, 917 err: leveldb.ErrNotFound, 918 }, 919 } { 920 got, err := index.Last(tc.prefix) 921 if tc.err != err { 922 t.Errorf("got error %v for Last with prefix %v, want %v", err, tc.prefix, tc.err) 923 } else { 924 if !bytes.Equal(got.Address, tc.last) { 925 t.Errorf("got %v for Last with prefix %v, want %v", got.Address, tc.prefix, tc.last) 926 } 927 } 928 929 got, err = index.First(tc.prefix) 930 if tc.err != err { 931 t.Errorf("got error %v for First with prefix %v, want %v", err, tc.prefix, tc.err) 932 } else { 933 if !bytes.Equal(got.Address, tc.first) { 934 t.Errorf("got %v for First with prefix %v, want %v", got.Address, tc.prefix, tc.first) 935 } 936 } 937 } 938 } 939 940 // TestIncByteSlice validates returned values of incByteSlice function. 941 func TestIncByteSlice(t *testing.T) { 942 for _, tc := range []struct { 943 b []byte 944 want []byte 945 }{ 946 {b: nil, want: nil}, 947 {b: []byte{}, want: nil}, 948 {b: []byte{0}, want: []byte{1}}, 949 {b: []byte{42}, want: []byte{43}}, 950 {b: []byte{255}, want: nil}, 951 {b: []byte{0, 0}, want: []byte{0, 1}}, 952 {b: []byte{1, 0}, want: []byte{1, 1}}, 953 {b: []byte{1, 255}, want: []byte{2, 0}}, 954 {b: []byte{255, 255}, want: nil}, 955 {b: []byte{32, 0, 255}, want: []byte{32, 1, 0}}, 956 } { 957 got := incByteSlice(tc.b) 958 if !bytes.Equal(got, tc.want) { 959 t.Errorf("got %v, want %v", got, tc.want) 960 } 961 } 962 }