vitess.io/vitess@v0.16.2/go/cache/lru_cache_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cache 18 19 import ( 20 "testing" 21 ) 22 23 type CacheValue struct { 24 size int64 25 } 26 27 func cacheValueSize(val any) int64 { 28 return val.(*CacheValue).size 29 } 30 31 func TestInitialState(t *testing.T) { 32 cache := NewLRUCache(5, cacheValueSize) 33 l, sz, c, e, h, m := cache.Len(), cache.UsedCapacity(), cache.MaxCapacity(), cache.Evictions(), cache.Hits(), cache.Misses() 34 if l != 0 { 35 t.Errorf("length = %v, want 0", l) 36 } 37 if sz != 0 { 38 t.Errorf("size = %v, want 0", sz) 39 } 40 if c != 5 { 41 t.Errorf("capacity = %v, want 5", c) 42 } 43 if e != 0 { 44 t.Errorf("evictions = %v, want 0", c) 45 } 46 if h != 0 { 47 t.Errorf("hits = %v, want 0", c) 48 } 49 if m != 0 { 50 t.Errorf("misses = %v, want 0", c) 51 } 52 } 53 54 func TestSetInsertsValue(t *testing.T) { 55 cache := NewLRUCache(100, cacheValueSize) 56 data := &CacheValue{0} 57 key := "key" 58 cache.Set(key, data) 59 60 v, ok := cache.Get(key) 61 if !ok || v.(*CacheValue) != data { 62 t.Errorf("Cache has incorrect value: %v != %v", data, v) 63 } 64 65 values := cache.Items() 66 if len(values) != 1 || values[0].Key != key { 67 t.Errorf("Cache.Values() returned incorrect values: %v", values) 68 } 69 } 70 71 func TestGetValueWithMultipleTypes(t *testing.T) { 72 cache := NewLRUCache(100, cacheValueSize) 73 data := &CacheValue{0} 74 key := "key" 75 cache.Set(key, data) 76 77 v, ok := cache.Get("key") 78 if !ok || v.(*CacheValue) != data { 79 t.Errorf("Cache has incorrect value for \"key\": %v != %v", data, v) 80 } 81 82 v, ok = cache.Get(string([]byte{'k', 'e', 'y'})) 83 if !ok || v.(*CacheValue) != data { 84 t.Errorf("Cache has incorrect value for []byte {'k','e','y'}: %v != %v", data, v) 85 } 86 } 87 88 func TestSetUpdatesSize(t *testing.T) { 89 cache := NewLRUCache(100, cacheValueSize) 90 emptyValue := &CacheValue{0} 91 key := "key1" 92 cache.Set(key, emptyValue) 93 if sz := cache.UsedCapacity(); sz != 0 { 94 t.Errorf("cache.UsedCapacity() = %v, expected 0", sz) 95 } 96 someValue := &CacheValue{20} 97 key = "key2" 98 cache.Set(key, someValue) 99 if sz := cache.UsedCapacity(); sz != 20 { 100 t.Errorf("cache.UsedCapacity() = %v, expected 20", sz) 101 } 102 } 103 104 func TestSetWithOldKeyUpdatesValue(t *testing.T) { 105 cache := NewLRUCache(100, cacheValueSize) 106 emptyValue := &CacheValue{0} 107 key := "key1" 108 cache.Set(key, emptyValue) 109 someValue := &CacheValue{20} 110 cache.Set(key, someValue) 111 112 v, ok := cache.Get(key) 113 if !ok || v.(*CacheValue) != someValue { 114 t.Errorf("Cache has incorrect value: %v != %v", someValue, v) 115 } 116 } 117 118 func TestSetWithOldKeyUpdatesSize(t *testing.T) { 119 cache := NewLRUCache(100, cacheValueSize) 120 emptyValue := &CacheValue{0} 121 key := "key1" 122 cache.Set(key, emptyValue) 123 124 if sz := cache.UsedCapacity(); sz != 0 { 125 t.Errorf("cache.UsedCapacity() = %v, expected %v", sz, 0) 126 } 127 128 someValue := &CacheValue{20} 129 cache.Set(key, someValue) 130 expected := int64(someValue.size) 131 if sz := cache.UsedCapacity(); sz != expected { 132 t.Errorf("cache.UsedCapacity() = %v, expected %v", sz, expected) 133 } 134 } 135 136 func TestGetNonExistent(t *testing.T) { 137 cache := NewLRUCache(100, cacheValueSize) 138 139 if _, ok := cache.Get("notthere"); ok { 140 t.Error("Cache returned a notthere value after no inserts.") 141 } 142 } 143 144 func TestDelete(t *testing.T) { 145 cache := NewLRUCache(100, cacheValueSize) 146 value := &CacheValue{1} 147 key := "key" 148 149 cache.Delete(key) 150 cache.Set(key, value) 151 cache.Delete(key) 152 153 if sz := cache.UsedCapacity(); sz != 0 { 154 t.Errorf("cache.UsedCapacity() = %v, expected 0", sz) 155 } 156 157 if _, ok := cache.Get(key); ok { 158 t.Error("Cache returned a value after deletion.") 159 } 160 } 161 162 func TestClear(t *testing.T) { 163 cache := NewLRUCache(100, cacheValueSize) 164 value := &CacheValue{1} 165 key := "key" 166 167 cache.Set(key, value) 168 cache.Clear() 169 170 if sz := cache.UsedCapacity(); sz != 0 { 171 t.Errorf("cache.UsedCapacity() = %v, expected 0 after Clear()", sz) 172 } 173 } 174 175 func TestCapacityIsObeyed(t *testing.T) { 176 size := int64(3) 177 cache := NewLRUCache(100, cacheValueSize) 178 cache.SetCapacity(size) 179 value := &CacheValue{1} 180 181 // Insert up to the cache's capacity. 182 cache.Set("key1", value) 183 cache.Set("key2", value) 184 cache.Set("key3", value) 185 if sz := cache.UsedCapacity(); sz != size { 186 t.Errorf("cache.UsedCapacity() = %v, expected %v", sz, size) 187 } 188 // Insert one more; something should be evicted to make room. 189 cache.Set("key4", value) 190 sz, evictions := cache.UsedCapacity(), cache.Evictions() 191 if sz != size { 192 t.Errorf("post-evict cache.UsedCapacity() = %v, expected %v", sz, size) 193 } 194 if evictions != 1 { 195 t.Errorf("post-evict cache.Evictions() = %v, expected 1", evictions) 196 } 197 198 // Check various other stats 199 if l := cache.Len(); int64(l) != size { 200 t.Errorf("cache.Len() returned bad length: %v", l) 201 } 202 if s := cache.UsedCapacity(); s != size { 203 t.Errorf("cache.UsedCapacity() returned bad size: %v", s) 204 } 205 if c := cache.MaxCapacity(); c != size { 206 t.Errorf("cache.UsedCapacity() returned bad length: %v", c) 207 } 208 if c := cache.Hits(); c != 0 { 209 t.Errorf("cache.Hits() returned hits when there should be none: %v", c) 210 } 211 if c := cache.Misses(); c != 0 { 212 t.Errorf("cache.Misses() returned misses when there should be none: %v", c) 213 } 214 } 215 216 func TestLRUIsEvicted(t *testing.T) { 217 size := int64(3) 218 cache := NewLRUCache(size, cacheValueSize) 219 220 cache.Set("key1", &CacheValue{1}) 221 cache.Set("key2", &CacheValue{1}) 222 cache.Set("key3", &CacheValue{1}) 223 // lru: [key3, key2, key1] 224 225 // Look up the elements. This will rearrange the LRU ordering. 226 cache.Get("key3") 227 cache.Get("key2") 228 cache.Get("key1") 229 // lru: [key1, key2, key3] 230 231 cache.Set("key0", &CacheValue{1}) 232 // lru: [key0, key1, key2] 233 234 // The least recently used one should have been evicted. 235 if _, ok := cache.Get("key3"); ok { 236 t.Error("Least recently used element was not evicted.") 237 } 238 239 if e, want := cache.Evictions(), int64(1); e != want { 240 t.Errorf("evictions: %d, want: %d", e, want) 241 } 242 243 if h, want := cache.Hits(), int64(3); h != want { 244 t.Errorf("hits: %d, want: %d", h, want) 245 } 246 247 if m, want := cache.Misses(), int64(1); m != want { 248 t.Errorf("misses: %d, want: %d", m, want) 249 } 250 }