github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/cache/redis_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/gomodule/redigo/redis"
     7  	"github.com/rafaeljusto/redigomock"
     8  	"github.com/stretchr/testify/assert"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func TestNewRedisStore(t *testing.T) {
    14  	asserts := assert.New(t)
    15  
    16  	store := NewRedisStore(10, "tcp", "", "", "", "0")
    17  	asserts.NotNil(store)
    18  
    19  	asserts.Panics(func() {
    20  		store.pool.Dial()
    21  	})
    22  
    23  	testConn := redigomock.NewConn()
    24  	cmd := testConn.Command("PING").Expect("PONG")
    25  	err := store.pool.TestOnBorrow(testConn, time.Now())
    26  	if testConn.Stats(cmd) != 1 {
    27  		fmt.Println("Command was not used")
    28  		return
    29  	}
    30  	asserts.NoError(err)
    31  }
    32  
    33  func TestRedisStore_Set(t *testing.T) {
    34  	asserts := assert.New(t)
    35  	conn := redigomock.NewConn()
    36  	pool := &redis.Pool{
    37  		Dial:    func() (redis.Conn, error) { return conn, nil },
    38  		MaxIdle: 10,
    39  	}
    40  	store := &RedisStore{pool: pool}
    41  
    42  	// 正常情况
    43  	{
    44  		cmd := conn.Command("SET", "test", redigomock.NewAnyData()).ExpectStringSlice("OK")
    45  		err := store.Set("test", "test val", -1)
    46  		asserts.NoError(err)
    47  		if conn.Stats(cmd) != 1 {
    48  			fmt.Println("Command was not used")
    49  			return
    50  		}
    51  	}
    52  
    53  	// 带有TTL
    54  	// 正常情况
    55  	{
    56  		cmd := conn.Command("SETEX", "test", 10, redigomock.NewAnyData()).ExpectStringSlice("OK")
    57  		err := store.Set("test", "test val", 10)
    58  		asserts.NoError(err)
    59  		if conn.Stats(cmd) != 1 {
    60  			fmt.Println("Command was not used")
    61  			return
    62  		}
    63  	}
    64  
    65  	// 序列化出错
    66  	{
    67  		value := struct {
    68  			Key string
    69  		}{
    70  			Key: "123",
    71  		}
    72  		err := store.Set("test", value, -1)
    73  		asserts.Error(err)
    74  	}
    75  
    76  	// 命令执行失败
    77  	{
    78  		conn.Clear()
    79  		cmd := conn.Command("SET", "test", redigomock.NewAnyData()).ExpectError(errors.New("error"))
    80  		err := store.Set("test", "test val", -1)
    81  		asserts.Error(err)
    82  		if conn.Stats(cmd) != 1 {
    83  			fmt.Println("Command was not used")
    84  			return
    85  		}
    86  	}
    87  	// 获取连接失败
    88  	{
    89  		store.pool = &redis.Pool{
    90  			Dial:    func() (redis.Conn, error) { return nil, errors.New("error") },
    91  			MaxIdle: 10,
    92  		}
    93  		err := store.Set("test", "123", -1)
    94  		asserts.Error(err)
    95  	}
    96  
    97  }
    98  
    99  func TestRedisStore_Get(t *testing.T) {
   100  	asserts := assert.New(t)
   101  	conn := redigomock.NewConn()
   102  	pool := &redis.Pool{
   103  		Dial:    func() (redis.Conn, error) { return conn, nil },
   104  		MaxIdle: 10,
   105  	}
   106  	store := &RedisStore{pool: pool}
   107  
   108  	// 正常情况
   109  	{
   110  		expectVal, _ := serializer("test val")
   111  		cmd := conn.Command("GET", "test").Expect(expectVal)
   112  		val, ok := store.Get("test")
   113  		if conn.Stats(cmd) != 1 {
   114  			fmt.Println("Command was not used")
   115  			return
   116  		}
   117  		asserts.True(ok)
   118  		asserts.Equal("test val", val.(string))
   119  	}
   120  
   121  	// Key不存在
   122  	{
   123  		conn.Clear()
   124  		cmd := conn.Command("GET", "test").Expect(nil)
   125  		val, ok := store.Get("test")
   126  		if conn.Stats(cmd) != 1 {
   127  			fmt.Println("Command was not used")
   128  			return
   129  		}
   130  		asserts.False(ok)
   131  		asserts.Nil(val)
   132  	}
   133  	// 解码错误
   134  	{
   135  		conn.Clear()
   136  		cmd := conn.Command("GET", "test").Expect([]byte{0x20})
   137  		val, ok := store.Get("test")
   138  		if conn.Stats(cmd) != 1 {
   139  			fmt.Println("Command was not used")
   140  			return
   141  		}
   142  		asserts.False(ok)
   143  		asserts.Nil(val)
   144  	}
   145  	// 获取连接失败
   146  	{
   147  		store.pool = &redis.Pool{
   148  			Dial:    func() (redis.Conn, error) { return nil, errors.New("error") },
   149  			MaxIdle: 10,
   150  		}
   151  		val, ok := store.Get("test")
   152  		asserts.False(ok)
   153  		asserts.Nil(val)
   154  	}
   155  }
   156  
   157  func TestRedisStore_Gets(t *testing.T) {
   158  	asserts := assert.New(t)
   159  	conn := redigomock.NewConn()
   160  	pool := &redis.Pool{
   161  		Dial:    func() (redis.Conn, error) { return conn, nil },
   162  		MaxIdle: 10,
   163  	}
   164  	store := &RedisStore{pool: pool}
   165  
   166  	// 全部命中
   167  	{
   168  		conn.Clear()
   169  		value1, _ := serializer("1")
   170  		value2, _ := serializer("2")
   171  		cmd := conn.Command("MGET", "test_1", "test_2").ExpectSlice(
   172  			value1, value2)
   173  		res, missed := store.Gets([]string{"1", "2"}, "test_")
   174  		if conn.Stats(cmd) != 1 {
   175  			fmt.Println("Command was not used")
   176  			return
   177  		}
   178  		asserts.Len(missed, 0)
   179  		asserts.Len(res, 2)
   180  		asserts.Equal("1", res["1"].(string))
   181  		asserts.Equal("2", res["2"].(string))
   182  	}
   183  
   184  	// 命中一个
   185  	{
   186  		conn.Clear()
   187  		value2, _ := serializer("2")
   188  		cmd := conn.Command("MGET", "test_1", "test_2").ExpectSlice(
   189  			nil, value2)
   190  		res, missed := store.Gets([]string{"1", "2"}, "test_")
   191  		if conn.Stats(cmd) != 1 {
   192  			fmt.Println("Command was not used")
   193  			return
   194  		}
   195  		asserts.Len(missed, 1)
   196  		asserts.Len(res, 1)
   197  		asserts.Equal("1", missed[0])
   198  		asserts.Equal("2", res["2"].(string))
   199  	}
   200  
   201  	// 命令出错
   202  	{
   203  		conn.Clear()
   204  		cmd := conn.Command("MGET", "test_1", "test_2").ExpectError(errors.New("error"))
   205  		res, missed := store.Gets([]string{"1", "2"}, "test_")
   206  		if conn.Stats(cmd) != 1 {
   207  			fmt.Println("Command was not used")
   208  			return
   209  		}
   210  		asserts.Len(missed, 2)
   211  		asserts.Len(res, 0)
   212  	}
   213  
   214  	// 连接出错
   215  	{
   216  		conn.Clear()
   217  		store.pool = &redis.Pool{
   218  			Dial:    func() (redis.Conn, error) { return nil, errors.New("error") },
   219  			MaxIdle: 10,
   220  		}
   221  		res, missed := store.Gets([]string{"1", "2"}, "test_")
   222  		asserts.Len(missed, 2)
   223  		asserts.Len(res, 0)
   224  	}
   225  }
   226  
   227  func TestRedisStore_Sets(t *testing.T) {
   228  	asserts := assert.New(t)
   229  	conn := redigomock.NewConn()
   230  	pool := &redis.Pool{
   231  		Dial:    func() (redis.Conn, error) { return conn, nil },
   232  		MaxIdle: 10,
   233  	}
   234  	store := &RedisStore{pool: pool}
   235  
   236  	// 正常
   237  	{
   238  		cmd := conn.Command("MSET", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()).ExpectSlice("OK")
   239  		err := store.Sets(map[string]interface{}{"1": "1", "2": "2"}, "test_")
   240  		asserts.NoError(err)
   241  		if conn.Stats(cmd) != 1 {
   242  			fmt.Println("Command was not used")
   243  			return
   244  		}
   245  	}
   246  
   247  	// 序列化失败
   248  	{
   249  		conn.Clear()
   250  		value := struct {
   251  			Key string
   252  		}{
   253  			Key: "123",
   254  		}
   255  		err := store.Sets(map[string]interface{}{"1": value, "2": "2"}, "test_")
   256  		asserts.Error(err)
   257  	}
   258  
   259  	// 执行失败
   260  	{
   261  		cmd := conn.Command("MSET", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()).ExpectError(errors.New("error"))
   262  		err := store.Sets(map[string]interface{}{"1": "1", "2": "2"}, "test_")
   263  		asserts.Error(err)
   264  		if conn.Stats(cmd) != 1 {
   265  			fmt.Println("Command was not used")
   266  			return
   267  		}
   268  	}
   269  
   270  	// 连接失败
   271  	{
   272  		conn.Clear()
   273  		store.pool = &redis.Pool{
   274  			Dial:    func() (redis.Conn, error) { return nil, errors.New("error") },
   275  			MaxIdle: 10,
   276  		}
   277  		err := store.Sets(map[string]interface{}{"1": "1", "2": "2"}, "test_")
   278  		asserts.Error(err)
   279  	}
   280  }
   281  
   282  func TestRedisStore_Delete(t *testing.T) {
   283  	asserts := assert.New(t)
   284  	conn := redigomock.NewConn()
   285  	pool := &redis.Pool{
   286  		Dial:    func() (redis.Conn, error) { return conn, nil },
   287  		MaxIdle: 10,
   288  	}
   289  	store := &RedisStore{pool: pool}
   290  
   291  	// 正常
   292  	{
   293  		cmd := conn.Command("DEL", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()).ExpectSlice("OK")
   294  		err := store.Delete([]string{"1", "2", "3", "4"}, "test_")
   295  		asserts.NoError(err)
   296  		if conn.Stats(cmd) != 1 {
   297  			fmt.Println("Command was not used")
   298  			return
   299  		}
   300  	}
   301  
   302  	// 命令执行失败
   303  	{
   304  		conn.Clear()
   305  		cmd := conn.Command("DEL", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()).ExpectError(errors.New("error"))
   306  		err := store.Delete([]string{"1", "2", "3", "4"}, "test_")
   307  		asserts.Error(err)
   308  		if conn.Stats(cmd) != 1 {
   309  			fmt.Println("Command was not used")
   310  			return
   311  		}
   312  	}
   313  
   314  	// 连接失败
   315  	{
   316  		conn.Clear()
   317  		store.pool = &redis.Pool{
   318  			Dial:    func() (redis.Conn, error) { return nil, errors.New("error") },
   319  			MaxIdle: 10,
   320  		}
   321  		err := store.Delete([]string{"1", "2", "3", "4"}, "test_")
   322  		asserts.Error(err)
   323  	}
   324  }