github.com/jimmyx0x/go-ethereum@v1.10.28/common/lru/basiclru_test.go (about) 1 // Copyright 2022 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 lru 18 19 import ( 20 "fmt" 21 "io" 22 "math/rand" 23 "testing" 24 ) 25 26 // Some of these test cases were adapted 27 // from https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru_test.go 28 29 func TestBasicLRU(t *testing.T) { 30 cache := NewBasicLRU[int, int](128) 31 32 for i := 0; i < 256; i++ { 33 cache.Add(i, i) 34 } 35 if cache.Len() != 128 { 36 t.Fatalf("bad len: %v", cache.Len()) 37 } 38 39 // Check that Keys returns least-recent key first. 40 keys := cache.Keys() 41 if len(keys) != 128 { 42 t.Fatal("wrong Keys() length", len(keys)) 43 } 44 for i, k := range keys { 45 v, ok := cache.Peek(k) 46 if !ok { 47 t.Fatalf("expected key %d be present", i) 48 } 49 if v != k { 50 t.Fatalf("expected %d == %d", k, v) 51 } 52 if v != i+128 { 53 t.Fatalf("wrong value at key %d: %d, want %d", i, v, i+128) 54 } 55 } 56 57 for i := 0; i < 128; i++ { 58 _, ok := cache.Get(i) 59 if ok { 60 t.Fatalf("%d should be evicted", i) 61 } 62 } 63 for i := 128; i < 256; i++ { 64 _, ok := cache.Get(i) 65 if !ok { 66 t.Fatalf("%d should not be evicted", i) 67 } 68 } 69 70 for i := 128; i < 192; i++ { 71 ok := cache.Remove(i) 72 if !ok { 73 t.Fatalf("%d should be in cache", i) 74 } 75 ok = cache.Remove(i) 76 if ok { 77 t.Fatalf("%d should not be in cache", i) 78 } 79 _, ok = cache.Get(i) 80 if ok { 81 t.Fatalf("%d should be deleted", i) 82 } 83 } 84 85 // Request item 192. 86 cache.Get(192) 87 // It should be the last item returned by Keys(). 88 for i, k := range cache.Keys() { 89 if (i < 63 && k != i+193) || (i == 63 && k != 192) { 90 t.Fatalf("out of order key: %v", k) 91 } 92 } 93 94 cache.Purge() 95 if cache.Len() != 0 { 96 t.Fatalf("bad len: %v", cache.Len()) 97 } 98 if _, ok := cache.Get(200); ok { 99 t.Fatalf("should contain nothing") 100 } 101 } 102 103 func TestBasicLRUAddExistingKey(t *testing.T) { 104 cache := NewBasicLRU[int, int](1) 105 106 cache.Add(1, 1) 107 cache.Add(1, 2) 108 109 v, _ := cache.Get(1) 110 if v != 2 { 111 t.Fatal("wrong value:", v) 112 } 113 } 114 115 // This test checks GetOldest and RemoveOldest. 116 func TestBasicLRUGetOldest(t *testing.T) { 117 cache := NewBasicLRU[int, int](128) 118 for i := 0; i < 256; i++ { 119 cache.Add(i, i) 120 } 121 122 k, _, ok := cache.GetOldest() 123 if !ok { 124 t.Fatalf("missing") 125 } 126 if k != 128 { 127 t.Fatalf("bad: %v", k) 128 } 129 130 k, _, ok = cache.RemoveOldest() 131 if !ok { 132 t.Fatalf("missing") 133 } 134 if k != 128 { 135 t.Fatalf("bad: %v", k) 136 } 137 138 k, _, ok = cache.RemoveOldest() 139 if !ok { 140 t.Fatalf("missing oldest item") 141 } 142 if k != 129 { 143 t.Fatalf("wrong oldest item: %v", k) 144 } 145 } 146 147 // Test that Add returns true/false if an eviction occurred 148 func TestBasicLRUAddReturnValue(t *testing.T) { 149 cache := NewBasicLRU[int, int](1) 150 if cache.Add(1, 1) { 151 t.Errorf("first add shouldn't have evicted") 152 } 153 if !cache.Add(2, 2) { 154 t.Errorf("second add should have evicted") 155 } 156 } 157 158 // This test verifies that Contains doesn't change item recency. 159 func TestBasicLRUContains(t *testing.T) { 160 cache := NewBasicLRU[int, int](2) 161 cache.Add(1, 1) 162 cache.Add(2, 2) 163 if !cache.Contains(1) { 164 t.Errorf("1 should be in the cache") 165 } 166 cache.Add(3, 3) 167 if cache.Contains(1) { 168 t.Errorf("Contains should not have updated recency of 1") 169 } 170 } 171 172 func BenchmarkLRU(b *testing.B) { 173 var ( 174 capacity = 1000 175 indexes = make([]int, capacity*20) 176 keys = make([]string, capacity) 177 values = make([][]byte, capacity) 178 ) 179 for i := range indexes { 180 indexes[i] = rand.Intn(capacity) 181 } 182 for i := range keys { 183 b := make([]byte, 32) 184 rand.Read(b) 185 keys[i] = string(b) 186 rand.Read(b) 187 values[i] = b 188 } 189 190 var sink []byte 191 192 b.Run("Add/BasicLRU", func(b *testing.B) { 193 cache := NewBasicLRU[int, int](capacity) 194 for i := 0; i < b.N; i++ { 195 cache.Add(i, i) 196 } 197 }) 198 b.Run("Get/BasicLRU", func(b *testing.B) { 199 cache := NewBasicLRU[string, []byte](capacity) 200 for i := 0; i < capacity; i++ { 201 index := indexes[i] 202 cache.Add(keys[index], values[index]) 203 } 204 205 b.ResetTimer() 206 for i := 0; i < b.N; i++ { 207 k := keys[indexes[i%len(indexes)]] 208 v, ok := cache.Get(k) 209 if ok { 210 sink = v 211 } 212 } 213 }) 214 215 // // vs. github.com/hashicorp/golang-lru/simplelru 216 // b.Run("Add/simplelru.LRU", func(b *testing.B) { 217 // cache, _ := simplelru.NewLRU(capacity, nil) 218 // for i := 0; i < b.N; i++ { 219 // cache.Add(i, i) 220 // } 221 // }) 222 // b.Run("Get/simplelru.LRU", func(b *testing.B) { 223 // cache, _ := simplelru.NewLRU(capacity, nil) 224 // for i := 0; i < capacity; i++ { 225 // index := indexes[i] 226 // cache.Add(keys[index], values[index]) 227 // } 228 // 229 // b.ResetTimer() 230 // for i := 0; i < b.N; i++ { 231 // k := keys[indexes[i%len(indexes)]] 232 // v, ok := cache.Get(k) 233 // if ok { 234 // sink = v.([]byte) 235 // } 236 // } 237 // }) 238 239 fmt.Fprintln(io.Discard, sink) 240 }