diff --git a/.github/workflows/test-redis.yml b/.github/workflows/test-redis.yml index a4e58b6f..f95852fb 100644 --- a/.github/workflows/test-redis.yml +++ b/.github/workflows/test-redis.yml @@ -66,6 +66,9 @@ jobs: slave3-port: 7005 sleep-duration: 10 + - name: Wait for Redis to Start + run: sleep 15 + - name: Install Go uses: actions/setup-go@v4 with: diff --git a/redis/README.md b/redis/README.md index f546d21b..aae925bc 100644 --- a/redis/README.md +++ b/redis/README.md @@ -29,6 +29,7 @@ func (s *Storage) Delete(key string) error func (s *Storage) Reset() error func (s *Storage) Close() error func (s *Storage) Conn() redis.UniversalClient +func (s *Storage) Keys() ([][]byte, error) ``` ### Installation Redis is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet: diff --git a/redis/redis.go b/redis/redis.go index c61f37c7..eff32227 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -74,8 +74,6 @@ func New(config ...Config) *Storage { } } -// ... - // Get value by key func (s *Storage) Get(key string) ([]byte, error) { if len(key) <= 0 { @@ -118,3 +116,32 @@ func (s *Storage) Close() error { func (s *Storage) Conn() redis.UniversalClient { return s.db } + +// Return all the keys +func (s *Storage) Keys() ([][]byte, error) { + var keys [][]byte + var cursor uint64 + var err error + + for { + var batch []string + + if batch, cursor, err = s.db.Scan(context.Background(), cursor, "*", 10).Result(); err != nil { + return nil, err + } + + for _, key := range batch { + keys = append(keys, []byte(key)) + } + + if cursor == 0 { + break + } + } + + if len(keys) == 0 { + return nil, nil + } + + return keys, nil +} diff --git a/redis/redis_test.go b/redis/redis_test.go index 42aca367..96beaa5e 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -9,12 +9,11 @@ import ( "github.com/stretchr/testify/require" ) -var testStore = New(Config{ - Reset: true, -}) - func Test_Redis_Set(t *testing.T) { var ( + testStore = New(Config{ + Reset: true, + }) key = "john" val = []byte("doe") ) @@ -25,6 +24,9 @@ func Test_Redis_Set(t *testing.T) { func Test_Redis_Set_Override(t *testing.T) { var ( + testStore = New(Config{ + Reset: true, + }) key = "john" val = []byte("doe") ) @@ -34,10 +36,17 @@ func Test_Redis_Set_Override(t *testing.T) { err = testStore.Set(key, val, 0) require.NoError(t, err) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) } func Test_Redis_Get(t *testing.T) { var ( + testStore = New(Config{ + Reset: true, + }) key = "john" val = []byte("doe") ) @@ -48,10 +57,17 @@ func Test_Redis_Get(t *testing.T) { result, err := testStore.Get(key) require.NoError(t, err) require.Equal(t, val, result) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 1) } -func Test_Redis_Set_Expiration(t *testing.T) { +func Test_Redis_Expiration(t *testing.T) { var ( + testStore = New(Config{ + Reset: true, + }) key = "john" val = []byte("doe") exp = 1 * time.Second @@ -61,17 +77,20 @@ func Test_Redis_Set_Expiration(t *testing.T) { require.NoError(t, err) time.Sleep(1100 * time.Millisecond) -} - -func Test_Redis_Get_Expired(t *testing.T) { - key := "john" result, err := testStore.Get(key) require.NoError(t, err) require.Zero(t, len(result)) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Redis_Get_NotExist(t *testing.T) { + testStore := New(Config{ + Reset: true, + }) result, err := testStore.Get("notexist") require.NoError(t, err) require.Zero(t, len(result)) @@ -79,6 +98,9 @@ func Test_Redis_Get_NotExist(t *testing.T) { func Test_Redis_Delete(t *testing.T) { var ( + testStore = New(Config{ + Reset: true, + }) key = "john" val = []byte("doe") ) @@ -92,9 +114,16 @@ func Test_Redis_Delete(t *testing.T) { result, err := testStore.Get(key) require.NoError(t, err) require.Zero(t, len(result)) + + keys, err := testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Redis_Reset(t *testing.T) { + testStore := New(Config{ + Reset: true, + }) val := []byte("doe") err := testStore.Set("john1", val, 0) @@ -103,6 +132,10 @@ func Test_Redis_Reset(t *testing.T) { err = testStore.Set("john2", val, 0) require.NoError(t, err) + keys, err := testStore.Keys() + require.NoError(t, err) + require.Len(t, keys, 2) + err = testStore.Reset() require.NoError(t, err) @@ -113,13 +146,23 @@ func Test_Redis_Reset(t *testing.T) { result, err = testStore.Get("john2") require.NoError(t, err) require.Zero(t, len(result)) + + keys, err = testStore.Keys() + require.NoError(t, err) + require.Nil(t, keys) } func Test_Redis_Close(t *testing.T) { + testStore := New(Config{ + Reset: true, + }) require.Nil(t, testStore.Close()) } func Test_Redis_Conn(t *testing.T) { + testStore := New(Config{ + Reset: true, + }) require.True(t, testStore.Conn() != nil) } @@ -184,6 +227,10 @@ func Test_Redis_Initalize_WithURL_TLS(t *testing.T) { err = testStoreUrl.Delete(key) require.NoError(t, err) + keys, err := testStoreUrl.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUrl.Close()) } @@ -226,6 +273,10 @@ func Test_Redis_Initalize_WithURL_TLS_Verify(t *testing.T) { err = testStoreUrl.Delete(key) require.NoError(t, err) + keys, err := testStoreUrl.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUrl.Close()) } @@ -249,6 +300,10 @@ func Test_Redis_Initalize_With_Secure_URL(t *testing.T) { err = testStoreUrl.Delete(key) require.NoError(t, err) + keys, err := testStoreUrl.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUrl.Close()) } @@ -273,6 +328,10 @@ func Test_Redis_Universal_Addrs(t *testing.T) { err = testStoreUniversal.Delete(key) require.NoError(t, err) + keys, err := testStoreUniversal.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUniversal.Close()) } @@ -299,6 +358,10 @@ func Test_Redis_Universal_With_URL_Undefined(t *testing.T) { err = testStoreUniversal.Delete(key) require.NoError(t, err) + keys, err := testStoreUniversal.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUniversal.Close()) } @@ -325,6 +388,10 @@ func Test_Redis_Universal_With_URL_Defined(t *testing.T) { err = testStoreUniversal.Delete(key) require.NoError(t, err) + keys, err := testStoreUniversal.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUniversal.Close()) } @@ -352,6 +419,10 @@ func Test_Redis_Universal_With_HostPort(t *testing.T) { err = testStoreUniversal.Delete(key) require.NoError(t, err) + keys, err := testStoreUniversal.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUniversal.Close()) } @@ -380,6 +451,10 @@ func Test_Redis_Universal_With_HostPort_And_URL(t *testing.T) { err = testStoreUniversal.Delete(key) require.NoError(t, err) + keys, err := testStoreUniversal.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUniversal.Close()) } @@ -410,10 +485,17 @@ func Test_Redis_Cluster(t *testing.T) { err = testStoreUniversal.Delete(key) require.NoError(t, err) + keys, err := testStoreUniversal.Keys() + require.NoError(t, err) + require.Nil(t, keys) + require.Nil(t, testStoreUniversal.Close()) } func Benchmark_Redis_Set(b *testing.B) { + testStore := New(Config{ + Reset: true, + }) b.ReportAllocs() b.ResetTimer() @@ -426,6 +508,9 @@ func Benchmark_Redis_Set(b *testing.B) { } func Benchmark_Redis_Get(b *testing.B) { + testStore := New(Config{ + Reset: true, + }) err := testStore.Set("john", []byte("doe"), 0) require.NoError(b, err) @@ -440,6 +525,9 @@ func Benchmark_Redis_Get(b *testing.B) { } func Benchmark_Redis_SetAndDelete(b *testing.B) { + testStore := New(Config{ + Reset: true, + }) b.ReportAllocs() b.ResetTimer()