go.uber.org/cadence@v1.2.9/internal/common/cache/lru_test.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package cache
    22  
    23  import (
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  )
    30  
    31  func TestLRU(t *testing.T) {
    32  	cache := NewLRU(5)
    33  
    34  	cache.Put("A", "Foo")
    35  	assert.Equal(t, "Foo", cache.Get("A"))
    36  	assert.Nil(t, cache.Get("B"))
    37  	assert.Equal(t, 1, cache.Size())
    38  
    39  	cache.Put("B", "Bar")
    40  	cache.Put("C", "Cid")
    41  	cache.Put("D", "Delt")
    42  	assert.Equal(t, 4, cache.Size())
    43  
    44  	assert.Equal(t, "Bar", cache.Get("B"))
    45  	assert.Equal(t, "Cid", cache.Get("C"))
    46  	assert.Equal(t, "Delt", cache.Get("D"))
    47  
    48  	cache.Put("A", "Foo2")
    49  	assert.Equal(t, "Foo2", cache.Get("A"))
    50  
    51  	cache.Put("E", "Epsi")
    52  	assert.Equal(t, "Epsi", cache.Get("E"))
    53  	assert.Equal(t, "Foo2", cache.Get("A"))
    54  	assert.Nil(t, cache.Get("B")) // Oldest, should be evicted
    55  
    56  	// Access C, D is now LRU
    57  	cache.Get("C")
    58  	cache.Put("F", "Felp")
    59  	assert.Nil(t, cache.Get("D"))
    60  
    61  	cache.Delete("A")
    62  	assert.Nil(t, cache.Get("A"))
    63  }
    64  
    65  func TestLRUWithTTL(t *testing.T) {
    66  	cache := New(5, &Options{
    67  		TTL: time.Millisecond * 100,
    68  	}).(*lru)
    69  
    70  	// We will capture this in the caches now function, and advance time as needed
    71  	currentTime := time.UnixMilli(0)
    72  	cache.now = func() time.Time { return currentTime }
    73  
    74  	cache.Put("A", "foo")
    75  	assert.Equal(t, "foo", cache.Get("A"))
    76  
    77  	currentTime = currentTime.Add(time.Millisecond * 300)
    78  
    79  	assert.Nil(t, cache.Get("A"))
    80  	assert.Equal(t, 0, cache.Size())
    81  }
    82  
    83  func TestLRUCacheConcurrentAccess(t *testing.T) {
    84  	cache := NewLRU(5)
    85  	values := map[string]string{
    86  		"A": "foo",
    87  		"B": "bar",
    88  		"C": "zed",
    89  		"D": "dank",
    90  		"E": "ezpz",
    91  	}
    92  
    93  	for k, v := range values {
    94  		cache.Put(k, v)
    95  	}
    96  
    97  	start := make(chan struct{})
    98  	var wg sync.WaitGroup
    99  	for i := 0; i < 20; i++ {
   100  		wg.Add(1)
   101  
   102  		go func() {
   103  			defer wg.Done()
   104  
   105  			<-start
   106  
   107  			for j := 0; j < 1000; j++ {
   108  				cache.Get("A")
   109  			}
   110  		}()
   111  	}
   112  
   113  	close(start)
   114  	wg.Wait()
   115  }
   116  
   117  func TestRemoveFunc(t *testing.T) {
   118  	ch := make(chan bool)
   119  	cache := New(5, &Options{
   120  		RemovedFunc: func(i interface{}) {
   121  			_, ok := i.(*testing.T)
   122  			assert.True(t, ok)
   123  			ch <- true
   124  		},
   125  	})
   126  
   127  	cache.Put("testing", t)
   128  	cache.Delete("testing")
   129  	assert.Nil(t, cache.Get("testing"))
   130  
   131  	timeout := time.NewTimer(time.Millisecond * 300)
   132  	select {
   133  	case b := <-ch:
   134  		assert.True(t, b)
   135  	case <-timeout.C:
   136  		t.Error("RemovedFunc did not send true on channel ch")
   137  	}
   138  }
   139  
   140  func TestRemovedFuncWithTTL(t *testing.T) {
   141  	ch := make(chan bool)
   142  	cache := New(5, &Options{
   143  		TTL: time.Millisecond * 50,
   144  		RemovedFunc: func(i interface{}) {
   145  			_, ok := i.(*testing.T)
   146  			assert.True(t, ok)
   147  			ch <- true
   148  		},
   149  	}).(*lru)
   150  
   151  	// We will capture this in the caches now function, and advance time as needed
   152  	currentTime := time.UnixMilli(0)
   153  	cache.now = func() time.Time { return currentTime }
   154  
   155  	cache.Put("A", t)
   156  	assert.Equal(t, t, cache.Get("A"))
   157  
   158  	currentTime = currentTime.Add(time.Millisecond * 100)
   159  
   160  	assert.Nil(t, cache.Get("A"))
   161  
   162  	select {
   163  	case b := <-ch:
   164  		assert.True(t, b)
   165  	case <-time.After(100 * time.Millisecond):
   166  		t.Error("RemovedFunc did not send true on channel ch")
   167  	}
   168  }