github.com/dubbogo/gost@v1.14.0/container/gxlru/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 /* 18 * Licensed to the Apache Software Foundation (ASF) under one or more 19 * contributor license agreements. See the NOTICE file distributed with 20 * this work for additional information regarding copyright ownership. 21 * The ASF licenses this file to You under the Apache License, Version 2.0 22 * (the "License"); you may not use this file except in compliance with 23 * the License. You may obtain a copy of the License at 24 * 25 * http://www.apache.org/licenses/LICENSE-2.0 26 * 27 * Unless required by applicable law or agreed to in writing, software 28 * distributed under the License is distributed on an "AS IS" BASIS, 29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 * See the License for the specific language governing permissions and 31 * limitations under the License. 32 */ 33 34 package gxlru 35 36 import ( 37 "encoding/json" 38 "testing" 39 "time" 40 ) 41 42 type CacheValue struct { 43 size int 44 } 45 46 func (cv *CacheValue) Size() int { 47 return cv.size 48 } 49 50 func TestInitialState(t *testing.T) { 51 cache := NewLRUCache(5) 52 l, sz, c, e, _ := cache.Stats() 53 if l != 0 { 54 t.Errorf("length = %v, want 0", l) 55 } 56 if sz != 0 { 57 t.Errorf("size = %v, want 0", sz) 58 } 59 if c != 5 { 60 t.Errorf("capacity = %v, want 5", c) 61 } 62 if e != 0 { 63 t.Errorf("evictions = %v, want 0", c) 64 } 65 } 66 67 func TestSetInsertsValue(t *testing.T) { 68 cache := NewLRUCache(100) 69 data := &CacheValue{0} 70 key := "key" 71 cache.Set(key, data) 72 73 v, ok := cache.Get(key) 74 if !ok || v.(*CacheValue) != data { 75 t.Errorf("Cache has incorrect value: %v != %v", data, v) 76 } 77 78 k := cache.Keys() 79 if len(k) != 1 || k[0] != key { 80 t.Errorf("Cache.Keys() returned incorrect values: %v", k) 81 } 82 values := cache.Items() 83 if len(values) != 1 || values[0].Key != key { 84 t.Errorf("Cache.Values() returned incorrect values: %v", values) 85 } 86 } 87 88 func TestSetIfAbsent(t *testing.T) { 89 cache := NewLRUCache(100) 90 data := &CacheValue{0} 91 key := "key" 92 cache.SetIfAbsent(key, data) 93 94 v, ok := cache.Get(key) 95 if !ok || v.(*CacheValue) != data { 96 t.Errorf("Cache has incorrect value: %v != %v", data, v) 97 } 98 99 cache.SetIfAbsent(key, &CacheValue{1}) 100 101 v, ok = cache.Get(key) 102 if !ok || v.(*CacheValue) != data { 103 t.Errorf("Cache has incorrect value: %v != %v", data, v) 104 } 105 } 106 107 func TestGetValueWithMultipleTypes(t *testing.T) { 108 cache := NewLRUCache(100) 109 data := &CacheValue{0} 110 key := "key" 111 cache.Set(key, data) 112 113 v, ok := cache.Get("key") 114 if !ok || v.(*CacheValue) != data { 115 t.Errorf("Cache has incorrect value for \"key\": %v != %v", data, v) 116 } 117 118 v, ok = cache.Get(string([]byte{'k', 'e', 'y'})) 119 if !ok || v.(*CacheValue) != data { 120 t.Errorf("Cache has incorrect value for []byte {'k','e','y'}: %v != %v", data, v) 121 } 122 } 123 124 func TestSetUpdatesSize(t *testing.T) { 125 cache := NewLRUCache(100) 126 emptyValue := &CacheValue{0} 127 key := "key1" 128 cache.Set(key, emptyValue) 129 if _, sz, _, _, _ := cache.Stats(); sz != 0 { 130 t.Errorf("cache.Size() = %v, expected 0", sz) 131 } 132 someValue := &CacheValue{20} 133 key = "key2" 134 cache.Set(key, someValue) 135 if _, sz, _, _, _ := cache.Stats(); sz != 20 { 136 t.Errorf("cache.Size() = %v, expected 20", sz) 137 } 138 } 139 140 func TestSetWithOldKeyUpdatesValue(t *testing.T) { 141 cache := NewLRUCache(100) 142 emptyValue := &CacheValue{0} 143 key := "key1" 144 cache.Set(key, emptyValue) 145 someValue := &CacheValue{20} 146 cache.Set(key, someValue) 147 148 v, ok := cache.Get(key) 149 if !ok || v.(*CacheValue) != someValue { 150 t.Errorf("Cache has incorrect value: %v != %v", someValue, v) 151 } 152 } 153 154 func TestSetWithOldKeyUpdatesSize(t *testing.T) { 155 cache := NewLRUCache(100) 156 emptyValue := &CacheValue{0} 157 key := "key1" 158 cache.Set(key, emptyValue) 159 160 if _, sz, _, _, _ := cache.Stats(); sz != 0 { 161 t.Errorf("cache.Size() = %v, expected %v", sz, 0) 162 } 163 164 someValue := &CacheValue{20} 165 cache.Set(key, someValue) 166 expected := int64(someValue.size) 167 if _, sz, _, _, _ := cache.Stats(); sz != expected { 168 t.Errorf("cache.Size() = %v, expected %v", sz, expected) 169 } 170 } 171 172 func TestGetNonExistent(t *testing.T) { 173 cache := NewLRUCache(100) 174 175 if _, ok := cache.Get("notthere"); ok { 176 t.Error("Cache returned a notthere value after no inserts.") 177 } 178 } 179 180 func TestPeek(t *testing.T) { 181 cache := NewLRUCache(2) 182 val1 := &CacheValue{1} 183 cache.Set("key1", val1) 184 val2 := &CacheValue{1} 185 cache.Set("key2", val2) 186 // Make key1 the most recent. 187 cache.Get("key1") 188 // Peek key2. 189 if v, ok := cache.Peek("key2"); ok && v.(*CacheValue) != val2 { 190 t.Errorf("key2 received: %v, want %v", v, val2) 191 } 192 // Push key2 out 193 cache.Set("key3", &CacheValue{1}) 194 if v, ok := cache.Peek("key2"); ok { 195 t.Errorf("key2 received: %v, want absent", v) 196 } 197 } 198 199 func TestDelete(t *testing.T) { 200 cache := NewLRUCache(100) 201 value := &CacheValue{1} 202 key := "key" 203 204 if cache.Delete(key) { 205 t.Error("Item unexpectedly already in cache.") 206 } 207 208 cache.Set(key, value) 209 210 if !cache.Delete(key) { 211 t.Error("Expected item to be in cache.") 212 } 213 214 if _, sz, _, _, _ := cache.Stats(); sz != 0 { 215 t.Errorf("cache.Size() = %v, expected 0", sz) 216 } 217 218 if _, ok := cache.Get(key); ok { 219 t.Error("Cache returned a value after deletion.") 220 } 221 } 222 223 func TestClear(t *testing.T) { 224 cache := NewLRUCache(100) 225 value := &CacheValue{1} 226 key := "key" 227 228 cache.Set(key, value) 229 cache.Clear() 230 231 if _, sz, _, _, _ := cache.Stats(); sz != 0 { 232 t.Errorf("cache.Size() = %v, expected 0 after Clear()", sz) 233 } 234 } 235 236 func TestCapacityIsObeyed(t *testing.T) { 237 size := int64(3) 238 cache := NewLRUCache(100) 239 cache.SetCapacity(size) 240 value := &CacheValue{1} 241 242 // Insert up to the cache's capacity. 243 cache.Set("key1", value) 244 cache.Set("key2", value) 245 cache.Set("key3", value) 246 if _, sz, _, _, _ := cache.Stats(); sz != size { 247 t.Errorf("cache.Size() = %v, expected %v", sz, size) 248 } 249 // Insert one more; something should be evicted to make room. 250 cache.Set("key4", value) 251 _, sz, _, evictions, _ := cache.Stats() 252 if sz != size { 253 t.Errorf("post-evict cache.Size() = %v, expected %v", sz, size) 254 } 255 if evictions != 1 { 256 t.Errorf("post-evict cache.evictions = %v, expected 1", evictions) 257 } 258 259 // Check json stats 260 data := cache.StatsJSON() 261 m := make(map[string]interface{}) 262 if err := json.Unmarshal([]byte(data), &m); err != nil { 263 t.Errorf("cache.StatsJSON() returned bad json data: %v %v", data, err) 264 } 265 if m["Size"].(float64) != float64(size) { 266 t.Errorf("cache.StatsJSON() returned bad size: %v", m) 267 } 268 269 // Check various other stats 270 if l := cache.Length(); l != size { 271 t.Errorf("cache.StatsJSON() returned bad length: %v", l) 272 } 273 if s := cache.Size(); s != size { 274 t.Errorf("cache.StatsJSON() returned bad size: %v", s) 275 } 276 if c := cache.Capacity(); c != size { 277 t.Errorf("cache.StatsJSON() returned bad length: %v", c) 278 } 279 280 // checks StatsJSON on nil 281 cache = nil 282 if s := cache.StatsJSON(); s != "{}" { 283 t.Errorf("cache.StatsJSON() on nil object returned %v", s) 284 } 285 } 286 287 func TestLRUIsEvicted(t *testing.T) { 288 size := int64(3) 289 cache := NewLRUCache(size) 290 291 cache.Set("key1", &CacheValue{1}) 292 cache.Set("key2", &CacheValue{1}) 293 cache.Set("key3", &CacheValue{1}) 294 // lru: [key3, key2, key1] 295 296 // Look up the elements. This will rearrange the LRU ordering. 297 cache.Get("key3") 298 beforeKey2 := time.Now() 299 cache.Get("key2") 300 afterKey2 := time.Now() 301 cache.Get("key1") 302 // lru: [key1, key2, key3] 303 304 cache.Set("key0", &CacheValue{1}) 305 // lru: [key0, key1, key2] 306 307 // The least recently used one should have been evicted. 308 if _, ok := cache.Get("key3"); ok { 309 t.Error("Least recently used element was not evicted.") 310 } 311 312 // Check oldest 313 if o := cache.Oldest(); o.Before(beforeKey2) || o.After(afterKey2) { 314 t.Errorf("cache.Oldest returned an unexpected value: got %v, expected a value between %v and %v", o, beforeKey2, afterKey2) 315 } 316 317 if e, want := cache.Evictions(), int64(1); e != want { 318 t.Errorf("evictions: %d, want: %d", e, want) 319 } 320 }