github.com/bhojpur/cache@v0.0.4/pkg/engine/ristretto/policy_test.go (about)

     1  package ristretto
     2  
     3  // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func TestPolicy(t *testing.T) {
    31  	defer func() {
    32  		require.Nil(t, recover())
    33  	}()
    34  	newPolicy(100, 10)
    35  }
    36  
    37  func TestPolicyMetrics(t *testing.T) {
    38  	p := newDefaultPolicy(100, 10)
    39  	p.CollectMetrics(newMetrics())
    40  	require.NotNil(t, p.metrics)
    41  	require.NotNil(t, p.evict.metrics)
    42  }
    43  
    44  func TestPolicyProcessItems(t *testing.T) {
    45  	p := newDefaultPolicy(100, 10)
    46  	p.itemsCh <- []uint64{1, 2, 2}
    47  	time.Sleep(wait)
    48  	p.Lock()
    49  	require.Equal(t, int64(2), p.admit.Estimate(2))
    50  	require.Equal(t, int64(1), p.admit.Estimate(1))
    51  	p.Unlock()
    52  
    53  	p.stop <- struct{}{}
    54  	p.itemsCh <- []uint64{3, 3, 3}
    55  	time.Sleep(wait)
    56  	p.Lock()
    57  	require.Equal(t, int64(0), p.admit.Estimate(3))
    58  	p.Unlock()
    59  }
    60  
    61  func TestPolicyPush(t *testing.T) {
    62  	p := newDefaultPolicy(100, 10)
    63  	require.True(t, p.Push([]uint64{}))
    64  
    65  	keepCount := 0
    66  	for i := 0; i < 10; i++ {
    67  		if p.Push([]uint64{1, 2, 3, 4, 5}) {
    68  			keepCount++
    69  		}
    70  	}
    71  	require.NotEqual(t, 0, keepCount)
    72  }
    73  
    74  func TestPolicyAdd(t *testing.T) {
    75  	p := newDefaultPolicy(1000, 100)
    76  	if victims, added := p.Add(1, 101); victims != nil || added {
    77  		t.Fatal("can't add an item bigger than entire cache")
    78  	}
    79  	p.Lock()
    80  	p.evict.add(1, 1)
    81  	p.admit.Increment(1)
    82  	p.admit.Increment(2)
    83  	p.admit.Increment(3)
    84  	p.Unlock()
    85  
    86  	victims, added := p.Add(1, 1)
    87  	require.Nil(t, victims)
    88  	require.False(t, added)
    89  
    90  	victims, added = p.Add(2, 20)
    91  	require.Nil(t, victims)
    92  	require.True(t, added)
    93  
    94  	victims, added = p.Add(3, 90)
    95  	require.NotNil(t, victims)
    96  	require.True(t, added)
    97  
    98  	victims, added = p.Add(4, 20)
    99  	require.NotNil(t, victims)
   100  	require.False(t, added)
   101  }
   102  
   103  func TestPolicyHas(t *testing.T) {
   104  	p := newDefaultPolicy(100, 10)
   105  	p.Add(1, 1)
   106  	require.True(t, p.Has(1))
   107  	require.False(t, p.Has(2))
   108  }
   109  
   110  func TestPolicyDel(t *testing.T) {
   111  	p := newDefaultPolicy(100, 10)
   112  	p.Add(1, 1)
   113  	p.Del(1)
   114  	p.Del(2)
   115  	require.False(t, p.Has(1))
   116  	require.False(t, p.Has(2))
   117  }
   118  
   119  func TestPolicyCap(t *testing.T) {
   120  	p := newDefaultPolicy(100, 10)
   121  	p.Add(1, 1)
   122  	require.Equal(t, int64(9), p.MaxCost()-p.Used())
   123  }
   124  
   125  func TestPolicyUpdate(t *testing.T) {
   126  	p := newDefaultPolicy(100, 10)
   127  	p.Add(1, 1)
   128  	p.Update(1, 2)
   129  	p.Lock()
   130  	require.Equal(t, int64(2), p.evict.keyCosts[1])
   131  	p.Unlock()
   132  }
   133  
   134  func TestPolicyCost(t *testing.T) {
   135  	p := newDefaultPolicy(100, 10)
   136  	p.Add(1, 2)
   137  	require.Equal(t, int64(2), p.Cost(1))
   138  	require.Equal(t, int64(-1), p.Cost(2))
   139  }
   140  
   141  func TestPolicyClear(t *testing.T) {
   142  	p := newDefaultPolicy(100, 10)
   143  	p.Add(1, 1)
   144  	p.Add(2, 2)
   145  	p.Add(3, 3)
   146  	p.Clear()
   147  	require.Equal(t, int64(10), p.MaxCost()-p.Used())
   148  	require.False(t, p.Has(1))
   149  	require.False(t, p.Has(2))
   150  	require.False(t, p.Has(3))
   151  }
   152  
   153  func TestPolicyClose(t *testing.T) {
   154  	defer func() {
   155  		require.NotNil(t, recover())
   156  	}()
   157  
   158  	p := newDefaultPolicy(100, 10)
   159  	p.Add(1, 1)
   160  	p.Close()
   161  	p.itemsCh <- []uint64{1}
   162  }
   163  
   164  func TestPushAfterClose(t *testing.T) {
   165  	p := newDefaultPolicy(100, 10)
   166  	p.Close()
   167  	require.False(t, p.Push([]uint64{1, 2}))
   168  }
   169  
   170  func TestAddAfterClose(t *testing.T) {
   171  	p := newDefaultPolicy(100, 10)
   172  	p.Close()
   173  	p.Add(1, 1)
   174  }
   175  
   176  func TestSampledLFUAdd(t *testing.T) {
   177  	e := newSampledLFU(4)
   178  	e.add(1, 1)
   179  	e.add(2, 2)
   180  	e.add(3, 1)
   181  	require.Equal(t, int64(4), e.used)
   182  	require.Equal(t, int64(2), e.keyCosts[2])
   183  }
   184  
   185  func TestSampledLFUDel(t *testing.T) {
   186  	e := newSampledLFU(4)
   187  	e.add(1, 1)
   188  	e.add(2, 2)
   189  	e.del(2)
   190  	require.Equal(t, int64(1), e.used)
   191  	_, ok := e.keyCosts[2]
   192  	require.False(t, ok)
   193  	e.del(4)
   194  }
   195  
   196  func TestSampledLFUUpdate(t *testing.T) {
   197  	e := newSampledLFU(4)
   198  	e.add(1, 1)
   199  	require.True(t, e.updateIfHas(1, 2))
   200  	require.Equal(t, int64(2), e.used)
   201  	require.False(t, e.updateIfHas(2, 2))
   202  }
   203  
   204  func TestSampledLFUClear(t *testing.T) {
   205  	e := newSampledLFU(4)
   206  	e.add(1, 1)
   207  	e.add(2, 2)
   208  	e.add(3, 1)
   209  	e.clear()
   210  	require.Equal(t, 0, len(e.keyCosts))
   211  	require.Equal(t, int64(0), e.used)
   212  }
   213  
   214  func TestSampledLFURoom(t *testing.T) {
   215  	e := newSampledLFU(16)
   216  	e.add(1, 1)
   217  	e.add(2, 2)
   218  	e.add(3, 3)
   219  	require.Equal(t, int64(6), e.roomLeft(4))
   220  }
   221  
   222  func TestSampledLFUSample(t *testing.T) {
   223  	e := newSampledLFU(16)
   224  	e.add(4, 4)
   225  	e.add(5, 5)
   226  	sample := e.fillSample([]*policyPair{
   227  		{1, 1},
   228  		{2, 2},
   229  		{3, 3},
   230  	})
   231  	k := sample[len(sample)-1].key
   232  	require.Equal(t, 5, len(sample))
   233  	require.NotEqual(t, 1, k)
   234  	require.NotEqual(t, 2, k)
   235  	require.NotEqual(t, 3, k)
   236  	require.Equal(t, len(sample), len(e.fillSample(sample)))
   237  	e.del(5)
   238  	sample = e.fillSample(sample[:len(sample)-2])
   239  	require.Equal(t, 4, len(sample))
   240  }
   241  
   242  func TestTinyLFUIncrement(t *testing.T) {
   243  	a := newTinyLFU(4)
   244  	a.Increment(1)
   245  	a.Increment(1)
   246  	a.Increment(1)
   247  	require.True(t, a.door.Has(1))
   248  	require.Equal(t, int64(2), a.freq.Estimate(1))
   249  
   250  	a.Increment(1)
   251  	require.False(t, a.door.Has(1))
   252  	require.Equal(t, int64(1), a.freq.Estimate(1))
   253  }
   254  
   255  func TestTinyLFUEstimate(t *testing.T) {
   256  	a := newTinyLFU(8)
   257  	a.Increment(1)
   258  	a.Increment(1)
   259  	a.Increment(1)
   260  	require.Equal(t, int64(3), a.Estimate(1))
   261  	require.Equal(t, int64(0), a.Estimate(2))
   262  }
   263  
   264  func TestTinyLFUPush(t *testing.T) {
   265  	a := newTinyLFU(16)
   266  	a.Push([]uint64{1, 2, 2, 3, 3, 3})
   267  	require.Equal(t, int64(1), a.Estimate(1))
   268  	require.Equal(t, int64(2), a.Estimate(2))
   269  	require.Equal(t, int64(3), a.Estimate(3))
   270  	require.Equal(t, int64(6), a.incrs)
   271  }
   272  
   273  func TestTinyLFUClear(t *testing.T) {
   274  	a := newTinyLFU(16)
   275  	a.Push([]uint64{1, 3, 3, 3})
   276  	a.clear()
   277  	require.Equal(t, int64(0), a.incrs)
   278  	require.Equal(t, int64(0), a.Estimate(3))
   279  }