github.com/xgzlucario/GigaCache@v0.0.0-20240508025442-54204e9c8a6b/cache_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  func genKV(i int) (string, []byte) {
    12  	k := fmt.Sprintf("%08x", i)
    13  	return k, []byte(k)
    14  }
    15  
    16  func getOptions(num, interval int) Options {
    17  	opt := DefaultOptions
    18  	opt.ShardCount = 1
    19  	opt.EvictInterval = interval
    20  	opt.IndexSize = num
    21  	return opt
    22  }
    23  
    24  func checkValidData(assert *assert.Assertions, m *GigaCache, start, end int) {
    25  	for i := start; i < end; i++ {
    26  		k, _ := genKV(i)
    27  		val, ts, ok := m.Get(k)
    28  		assert.True(ok)
    29  		assert.Equal(string(val), k)
    30  		assert.GreaterOrEqual(ts, int64(0))
    31  	}
    32  	// scan
    33  	beginKey, _ := genKV(start)
    34  	endKey, _ := genKV(end)
    35  
    36  	var count int
    37  	m.Scan(func(key, val []byte, i int64) bool {
    38  		if string(key) < beginKey || string(key) >= endKey {
    39  			assert.Fail("invalid data")
    40  		}
    41  		assert.Equal(key, val)
    42  		count++
    43  		return true
    44  	})
    45  	assert.Equal(count, end-start)
    46  
    47  	// scan break
    48  	count = 0
    49  	m.Scan(func(key, val []byte, i int64) bool {
    50  		count++
    51  		return count < (end-start)/2
    52  	})
    53  	assert.Equal(count, (end-start)/2)
    54  }
    55  
    56  func checkInvalidData(assert *assert.Assertions, m *GigaCache, start, end int) {
    57  	// range
    58  	for i := start; i < end; i++ {
    59  		k, _ := genKV(i)
    60  		val, ts, ok := m.Get(k)
    61  		assert.False(ok)
    62  		assert.Nil(val)
    63  		assert.Equal(ts, int64(0))
    64  		// setTTL
    65  		ok = m.SetTTL(k, time.Now().UnixNano())
    66  		assert.False(ok)
    67  		// remove
    68  		m.Remove(k)
    69  	}
    70  	// scan
    71  	beginKey, _ := genKV(start)
    72  	endKey, _ := genKV(end)
    73  
    74  	m.Scan(func(key, val []byte, i int64) bool {
    75  		if string(key) >= beginKey && string(key) < endKey {
    76  			assert.Fail("invalid data")
    77  		}
    78  		assert.Equal(key, val)
    79  		return true
    80  	})
    81  }
    82  
    83  func TestCache(t *testing.T) {
    84  	assert := assert.New(t)
    85  	const num = 1000
    86  	m := New(getOptions(num, 3))
    87  
    88  	// init cache.
    89  	for i := 0; i < num/3; i++ {
    90  		k, v := genKV(i)
    91  		m.Set(k, v)
    92  	}
    93  	for i := num / 3; i < num*2/3; i++ {
    94  		k, v := genKV(i)
    95  		m.SetEx(k, v, time.Hour)
    96  	}
    97  	for i := num * 2 / 3; i < num; i++ {
    98  		k, v := genKV(i)
    99  		m.SetEx(k, v, time.Second)
   100  	}
   101  
   102  	// wait for expired.
   103  	time.Sleep(time.Second * 2)
   104  
   105  	// check.
   106  	{
   107  		checkValidData(assert, m, 0, num*2/3)
   108  		checkInvalidData(assert, m, num*2/3, num)
   109  		m.Migrate()
   110  		checkValidData(assert, m, 0, num*2/3)
   111  		checkInvalidData(assert, m, num*2/3, num)
   112  	}
   113  
   114  	// setTTL
   115  	ts := time.Now().UnixNano()
   116  	for i := num / 3; i < num*2/3; i++ {
   117  		k, _ := genKV(i)
   118  		assert.True(m.SetTTL(k, ts))
   119  	}
   120  	time.Sleep(time.Second)
   121  
   122  	// check.
   123  	{
   124  		checkValidData(assert, m, 0, num/3)
   125  		checkInvalidData(assert, m, num/3, num)
   126  		m.Migrate()
   127  		checkValidData(assert, m, 0, num/3)
   128  		checkInvalidData(assert, m, num/3, num)
   129  	}
   130  
   131  	// remove all.
   132  	for i := 0; i < num/3; i++ {
   133  		k, _ := genKV(i)
   134  		m.Remove(k)
   135  	}
   136  	for i := num / 3; i < num; i++ {
   137  		k, _ := genKV(i)
   138  		m.Remove(k)
   139  	}
   140  
   141  	// check.
   142  	{
   143  		checkInvalidData(assert, m, 0, num)
   144  		m.Migrate()
   145  		checkInvalidData(assert, m, 0, num)
   146  	}
   147  
   148  	assert.Panics(func() {
   149  		opt := DefaultOptions
   150  		opt.ShardCount = 0
   151  		New(opt)
   152  	})
   153  
   154  	assert.Panics(func() {
   155  		opt := DefaultOptions
   156  		opt.EvictInterval = -1
   157  		New(opt)
   158  	})
   159  }
   160  
   161  func TestEvict(t *testing.T) {
   162  	assert := assert.New(t)
   163  	const num = 1000
   164  	opt := getOptions(num, 1)
   165  	m := New(opt)
   166  
   167  	// set data.
   168  	for i := 0; i < num; i++ {
   169  		k, v := genKV(i)
   170  		m.SetEx(k, v, time.Second)
   171  	}
   172  	time.Sleep(time.Second * 2)
   173  
   174  	// stat
   175  	stat := m.Stat()
   176  	assert.Equal(stat.Len, num)
   177  	assert.Equal(stat.Alloc, uint64(stat.Len*(16+2)))
   178  	assert.Equal(stat.Unused, uint64(0))
   179  	assert.Equal(stat.Evict, uint64(0))
   180  	assert.Greater(stat.Probe, uint64(0))
   181  	assert.Equal(stat.EvictRate(), float64(0))
   182  	assert.Equal(stat.UnusedRate(), float64(0))
   183  
   184  	// trig evict.
   185  	m.Set("trig1234", []byte("trig1234"))
   186  
   187  	stat = m.Stat()
   188  	assert.Equal(stat.Len, int(num-stat.Evict+1))
   189  	assert.Equal(stat.Alloc, uint64(16+2))
   190  	assert.Equal(stat.Unused, uint64(0))
   191  	assert.Equal(stat.Migrates, uint64(1))
   192  }
   193  
   194  func TestDataAlloc(t *testing.T) {
   195  	assert := assert.New(t)
   196  
   197  	t.Run("memhash", func(t *testing.T) {
   198  		opt := DefaultOptions
   199  		opt.ShardCount = 1
   200  		opt.DisableEvict = true
   201  		m := New(opt)
   202  		m.Set("hello", []byte("world"))
   203  
   204  		m.Set("abc", []byte("123"))
   205  		// stat
   206  		stat := m.Stat()
   207  		assert.Equal(stat.Len, 2)
   208  		assert.Equal(stat.Alloc, uint64(12+8))
   209  		assert.Equal(stat.Unused, uint64(0))
   210  
   211  		// set same data(update inplaced).
   212  		m.Set("abc", []byte("234"))
   213  
   214  		stat = m.Stat()
   215  		assert.Equal(stat.Len, 2)
   216  		assert.Equal(stat.Alloc, uint64(12+8))
   217  		assert.Equal(stat.Unused, uint64(0))
   218  
   219  		// set great.
   220  		m.Set("abc", []byte("12345"))
   221  
   222  		stat = m.Stat()
   223  		assert.Equal(stat.Len, 2)
   224  		assert.Equal(stat.Alloc, uint64(12+8+10))
   225  		assert.Equal(stat.Unused, uint64(8))
   226  	})
   227  
   228  	t.Run("testHash", func(t *testing.T) {
   229  		opt := DefaultOptions
   230  		opt.ShardCount = 1
   231  		opt.DisableEvict = true
   232  		opt.HashFn = func(s string) uint64 {
   233  			return 0
   234  		}
   235  		m := New(opt)
   236  		m.Set("hello", []byte("world"))
   237  
   238  		m.Set("abc", []byte("123"))
   239  		// stat
   240  		stat := m.Stat()
   241  		assert.Equal(stat.Len, 2)
   242  		assert.Equal(stat.Alloc, uint64(12+8))
   243  		assert.Equal(stat.Unused, uint64(0))
   244  
   245  		// set same data(update inplaced).
   246  		m.Set("abc", []byte("234"))
   247  
   248  		stat = m.Stat()
   249  		assert.Equal(stat.Len, 2)
   250  		assert.Equal(stat.Alloc, uint64(12+8))
   251  		assert.Equal(stat.Unused, uint64(0))
   252  
   253  		// set great.
   254  		m.Set("abc", []byte("12345"))
   255  
   256  		stat = m.Stat()
   257  		assert.Equal(stat.Len, 2)
   258  		assert.Equal(stat.Alloc, uint64(12+8+10))
   259  		assert.Equal(stat.Unused, uint64(8))
   260  	})
   261  }
   262  
   263  func TestScanSmall(t *testing.T) {
   264  	assert := assert.New(t)
   265  	opt := DefaultOptions
   266  	opt.ShardCount = 1024
   267  	m := New(opt)
   268  
   269  	for i := 0; i < 100; i++ {
   270  		k, v := genKV(i)
   271  		m.Set(k, v)
   272  	}
   273  
   274  	var count int
   275  	m.Scan(func(key, val []byte, ttl int64) (next bool) {
   276  		assert.Equal(key, val)
   277  		assert.Equal(ttl, int64(0))
   278  		count++
   279  		return true
   280  	})
   281  	assert.Equal(count, 100)
   282  }
   283  
   284  func TestUtils(t *testing.T) {
   285  	_ = SizeUvarint(1)
   286  }