From ec7ab9cadc26bd6849ec0e8ceae195af42cb3798 Mon Sep 17 00:00:00 2001 From: yaziedda Date: Tue, 8 Oct 2024 14:22:31 +0700 Subject: [PATCH] add unit test for lib/store/redis --- store/redis/redis_test.go | 209 ++++++++++++++++++++++++++++++++++---- 1 file changed, 192 insertions(+), 17 deletions(-) diff --git a/store/redis/redis_test.go b/store/redis/redis_test.go index dba7ef75..8161a674 100644 --- a/store/redis/redis_test.go +++ b/store/redis/redis_test.go @@ -2,6 +2,7 @@ package redis import ( "context" + "fmt" "testing" "time" @@ -30,20 +31,65 @@ func TestNewRedis(t *testing.T) { func TestRedisGet(t *testing.T) { // Given ctrl := gomock.NewController(t) + defer ctrl.Finish() ctx := context.Background() client := NewMockRedisClientInterface(ctrl) - client.EXPECT().Get(ctx, "my-key").Return(&redis.StringCmd{}) - store := NewRedis(client) - // When - value, err := store.Get(ctx, "my-key") - - // Then - assert.Nil(t, err) - assert.NotNil(t, value) + tests := []struct { + name string + key string + returnVal string + returnErr error + expectErr bool + expectVal interface{} + }{ + { + name: "Returns Value", + key: "my-key", + returnVal: "value", + returnErr: nil, + expectErr: false, + expectVal: "value", + }, + { + name: "Key Not Found", + key: "non-existent-key", + returnVal: "", + returnErr: redis.Nil, + expectErr: true, + expectVal: nil, + }, + { + name: "Return Error", + key: "my-key", + returnVal: "", + returnErr: fmt.Errorf("some error"), + expectErr: true, + expectVal: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Given: mock the Redis client's Get method + client.EXPECT().Get(ctx, tt.key).Return(redis.NewStringResult(tt.returnVal, tt.returnErr)) + + // When + value, err := store.Get(ctx, tt.key) + + // Then + if tt.expectErr { + assert.Error(t, err) + assert.Equal(t, tt.expectVal, value) + } else { + assert.Nil(t, err) + assert.Equal(t, tt.expectVal, value) + } + }) + } } func TestRedisSet(t *testing.T) { @@ -153,21 +199,53 @@ func TestRedisInvalidate(t *testing.T) { } func TestRedisClear(t *testing.T) { - // Given ctrl := gomock.NewController(t) + defer ctrl.Finish() ctx := context.Background() - client := NewMockRedisClientInterface(ctrl) - client.EXPECT().FlushAll(ctx).Return(&redis.StatusCmd{}) - store := NewRedis(client) - // When - err := store.Clear(ctx) - - // Then - assert.Nil(t, err) + tests := []struct { + name string + returnValue *redis.StatusCmd + returnError error + expectError bool + expectedError string + }{ + { + name: "Successfully clears data", + returnValue: &redis.StatusCmd{}, + returnError: nil, + expectError: false, + }, + { + name: "Returns error on failure", + returnValue: redis.NewStatusResult("", fmt.Errorf("flush error")), + returnError: nil, + expectError: true, + expectedError: "flush error", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.expectError { + client.EXPECT().FlushAll(ctx).Return(tt.returnValue).Times(1) + } else { + client.EXPECT().FlushAll(ctx).Return(tt.returnValue).Times(1) + } + + err := store.Clear(ctx) + + if tt.expectError { + assert.Error(t, err) + assert.Equal(t, tt.expectedError, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } } func TestRedisGetType(t *testing.T) { @@ -181,3 +259,100 @@ func TestRedisGetType(t *testing.T) { // When - Then assert.Equal(t, RedisType, store.GetType()) } + +func TestRedisGetWithTTL(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ctx := context.Background() + client := NewMockRedisClientInterface(ctrl) + store := NewRedis(client) + + t.Run("Returns Value and TTL", func(t *testing.T) { + testReturnsValueAndTTL(t, ctx, client, store) + }) + + t.Run("Key Not Found", func(t *testing.T) { + testKeyNotFound(t, ctx, client, store) + }) + + t.Run("Get Error", func(t *testing.T) { + testGetError(t, ctx, client, store) + }) + + t.Run("TTL Fetch Error", func(t *testing.T) { + testTTLFetchError(t, ctx, client, store) + }) +} + +func testReturnsValueAndTTL(t *testing.T, ctx context.Context, client *MockRedisClientInterface, store *RedisStore) { + // Given + key := "my-key" + returnValue := "value" + returnTTL := 10 * time.Second + client.EXPECT(). + Get(ctx, key). + Return(redis.NewStringResult(returnValue, nil)) + client.EXPECT(). + TTL(ctx, key). + Return(redis.NewDurationResult(returnTTL, nil)) + + // When + value, ttl, err := store.GetWithTTL(ctx, key) + + // Then + assert.NoError(t, err) + assert.Equal(t, returnValue, value) + assert.Equal(t, returnTTL, ttl) +} + +func testKeyNotFound(t *testing.T, ctx context.Context, client *MockRedisClientInterface, store *RedisStore) { + // Given + key := "non-existent-key" + client.EXPECT(). + Get(ctx, key). + Return(redis.NewStringResult("", redis.Nil)) + + // When + value, ttl, err := store.GetWithTTL(ctx, key) + + // Then + assert.Error(t, err) + assert.Nil(t, value) + assert.Equal(t, 0*time.Second, ttl) +} + +func testGetError(t *testing.T, ctx context.Context, client *MockRedisClientInterface, store *RedisStore) { + // Given + key := "my-key" + client.EXPECT(). + Get(ctx, key). + Return(redis.NewStringResult("", fmt.Errorf("some error"))) + + // When + value, ttl, err := store.GetWithTTL(ctx, key) + + // Then + assert.Error(t, err) + assert.Equal(t, nil, value) + assert.Equal(t, 0*time.Second, ttl) +} + +func testTTLFetchError(t *testing.T, ctx context.Context, client *MockRedisClientInterface, store *RedisStore) { + // Given + key := "my-key" + client.EXPECT(). + Get(ctx, key). + Return(redis.NewStringResult("", nil)) + client.EXPECT(). + TTL(ctx, key). + Return(redis.NewDurationResult(0, fmt.Errorf("ttl error"))) + + // When + value, ttl, err := store.GetWithTTL(ctx, key) + + // Then + assert.Error(t, err) + assert.Equal(t, nil, value) + assert.Equal(t, 0*time.Second, ttl) +}