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  }