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  }