Repository: beatlabs/harvester
Pull request #88 (2021-06-11 11:56:52)

Use redis universal client instead of a concrete type
<!--
Thanks for taking precious time for making a PR.

Before creating a pull request, please make sure:
- Your PR solves one problem for which a issue exist and a solution has been discussed
- You have read the guide for contributing
  - See https://github.com/beatlabs/harvester/blob/master/CONTRIBUTE.md
- You signed all your commits (otherwise we won't be able to merge the PR)
  - See https://github.com/beatlabs/harvester/blob/master/SIGNYOURWORK.md
- You added unit tests for the new functionality
- You mention in the PR description which issue it is addressing, e.g. "Resolves #123"
-->

## Which problem is this PR solving?

Current implementation of the redis seeder/watcher requires a concrete implementation of the redis client. It does not allow developers to use other clients, e.g. `ClusterClient` or `SentinelClient`. 

To resolve this limitation, the library should consume and use internally existing `redis.UniversalClient` interface abstraction.

## Short description of the changes

Replaces concrete redis client struct with interface.



Patch:
diff --git a/harvester.go b/harvester.go
index 629344b..a2f81e5 100644
--- a/harvester.go
+++ b/harvester.go
@@ -61,8 +61,8 @@ type Builder struct {
 	monitorConsulCfg         *consulConfig
 	err                      error
 	chNotify                 chan<- config.ChangeNotification
-	monitorRedisClient       *redis.Client
-	seedRedisClient          *redis.Client
+	monitorRedisClient       redis.UniversalClient
+	seedRedisClient          redis.UniversalClient
 	monitorRedisPollInterval time.Duration
 }
 
@@ -114,7 +114,7 @@ func (b *Builder) WithConsulMonitor(addr, dataCenter, token string, timeout time
 }
 
 // WithRedisSeed enables support for seeding values with redis.
-func (b *Builder) WithRedisSeed(client *redis.Client) *Builder {
+func (b *Builder) WithRedisSeed(client redis.UniversalClient) *Builder {
 	if b.err != nil {
 		return b
 	}
@@ -128,7 +128,7 @@ func (b *Builder) WithRedisSeed(client *redis.Client) *Builder {
 
 // WithRedisMonitor enables support for monitoring keys in Redis. It automatically parses the config
 // and monitors every field found tagged with ConsulLogger.
-func (b *Builder) WithRedisMonitor(client *redis.Client, pollInterval time.Duration) *Builder {
+func (b *Builder) WithRedisMonitor(client redis.UniversalClient, pollInterval time.Duration) *Builder {
 	if b.err != nil {
 		return b
 	}
diff --git a/monitor/redis/watcher.go b/monitor/redis/watcher.go
index f3d245c..367d0cb 100644
--- a/monitor/redis/watcher.go
+++ b/monitor/redis/watcher.go
@@ -14,13 +14,13 @@ import (
 
 // Watcher of Redis changes.
 type Watcher struct {
-	client       *redis.Client
+	client       redis.UniversalClient
 	keys         []string
 	pollInterval time.Duration
 }
 
 // New watcher.
-func New(client *redis.Client, pollInterval time.Duration, keys []string) (*Watcher, error) {
+func New(client redis.UniversalClient, pollInterval time.Duration, keys []string) (*Watcher, error) {
 	if client == nil {
 		return nil, errors.New("client is nil")
 	}
diff --git a/seed/redis/getter.go b/seed/redis/getter.go
index 1449e16..6095052 100644
--- a/seed/redis/getter.go
+++ b/seed/redis/getter.go
@@ -10,11 +10,11 @@ import (
 
 // Getter definition.
 type Getter struct {
-	client *redis.Client
+	client redis.UniversalClient
 }
 
 // New creates a getter.
-func New(client *redis.Client) (*Getter, error) {
+func New(client redis.UniversalClient) (*Getter, error) {
 	if client == nil {
 		return nil, errors.New("client is nil")
 	}


Test patch:
diff --git a/harvester_test.go b/harvester_test.go
index c0a8709..a27e814 100644
--- a/harvester_test.go
+++ b/harvester_test.go
@@ -20,8 +20,8 @@ func TestCreateWithConsulAndRedis(t *testing.T) {
 	type args struct {
 		cfg                    interface{}
 		consulAddress          string
-		seedRedisClient        *redis.Client
-		monitorRedisClient     *redis.Client
+		seedRedisClient        redis.UniversalClient
+		monitorRedisClient     redis.UniversalClient
 		monitoringPollInterval time.Duration
 	}
 	tests := map[string]struct {
diff --git a/monitor/redis/watcher_integration_test.go b/monitor/redis/watcher_integration_test.go
index 9eb6b37..080b31a 100644
--- a/monitor/redis/watcher_integration_test.go
+++ b/monitor/redis/watcher_integration_test.go
@@ -63,13 +63,13 @@ func TestWatch(t *testing.T) {
 	}
 }
 
-func set(t *testing.T, client *redis.Client, key string, val string) {
+func set(t *testing.T, client redis.UniversalClient, key string, val string) {
 	getResult, err := client.Set(context.Background(), key, val, 0).Result()
 	require.NoError(t, err)
 	require.Equal(t, "OK", getResult)
 }
 
-func del(t *testing.T, client *redis.Client, key string) {
+func del(t *testing.T, client redis.UniversalClient, key string) {
 	delResult, err := client.Del(context.Background(), key).Result()
 	require.NoError(t, err)
 	require.Equal(t, int64(1), delResult)
diff --git a/monitor/redis/watcher_test.go b/monitor/redis/watcher_test.go
index ce267d6..80c9778 100644
--- a/monitor/redis/watcher_test.go
+++ b/monitor/redis/watcher_test.go
@@ -13,7 +13,7 @@ import (
 
 func TestNew(t *testing.T) {
 	type args struct {
-		client       *redis.Client
+		client       redis.UniversalClient
 		pollInterval time.Duration
 		keys         []string
 	}
diff --git a/seed/redis/getter_test.go b/seed/redis/getter_test.go
index ebdcd33..7920bd4 100644
--- a/seed/redis/getter_test.go
+++ b/seed/redis/getter_test.go
@@ -9,7 +9,7 @@ import (
 
 func TestNew(t *testing.T) {
 	type args struct {
-		client *redis.Client
+		client redis.UniversalClient
 	}
 	tests := map[string]struct {
 		args        args