1 // Copyright (c) 2013-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
12 "github.com/btcsuite/btcd/chaincfg/chainhash"
13 "github.com/btcsuite/btcd/wire"
16 // TestMruInventoryMap ensures the MruInventoryMap behaves as expected including
17 // limiting, eviction of least-recently used entries, specific entry removal,
18 // and existence tests.
19 func TestMruInventoryMap(t *testing.T) {
20 // Create a bunch of fake inventory vectors to use in testing the mru
23 invVects := make([]*wire.InvVect, 0, numInvVects)
24 for i := 0; i < numInvVects; i++ {
25 hash := &chainhash.Hash{byte(i)}
26 iv := wire.NewInvVect(wire.InvTypeBlock, hash)
27 invVects = append(invVects, iv)
34 {name: "limit 0", limit: 0},
35 {name: "limit 1", limit: 1},
36 {name: "limit 5", limit: 5},
37 {name: "limit 7", limit: 7},
38 {name: "limit one less than available", limit: numInvVects - 1},
39 {name: "limit all available", limit: numInvVects},
43 for i, test := range tests {
44 // Create a new mru inventory map limited by the specified test
45 // limit and add all of the test inventory vectors. This will
46 // cause evicition since there are more test inventory vectors
48 mruInvMap := newMruInventoryMap(uint(test.limit))
49 for j := 0; j < numInvVects; j++ {
50 mruInvMap.Add(invVects[j])
53 // Ensure the limited number of most recent entries in the
54 // inventory vector list exist.
55 for j := numInvVects - test.limit; j < numInvVects; j++ {
56 if !mruInvMap.Exists(invVects[j]) {
57 t.Errorf("Exists #%d (%s) entry %s does not "+
58 "exist", i, test.name, *invVects[j])
63 // Ensure the entries before the limited number of most recent
64 // entries in the inventory vector list do not exist.
65 for j := 0; j < numInvVects-test.limit; j++ {
66 if mruInvMap.Exists(invVects[j]) {
67 t.Errorf("Exists #%d (%s) entry %s exists", i,
68 test.name, *invVects[j])
73 // Readd the entry that should currently be the least-recently
74 // used entry so it becomes the most-recently used entry, then
75 // force an eviction by adding an entry that doesn't exist and
76 // ensure the evicted entry is the new least-recently used
79 // This check needs at least 2 entries.
81 origLruIndex := numInvVects - test.limit
82 mruInvMap.Add(invVects[origLruIndex])
84 iv := wire.NewInvVect(wire.InvTypeBlock,
85 &chainhash.Hash{0x00, 0x01})
88 // Ensure the original lru entry still exists since it
89 // was updated and should've have become the mru entry.
90 if !mruInvMap.Exists(invVects[origLruIndex]) {
91 t.Errorf("MRU #%d (%s) entry %s does not exist",
92 i, test.name, *invVects[origLruIndex])
96 // Ensure the entry that should've become the new lru
98 newLruIndex := origLruIndex + 1
99 if mruInvMap.Exists(invVects[newLruIndex]) {
100 t.Errorf("MRU #%d (%s) entry %s exists", i,
101 test.name, *invVects[newLruIndex])
106 // Delete all of the entries in the inventory vector list,
107 // including those that don't exist in the map, and ensure they
109 for j := 0; j < numInvVects; j++ {
110 mruInvMap.Delete(invVects[j])
111 if mruInvMap.Exists(invVects[j]) {
112 t.Errorf("Delete #%d (%s) entry %s exists", i,
113 test.name, *invVects[j])
120 // TestMruInventoryMapStringer tests the stringized output for the
121 // MruInventoryMap type.
122 func TestMruInventoryMapStringer(t *testing.T) {
123 // Create a couple of fake inventory vectors to use in testing the mru
124 // inventory stringer code.
125 hash1 := &chainhash.Hash{0x01}
126 hash2 := &chainhash.Hash{0x02}
127 iv1 := wire.NewInvVect(wire.InvTypeBlock, hash1)
128 iv2 := wire.NewInvVect(wire.InvTypeBlock, hash2)
130 // Create new mru inventory map and add the inventory vectors.
131 mruInvMap := newMruInventoryMap(uint(2))
135 // Ensure the stringer gives the expected result. Since map iteration
136 // is not ordered, either entry could be first, so account for both
138 wantStr1 := fmt.Sprintf("<%d>[%s, %s]", 2, *iv1, *iv2)
139 wantStr2 := fmt.Sprintf("<%d>[%s, %s]", 2, *iv2, *iv1)
140 gotStr := mruInvMap.String()
141 if gotStr != wantStr1 && gotStr != wantStr2 {
142 t.Fatalf("unexpected string representation - got %q, want %q "+
143 "or %q", gotStr, wantStr1, wantStr2)
147 // BenchmarkMruInventoryList performs basic benchmarks on the most recently
148 // used inventory handling.
149 func BenchmarkMruInventoryList(b *testing.B) {
150 // Create a bunch of fake inventory vectors to use in benchmarking
151 // the mru inventory code.
153 numInvVects := 100000
154 invVects := make([]*wire.InvVect, 0, numInvVects)
155 for i := 0; i < numInvVects; i++ {
156 hashBytes := make([]byte, chainhash.HashSize)
158 hash, _ := chainhash.NewHash(hashBytes)
159 iv := wire.NewInvVect(wire.InvTypeBlock, hash)
160 invVects = append(invVects, iv)
164 // Benchmark the add plus evicition code.
166 mruInvMap := newMruInventoryMap(uint(limit))
167 for i := 0; i < b.N; i++ {
168 mruInvMap.Add(invVects[i%numInvVects])