From dc8fd5e0452bcf755b1d63f91074990e56b52cd7 Mon Sep 17 00:00:00 2001 From: Ramadani Date: Wed, 11 Aug 2021 13:31:16 +0800 Subject: [PATCH 1/3] fix redis cluster multiple keys --- cache/cache_redis_cluster.go | 24 ++++++++++++++++-- cache/cache_redis_cluster_test.go | 41 +++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/cache/cache_redis_cluster.go b/cache/cache_redis_cluster.go index af9b7db..4e4f346 100644 --- a/cache/cache_redis_cluster.go +++ b/cache/cache_redis_cluster.go @@ -36,11 +36,31 @@ func (c *cacheRedisCluster) SetNX(ctx context.Context, key string, value interfa } func (c *cacheRedisCluster) Exists(ctx context.Context, keys ...string) (int64, error) { - return c.client.Exists(ctx, keys...).Result() + n := int64(0) + + for _, key := range keys { + i, err := c.client.Exists(ctx, key).Result() + if err != nil { + return 0, err + } + n += i + } + + return n, nil } func (c *cacheRedisCluster) Del(ctx context.Context, keys ...string) (int64, error) { - return c.client.Del(ctx, keys...).Result() + n := int64(0) + + for _, key := range keys { + i, err := c.client.Del(ctx, key).Result() + if err != nil { + return 0, err + } + n += i + } + + return n, nil } // NewCacheRedisCluster cache using redis cluster diff --git a/cache/cache_redis_cluster_test.go b/cache/cache_redis_cluster_test.go index 62eeb0a..2eb4e1e 100644 --- a/cache/cache_redis_cluster_test.go +++ b/cache/cache_redis_cluster_test.go @@ -91,6 +91,29 @@ func TestCacheRedisCluster(t *testing.T) { assert.Nil(t, err) }) + t.Run("ExistsHasError", func(t *testing.T) { + defer miniRedis.SetError("") + + key := "123-5-1" + ttl := 5 * time.Second + + res, err := redisCache.Set(ctx, key, "1", ttl) + + assert.Equal(t, "OK", res) + assert.Nil(t, err) + + exists, err := redisCache.Exists(ctx, fmt.Sprintf("test-%s", key)) + + assert.Equal(t, int64(0), exists) + assert.Nil(t, err) + + miniRedis.SetError("error") + exists, err = redisCache.Exists(ctx, key) + + assert.Equal(t, int64(0), exists) + assert.Error(t, err) + }) + t.Run("Delete", func(t *testing.T) { key := "123-6" ttl := 5 * time.Second @@ -110,4 +133,22 @@ func TestCacheRedisCluster(t *testing.T) { assert.Equal(t, int64(0), exists) assert.Nil(t, err) }) + + t.Run("DeleteHasError", func(t *testing.T) { + defer miniRedis.SetError("") + + key := "123-6-1" + ttl := 5 * time.Second + + res, err := redisCache.Set(ctx, key, "1", ttl) + + assert.Equal(t, "OK", res) + assert.Nil(t, err) + + miniRedis.SetError("error") + exists, err := redisCache.Del(ctx, key) + + assert.Equal(t, int64(0), exists) + assert.Error(t, err) + }) } From 8c733e048c130b5240e4a910ab66a75f72c51eb4 Mon Sep 17 00:00:00 2001 From: Ramadani Date: Wed, 11 Aug 2021 13:31:35 +0800 Subject: [PATCH 2/3] convert result to int64 --- get_cached_quota.go | 6 ++++-- get_cached_quota_test.go | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/get_cached_quota.go b/get_cached_quota.go index 9c5213e..5cb3ca6 100644 --- a/get_cached_quota.go +++ b/get_cached_quota.go @@ -24,8 +24,10 @@ func (q *getCachedQuota) Do(ctx context.Context, req *QuotaRequest) (int64, erro return 0, err } - res, _ := strconv.Atoi(val) - + res, err := strconv.Atoi(val) + if err != nil { + return 0, err + } return int64(res), nil } diff --git a/get_cached_quota_test.go b/get_cached_quota_test.go index 7bbf2fd..5920562 100644 --- a/get_cached_quota_test.go +++ b/get_cached_quota_test.go @@ -77,4 +77,19 @@ func TestGetCachedQuota(t *testing.T) { assert.Equal(t, int64(1000), res) assert.Nil(t, err) }) + + t.Run("ErrorConvertValue", func(t *testing.T) { + defer mockCtrl.Finish() + + req := &andromeda.QuotaRequest{QuotaID: "123"} + key := "123-key" + + mockGetQuotaKey.EXPECT().Do(ctx, req).Return(key, nil) + mockCache.EXPECT().Get(ctx, key).Return("lorem", nil) + + res, err := getCachedQuota.Do(ctx, req) + + assert.Equal(t, int64(0), res) + assert.NotNil(t, err) + }) } From 5f33e0ca44b012cec6aa6f83330774ca0d1d7fe5 Mon Sep 17 00:00:00 2001 From: Ramadani Date: Wed, 11 Aug 2021 13:31:49 +0800 Subject: [PATCH 3/3] create cache redis using universal client --- cache/cache_redis_universal.go | 49 ++++++++++++ cache/cache_redis_universal_test.go | 115 ++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 cache/cache_redis_universal.go create mode 100644 cache/cache_redis_universal_test.go diff --git a/cache/cache_redis_universal.go b/cache/cache_redis_universal.go new file mode 100644 index 0000000..518d5af --- /dev/null +++ b/cache/cache_redis_universal.go @@ -0,0 +1,49 @@ +package cache + +import ( + "context" + "github.com/go-redis/redis/v8" + "github.com/ramadani/andromeda" + "time" +) + +type cacheRedisUniversal struct { + client redis.UniversalClient +} + +func (c *cacheRedisUniversal) IncrBy(ctx context.Context, key string, value int64) (int64, error) { + return c.client.IncrBy(ctx, key, value).Result() +} + +func (c *cacheRedisUniversal) DecrBy(ctx context.Context, key string, decrement int64) (int64, error) { + return c.client.DecrBy(ctx, key, decrement).Result() +} + +func (c *cacheRedisUniversal) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) (string, error) { + return c.client.Set(ctx, key, value, expiration).Result() +} + +func (c *cacheRedisUniversal) Get(ctx context.Context, key string) (string, error) { + val, err := c.client.Get(ctx, key).Result() + if err == redis.Nil { + err = andromeda.ErrCacheNotFound + } + return val, err +} + +func (c *cacheRedisUniversal) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) (bool, error) { + return c.client.SetNX(ctx, key, value, expiration).Result() +} + +func (c *cacheRedisUniversal) Exists(ctx context.Context, keys ...string) (int64, error) { + return c.client.Exists(ctx, keys...).Result() +} + +func (c *cacheRedisUniversal) Del(ctx context.Context, keys ...string) (int64, error) { + return c.client.Del(ctx, keys...).Result() +} + +// NewCacheRedisUniversal cache using redis +func NewCacheRedisUniversal(client redis.UniversalClient) andromeda.Cache { + return &cacheRedisUniversal{client: client} +} diff --git a/cache/cache_redis_universal_test.go b/cache/cache_redis_universal_test.go new file mode 100644 index 0000000..73d3508 --- /dev/null +++ b/cache/cache_redis_universal_test.go @@ -0,0 +1,115 @@ +package cache_test + +import ( + "context" + "fmt" + "github.com/alicebob/miniredis/v2" + "github.com/go-redis/redis/v8" + "github.com/ramadani/andromeda" + "github.com/ramadani/andromeda/cache" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func TestCacheRedisUniversal(t *testing.T) { + ctx := context.TODO() + miniRedis, err := miniredis.Run() + assert.Nil(t, err) + + redisCache := cache.NewCacheRedisUniversal(redis.NewUniversalClient(&redis.UniversalOptions{ + Addrs: []string{miniRedis.Addr()}, + })) + + t.Run("IncrByAndDecrBy", func(t *testing.T) { + key := "123-1" + + res, err := redisCache.IncrBy(ctx, key, 1) + + assert.Equal(t, int64(1), res) + assert.Nil(t, err) + + res, err = redisCache.DecrBy(ctx, key, 1) + + assert.Equal(t, int64(0), res) + assert.Nil(t, err) + }) + + t.Run("SetAndGet", func(t *testing.T) { + key := "123-2" + ttl := 5 * time.Second + + res, err := redisCache.Set(ctx, key, "1", ttl) + + assert.Equal(t, "OK", res) + assert.Nil(t, err) + + res, err = redisCache.Get(ctx, key) + + assert.Equal(t, "1", res) + assert.Nil(t, err) + }) + + t.Run("ErrCacheNotFound", func(t *testing.T) { + key := "123-3" + res, err := redisCache.Get(ctx, key) + + assert.Equal(t, "", res) + assert.Equal(t, andromeda.ErrCacheNotFound, err) + }) + + t.Run("SetNX", func(t *testing.T) { + key := "123-4" + ttl := 5 * time.Second + + res, err := redisCache.SetNX(ctx, key, "1", ttl) + + assert.True(t, res) + assert.Nil(t, err) + + res, err = redisCache.SetNX(ctx, key, "1", ttl) + + assert.False(t, res) + assert.Nil(t, err) + }) + + t.Run("Exists", func(t *testing.T) { + key := "123-5" + ttl := 5 * time.Second + + res, err := redisCache.Set(ctx, key, "1", ttl) + + assert.Equal(t, "OK", res) + assert.Nil(t, err) + + exists, err := redisCache.Exists(ctx, key) + + assert.Equal(t, int64(1), exists) + assert.Nil(t, err) + + exists, err = redisCache.Exists(ctx, fmt.Sprintf("test-%s", key)) + + assert.Equal(t, int64(0), exists) + assert.Nil(t, err) + }) + + t.Run("Delete", func(t *testing.T) { + key := "123-6" + ttl := 5 * time.Second + + res, err := redisCache.Set(ctx, key, "1", ttl) + + assert.Equal(t, "OK", res) + assert.Nil(t, err) + + exists, err := redisCache.Del(ctx, key) + + assert.Equal(t, int64(1), exists) + assert.Nil(t, err) + + exists, err = redisCache.Del(ctx, key) + + assert.Equal(t, int64(0), exists) + assert.Nil(t, err) + }) +}