github.com/vicanso/lru-ttl@v1.5.1/l2cache_test.go (about)

     1  // Copyright 2020 tree xie
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package lruttl
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"encoding/json"
    20  	"errors"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  type testSlowCache struct {
    28  	data map[string][]byte
    29  }
    30  
    31  const slowCacheTTL = 101 * time.Millisecond
    32  
    33  var testSlowCacheNilErr = errors.New("not found")
    34  
    35  func (sc *testSlowCache) Get(_ context.Context, key string) ([]byte, error) {
    36  	buf, ok := sc.data[key]
    37  	if !ok {
    38  		return nil, testSlowCacheNilErr
    39  	}
    40  	time.Sleep(time.Second)
    41  	return buf, nil
    42  }
    43  
    44  func (sc *testSlowCache) Set(_ context.Context, key string, value []byte, ttl time.Duration) error {
    45  	sc.data[key] = value
    46  	return nil
    47  }
    48  func (sc *testSlowCache) TTL(_ context.Context, key string) (time.Duration, error) {
    49  	return slowCacheTTL, nil
    50  }
    51  
    52  func (sc *testSlowCache) Del(_ context.Context, key string) (int64, error) {
    53  	delete(sc.data, key)
    54  	return 1, nil
    55  }
    56  
    57  type testData struct {
    58  	Name string `json:"name,omitempty"`
    59  }
    60  
    61  func TestL2Cache(t *testing.T) {
    62  	assert := assert.New(t)
    63  	ctx := context.Background()
    64  
    65  	sc := testSlowCache{
    66  		data: make(map[string][]byte),
    67  	}
    68  	opts := []L2CacheOption{
    69  		L2CacheMarshalOption(json.Marshal),
    70  		L2CacheUnmarshalOption(json.Unmarshal),
    71  		L2CachePrefixOption("prefix:"),
    72  		L2CacheNilErrOption(testSlowCacheNilErr),
    73  	}
    74  	l2 := NewL2Cache(&sc, 1, time.Second, opts...)
    75  
    76  	key, err := l2.getKey("1")
    77  	assert.Nil(err)
    78  	assert.Equal("prefix:1", key)
    79  	_, err = l2.getKey("")
    80  	assert.Equal(ErrKeyIsNil, err)
    81  
    82  	key = "abcd"
    83  	name := "test"
    84  	data := testData{}
    85  
    86  	err = l2.Get(ctx, key, &data)
    87  	assert.NotNil(err)
    88  	assert.Equal("not found", err.Error())
    89  
    90  	err = l2.Set(ctx, key, &testData{
    91  		Name: name,
    92  	})
    93  	assert.Nil(err)
    94  
    95  	// 成功获取
    96  	err = l2.Get(ctx, key, &data)
    97  	assert.Nil(err)
    98  	assert.Equal(name, data.Name)
    99  
   100  	// 由于lru的大小令为1,因此会导致lru中清除了原有的key
   101  	err = l2.Set(ctx, "ab", &testData{})
   102  	assert.Nil(err)
   103  
   104  	// 从slow cache中获取数据并更新lru缓存
   105  	err = l2.Get(ctx, key, &data)
   106  	assert.Nil(err)
   107  	assert.Equal(name, data.Name)
   108  
   109  	// 从lru获取缓存(时间较快)
   110  	start := time.Now()
   111  	err = l2.Get(ctx, key, &data)
   112  	assert.Nil(err)
   113  	assert.Equal(name, data.Name)
   114  	// 从lru获取耗时少于10ms
   115  	assert.True(time.Since(start) < 10*time.Millisecond)
   116  
   117  	err = l2.Set(ctx, key, &map[string]string{
   118  		"name": "newName",
   119  	})
   120  	assert.Nil(err)
   121  	m := make(map[string]string)
   122  	err = l2.Get(ctx, key, &m)
   123  	assert.Nil(err)
   124  	assert.Equal("newName", m["name"])
   125  
   126  	err = l2.Get(ctx, "abc", &map[string]string{})
   127  	assert.NotNil(err)
   128  
   129  	err = l2.GetIgnoreNilErr(ctx, "abc", &map[string]string{})
   130  	assert.Nil(err)
   131  }
   132  
   133  func TestL2CacheTTL(t *testing.T) {
   134  	assert := assert.New(t)
   135  	sc := testSlowCache{
   136  		data: make(map[string][]byte),
   137  	}
   138  	ctx := context.Background()
   139  	l2 := NewL2Cache(&sc, 10, 10*time.Second)
   140  	key := "test"
   141  	err := l2.Set(ctx, key, "value", 2*time.Second)
   142  	assert.Nil(err)
   143  
   144  	ttl, err := l2.TTL(ctx, key)
   145  	assert.Nil(err)
   146  	// 从lru中获取
   147  	assert.True(ttl > time.Second && ttl <= 2*time.Second)
   148  
   149  	l2.ttlCache.Remove(key)
   150  
   151  	ttl, err = l2.TTL(ctx, key)
   152  	assert.Nil(err)
   153  	// 从slow cache中获取,slow cache获取ttl为固定值
   154  	assert.Equal(slowCacheTTL, ttl)
   155  }
   156  
   157  func TestL2CacheDel(t *testing.T) {
   158  	assert := assert.New(t)
   159  	sc := testSlowCache{
   160  		data: make(map[string][]byte),
   161  	}
   162  	ctx := context.Background()
   163  	l2 := NewL2Cache(&sc, 10, 10*time.Second)
   164  	key := "test"
   165  	value := "value"
   166  	err := l2.Set(ctx, key, value, 2*time.Second)
   167  	assert.Nil(err)
   168  
   169  	result := ""
   170  	err = l2.Get(ctx, key, &result)
   171  	assert.Nil(err)
   172  	assert.Equal(value, result)
   173  
   174  	count, err := l2.Del(ctx, key)
   175  	assert.Equal(int64(1), count)
   176  	assert.Nil(err)
   177  
   178  	// 删除后再获取失败
   179  	err = l2.Get(ctx, key, &result)
   180  	assert.Equal("not found", err.Error())
   181  }
   182  
   183  func TestGetSetBytes(t *testing.T) {
   184  	assert := assert.New(t)
   185  	sc := testSlowCache{
   186  		data: make(map[string][]byte),
   187  	}
   188  	ctx := context.Background()
   189  	l2 := NewL2Cache(&sc, 10, 10*time.Second)
   190  
   191  	key := "TestGetSetBytes"
   192  	err := l2.SetBytes(ctx, key, []byte("abc"))
   193  	assert.Nil(err)
   194  
   195  	buf, err := l2.GetBytes(ctx, key)
   196  	assert.Nil(err)
   197  	assert.Equal([]byte("abc"), buf)
   198  }
   199  
   200  func TestBufferMarshalUnmarshal(t *testing.T) {
   201  	assert := assert.New(t)
   202  	buf := bytes.NewBufferString("abc")
   203  	result, err := BufferMarshal(buf)
   204  	assert.Nil(err)
   205  	assert.Equal(buf.Bytes(), result)
   206  
   207  	newBuf := &bytes.Buffer{}
   208  	err = BufferUnmarshal(result, newBuf)
   209  	assert.Nil(err)
   210  	assert.Equal(buf, newBuf)
   211  }