summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2020-12-21 13:14:42 +0300
committerValery Piashchynski <[email protected]>2020-12-21 13:14:42 +0300
commite7a62f19155bbba9ac17527e2abb30d31c632655 (patch)
treef060dbd61f0dc0d1093937eced738bd6aead1373
parentb403dd170bf3dc3ce451ba4ada40dd55773b032a (diff)
Finish redis plugin
-rw-r--r--.github/workflows/build.yml2
-rwxr-xr-x.rr.yaml74
-rwxr-xr-xMakefile1
-rwxr-xr-xgo.mod1
-rwxr-xr-xgo.sum11
-rwxr-xr-xinterfaces/config/interface.go3
-rw-r--r--interfaces/redis/interface.go7
-rwxr-xr-xplugins/config/plugin.go29
-rw-r--r--plugins/redis/config.go36
-rw-r--r--plugins/redis/plugin.go63
-rw-r--r--plugins/redis/tests/configs/.rr-redis.yaml25
-rw-r--r--plugins/redis/tests/plugin1.go43
-rw-r--r--plugins/redis/tests/redis_plugin_test.go124
-rw-r--r--plugins/redis/tests/redis_plugin_tests.go1
14 files changed, 336 insertions, 84 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7c52c346..51c49af7 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -85,6 +85,7 @@ jobs:
go test -v -race -cover -tags=debug ./plugins/static/tests
go test -v -race -cover -tags=debug ./plugins/static
go test -v -race -cover -tags=debug ./plugins/headers/tests
+ go test -v -race -cover -tags=debug ./plugins/redis/tests
go test -v -race -cover -tags=debug ./plugins/checker/tests
- name: Run golang tests on Linux and MacOS
@@ -112,6 +113,7 @@ jobs:
go test -v -race -cover -tags=debug -coverprofile=./coverage-ci/static_root.txt -covermode=atomic ./plugins/static
go test -v -race -cover -tags=debug -coverprofile=./coverage-ci/headers.txt -covermode=atomic ./plugins/headers/tests
go test -v -race -cover -tags=debug -coverprofile=./coverage-ci/checker.txt -covermode=atomic ./plugins/checker/tests
+ go test -v -race -cover -tags=debug -coverprofile=./coverage-ci/redis.txt -covermode=atomic ./plugins/redis/tests
go test -v -race -cover -tags=debug -coverprofile=./coverage-ci/reload.txt -covermode=atomic ./plugins/reload/tests
cat ./coverage-ci/*.txt > ./coverage-ci/summary.txt
diff --git a/.rr.yaml b/.rr.yaml
index 5caff422..3e8b267d 100755
--- a/.rr.yaml
+++ b/.rr.yaml
@@ -15,7 +15,7 @@ http:
debug: true
address: 127.0.0.1:18903
maxRequestSize: 1024
- middleware: [ "" ]
+ middleware: [ "gzip", "headers" ]
uploads:
forbid: [ ".php", ".exe", ".bat" ]
trustedSubnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ]
@@ -36,4 +36,74 @@ http:
http2:
enabled: false
h2c: false
- maxConcurrentStreams: 128 \ No newline at end of file
+ maxConcurrentStreams: 128
+
+redis:
+ # UniversalClient is an abstract client which - based on the provided options -
+ # can connect to either clusters, or sentinel-backed failover instances
+ # or simple single-instance servers. This can be useful for testing
+ # cluster-specific applications locally.
+ # if the number of addrs is 1 and master_name is empty, a single-node redis Client will be returned
+
+ # if the number of Addrs is two or more, a ClusterClient will be returned
+ addrs:
+ - 'localhost:6379'
+ # if a MasterName is passed a sentinel-backed FailoverClient will be returned
+ master_name: ''
+ username: ''
+ password: ''
+ db: 0
+ sentinel_password: ''
+ route_by_latency: false
+ route_randomly: false
+ dial_timeout: 0 # accepted values [1s, 5m, 3h]
+ max_retries: 1
+ min_retry_backoff: 0 # accepted values [1s, 5m, 3h]
+ max_retry_backoff: 0 # accepted values [1s, 5m, 3h]
+ pool_size: 0
+ min_idle_conns: 0
+ max_conn_age: 0 # accepted values [1s, 5m, 3h]
+ read_timeout: 0 # accepted values [1s, 5m, 3h]
+ write_timeout: 0 # accepted values [1s, 5m, 3h]
+ pool_timeout: 0 # accepted values [1s, 5m, 3h]
+ idle_timeout: 0 # accepted values [1s, 5m, 3h]
+ idle_check_freq: 0 # accepted values [1s, 5m, 3h]
+ read_only: false
+
+metrics:
+ # prometheus client address (path /metrics added automatically)
+ address: localhost:2112
+ collect:
+ app_metric:
+ type: histogram
+ help: "Custom application metric"
+ labels: [ "type" ]
+ buckets: [ 0.1, 0.2, 0.3, 1.0 ]
+ # objectives defines the quantile rank estimates with their respective
+ # absolute error [ for summary only ]
+ objectives:
+ - 1.4: 2.3
+ - 2.0: 1.4
+
+reload:
+ # sync interval
+ interval: 1s
+ # global patterns to sync
+ patterns: [ ".php" ]
+ # list of included for sync services
+ services:
+ http:
+ # recursive search for file patterns to add
+ recursive: true
+ # ignored folders
+ ignore: [ "vendor" ]
+ # service specific file pattens to sync
+ patterns: [ ".php", ".go",".md", ]
+ # directories to sync. If recursive is set to true,
+ # recursive sync will be applied only to the directories in `dirs` section
+ dirs: [ "." ]
+ rpc:
+ recursive: true
+ patterns: [ ".json" ]
+ # to include all project directories from workdir, leave `dirs` empty or add a dot "."
+ dirs: [ "" ] \ No newline at end of file
diff --git a/Makefile b/Makefile
index 1420b2c0..c216bb3d 100755
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@ test: ## Run application tests
go test -v -race -cover -tags=debug -covermode=atomic ./plugins/static/tests
go test -v -race -cover -tags=debug -covermode=atomic ./plugins/headers/tests
go test -v -race -cover -tags=debug -covermode=atomic ./plugins/checker/tests
+ go test -v -race -cover -tags=debug -covermode=atomic ./plugins/redis/tests
go test -v -race -cover -tags=debug -covermode=atomic ./plugins/reload/tests
lint: ## Run application linters
diff --git a/go.mod b/go.mod
index b19ef157..5c5d9061 100755
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.15
require (
github.com/NYTimes/gziphandler v1.1.1
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
+ github.com/alicebob/miniredis/v2 v2.14.1
github.com/fatih/color v1.10.0
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/go-redis/redis/v8 v8.4.4
diff --git a/go.sum b/go.sum
index 0718fc24..348e6043 100755
--- a/go.sum
+++ b/go.sum
@@ -29,6 +29,11 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
+github.com/alicebob/miniredis/v2 v2.14.1 h1:GjlbSeoJ24bzdLRs13HoMEeaRZx9kg5nHoRW7QV/nCs=
+github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -57,6 +62,9 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
@@ -428,6 +436,8 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yookoala/gofast v0.4.0 h1:dLBjghcsbbZNOEHN8N1X/gh9S6srmJed4WQfG7DlKwo=
github.com/yookoala/gofast v0.4.0/go.mod h1:rfbkoKaQG1bnuTUZcmV3vAlnfpF4FTq8WbQJf2vcpg8=
+github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
+github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
@@ -529,6 +539,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/interfaces/config/interface.go b/interfaces/config/interface.go
index 00010eae..2a7c67ce 100755
--- a/interfaces/config/interface.go
+++ b/interfaces/config/interface.go
@@ -14,6 +14,9 @@ type Configurer interface {
// Get used to get config section
Get(name string) interface{}
+ // Overwrite used to overwrite particular values in the unmarshalled config
+ Overwrite(values map[string]interface{}) error
+
// Has checks if config section exists.
Has(name string) bool
}
diff --git a/interfaces/redis/interface.go b/interfaces/redis/interface.go
index 61dd6c08..909c8ca4 100644
--- a/interfaces/redis/interface.go
+++ b/interfaces/redis/interface.go
@@ -2,9 +2,8 @@ package redis
import "github.com/go-redis/redis/v8"
+// Redis in the redis KV plugin interface
type Redis interface {
- GetClient() *redis.Client
- GetUniversalClient() *redis.UniversalClient
- GetClusterClient() *redis.ClusterClient
- GetSentinelClient() *redis.SentinelClient
+ // GetClient
+ GetClient() redis.UniversalClient
}
diff --git a/plugins/config/plugin.go b/plugins/config/plugin.go
index 2555d28a..b438a185 100755
--- a/plugins/config/plugin.go
+++ b/plugins/config/plugin.go
@@ -1,6 +1,7 @@
package config
import (
+ "bytes"
"errors"
"fmt"
"strings"
@@ -9,9 +10,10 @@ import (
)
type Viper struct {
- viper *viper.Viper
- Path string
- Prefix string
+ viper *viper.Viper
+ Path string
+ Prefix string
+ ReadInCfg []byte
}
// Inits config provider.
@@ -32,17 +34,16 @@ func (v *Viper) Init() error {
v.viper.SetConfigFile(v.Path)
v.viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
+ if v.ReadInCfg != nil {
+ return v.viper.ReadConfig(bytes.NewBuffer(v.ReadInCfg))
+ }
return v.viper.ReadInConfig()
}
// Overwrite overwrites existing config with provided values
-func (v *Viper) Overwrite(values map[string]string) error {
+func (v *Viper) Overwrite(values map[string]interface{}) error {
if len(values) != 0 {
- for _, flag := range values {
- key, value, err := parseFlag(flag)
- if err != nil {
- return err
- }
+ for key, value := range values {
v.viper.Set(key, value)
}
}
@@ -69,16 +70,6 @@ func (v *Viper) Has(name string) bool {
return v.viper.IsSet(name)
}
-func parseFlag(flag string) (string, string, error) {
- if !strings.Contains(flag, "=") {
- return "", "", fmt.Errorf("invalid flag `%s`", flag)
- }
-
- parts := strings.SplitN(strings.TrimLeft(flag, " \"'`"), "=", 2)
-
- return strings.Trim(parts[0], " \n\t"), parseValue(strings.Trim(parts[1], " \n\t")), nil
-}
-
func parseValue(value string) string {
escape := []rune(value)[0]
diff --git a/plugins/redis/config.go b/plugins/redis/config.go
index b39fcd00..ebcefed1 100644
--- a/plugins/redis/config.go
+++ b/plugins/redis/config.go
@@ -1,18 +1,32 @@
package redis
+import "time"
+
type Config struct {
- // Addr is address to use. If len > 1, cluster client will be used
- Addr []string
- // database number to use, 0 is used by default
- DB int
- // Master name for failover client, empty by default
- Master string
- // Redis password, empty by default
- Password string
+ Addrs []string `yaml:"addrs"`
+ DB int `yaml:"db"`
+ Username string `yaml:"username"`
+ Password string `yaml:"password"`
+ MasterName string `yaml:"master_name"`
+ SentinelPassword string `yaml:"sentinel_password"`
+ RouteByLatency bool `yaml:"route_by_latency"`
+ RouteRandomly bool `yaml:"route_randomly"`
+ MaxRetries int `yaml:"max_retries"`
+ DialTimeout time.Duration `yaml:"dial_timeout"`
+ MinRetryBackoff time.Duration `yaml:"min_retry_backoff"`
+ MaxRetryBackoff time.Duration `yaml:"max_retry_backoff"`
+ PoolSize int `yaml:"pool_size"`
+ MinIdleConns int `yaml:"min_idle_conns"`
+ MaxConnAge time.Duration `yaml:"max_conn_age"`
+ ReadTimeout time.Duration `yaml:"read_timeout"`
+ WriteTimeout time.Duration `yaml:"write_timeout"`
+ PoolTimeout time.Duration `yaml:"pool_timeout"`
+ IdleTimeout time.Duration `yaml:"idle_timeout"`
+ IdleCheckFreq time.Duration `yaml:"idle_check_freq"`
+ ReadOnly bool `yaml:"read_only"`
}
// InitDefaults initializing fill config with default values
-func (s *Config) InitDefaults() error {
- s.Addr = []string{"localhost:6379"} // default addr is pointing to local storage
- return nil
+func (s *Config) InitDefaults() {
+ s.Addrs = []string{"localhost:6379"} // default addr is pointing to local storage
}
diff --git a/plugins/redis/plugin.go b/plugins/redis/plugin.go
index 64b6024e..08bb7972 100644
--- a/plugins/redis/plugin.go
+++ b/plugins/redis/plugin.go
@@ -2,6 +2,7 @@ package redis
import (
"github.com/go-redis/redis/v8"
+ "github.com/spiral/errors"
"github.com/spiral/roadrunner/v2/interfaces/config"
"github.com/spiral/roadrunner/v2/interfaces/log"
)
@@ -11,44 +12,62 @@ const PluginName = "redis"
type Plugin struct {
// config for RR integration
cfg *Config
- // redis client
- universalClient *redis.UniversalClient
- clusterClient *redis.ClusterClient
- client *redis.Client
- sentinelClient *redis.SentinelClient
+ // logger
+ log log.Logger
+ // redis universal client
+ universalClient redis.UniversalClient
}
-func (s *Plugin) GetClient() *redis.Client {
- return s.client
-}
-
-func (s *Plugin) GetUniversalClient() *redis.UniversalClient {
+func (s *Plugin) GetClient() redis.UniversalClient {
return s.universalClient
}
-func (s *Plugin) GetClusterClient() *redis.ClusterClient {
- return s.clusterClient
-}
+func (s *Plugin) Init(cfg config.Configurer, log log.Logger) error {
+ const op = errors.Op("redis plugin init")
+ s.cfg = &Config{}
+ s.cfg.InitDefaults()
-func (s *Plugin) GetSentinelClient() *redis.SentinelClient {
- return s.sentinelClient
-}
+ err := cfg.UnmarshalKey(PluginName, &s.cfg)
+ if err != nil {
+ return errors.E(op, errors.Disabled, err)
+ }
+
+ s.log = log
+
+ s.universalClient = redis.NewUniversalClient(&redis.UniversalOptions{
+ Addrs: s.cfg.Addrs,
+ DB: s.cfg.DB,
+ Username: s.cfg.Username,
+ Password: s.cfg.Password,
+ SentinelPassword: s.cfg.SentinelPassword,
+ MaxRetries: s.cfg.MaxRetries,
+ MinRetryBackoff: s.cfg.MaxRetryBackoff,
+ MaxRetryBackoff: s.cfg.MaxRetryBackoff,
+ DialTimeout: s.cfg.DialTimeout,
+ ReadTimeout: s.cfg.ReadTimeout,
+ WriteTimeout: s.cfg.WriteTimeout,
+ PoolSize: s.cfg.PoolSize,
+ MinIdleConns: s.cfg.MinIdleConns,
+ MaxConnAge: s.cfg.MaxConnAge,
+ PoolTimeout: s.cfg.PoolTimeout,
+ IdleTimeout: s.cfg.IdleTimeout,
+ IdleCheckFrequency: s.cfg.IdleCheckFreq,
+ ReadOnly: s.cfg.ReadOnly,
+ RouteByLatency: s.cfg.RouteByLatency,
+ RouteRandomly: s.cfg.RouteRandomly,
+ MasterName: s.cfg.MasterName,
+ })
-func (s *Plugin) Init(cfg config.Configurer, log log.Logger) error {
- _ = cfg
- _ = log
- _ = s.cfg
return nil
}
func (s *Plugin) Serve() chan error {
errCh := make(chan error, 1)
-
return errCh
}
func (s Plugin) Stop() error {
- return nil
+ return s.universalClient.Close()
}
func (s *Plugin) Name() string {
diff --git a/plugins/redis/tests/configs/.rr-redis.yaml b/plugins/redis/tests/configs/.rr-redis.yaml
deleted file mode 100644
index 52198a35..00000000
--- a/plugins/redis/tests/configs/.rr-redis.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-redis:
- - cluster:
- addr:
- - 'localhost:6379'
- db: 0
- master: null
- password: ''
- - universal:
- addr:
- - 'localhost:6379'
- db: 0
- master: null
- password: ''
- - default:
- addr:
- - 'localhost:6379'
- db: 0
- master: null
- password: ''
- - sentinel:
- addr:
- - 'localhost:6379'
- db: 0
- master: null
- password: '' \ No newline at end of file
diff --git a/plugins/redis/tests/plugin1.go b/plugins/redis/tests/plugin1.go
new file mode 100644
index 00000000..e19ca90a
--- /dev/null
+++ b/plugins/redis/tests/plugin1.go
@@ -0,0 +1,43 @@
+package tests
+
+import (
+ "context"
+ "time"
+
+ "github.com/go-redis/redis/v8"
+ "github.com/spiral/errors"
+ redisPlugin "github.com/spiral/roadrunner/v2/interfaces/redis"
+)
+
+type Plugin1 struct {
+ redisClient redis.UniversalClient
+}
+
+func (p *Plugin1) Init(redis redisPlugin.Redis) error {
+ p.redisClient = redis.GetClient()
+ return nil
+}
+
+func (p *Plugin1) Serve() chan error {
+ const op = errors.Op("plugin1 serve")
+ errCh := make(chan error, 1)
+ p.redisClient.Set(context.Background(), "foo", "bar", time.Minute)
+
+ stringCmd := p.redisClient.Get(context.Background(), "foo")
+ data, err := stringCmd.Result()
+ if err != nil {
+ errCh <- errors.E(op, err)
+ return errCh
+ }
+
+ if data != "bar" {
+ errCh <- errors.E(op, errors.Str("no such key"))
+ return errCh
+ }
+
+ return errCh
+}
+
+func (p *Plugin1) Stop() error {
+ return p.redisClient.Close()
+}
diff --git a/plugins/redis/tests/redis_plugin_test.go b/plugins/redis/tests/redis_plugin_test.go
new file mode 100644
index 00000000..8f8da983
--- /dev/null
+++ b/plugins/redis/tests/redis_plugin_test.go
@@ -0,0 +1,124 @@
+package tests
+
+import (
+ "fmt"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+ "testing"
+ "time"
+
+ "github.com/alicebob/miniredis/v2"
+ "github.com/golang/mock/gomock"
+ "github.com/spiral/endure"
+ "github.com/spiral/roadrunner/v2/mocks"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+ "github.com/spiral/roadrunner/v2/plugins/redis"
+ "github.com/stretchr/testify/assert"
+)
+
+func redisConfig(port string) string {
+ cfg := `
+redis:
+ addrs:
+ - 'localhost:%s'
+ master_name: ''
+ username: ''
+ password: ''
+ db: 0
+ sentinel_password: ''
+ route_by_latency: false
+ route_randomly: false
+ dial_timeout: 0
+ max_retries: 1
+ min_retry_backoff: 0
+ max_retry_backoff: 0
+ pool_size: 0
+ min_idle_conns: 0
+ max_conn_age: 0
+ read_timeout: 0
+ write_timeout: 0
+ pool_timeout: 0
+ idle_timeout: 0
+ idle_check_freq: 0
+ read_only: false
+`
+ return fmt.Sprintf(cfg, port)
+}
+
+func TestRedisInit(t *testing.T) {
+ cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ s, err := miniredis.Run()
+ if err != nil {
+ panic(err)
+ }
+ defer s.Close()
+
+ c := redisConfig(s.Port())
+
+ cfg := &config.Viper{}
+ cfg.Prefix = "rr"
+ cfg.Path = ".rr-redis.yaml"
+ cfg.ReadInCfg = []byte(c)
+
+ controller := gomock.NewController(t)
+ mockLogger := mocks.NewMockLogger(controller)
+
+ err = cont.RegisterAll(
+ cfg,
+ mockLogger,
+ &redis.Plugin{},
+ &Plugin1{},
+ )
+ assert.NoError(t, err)
+
+ err = cont.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ch, err := cont.Serve()
+ assert.NoError(t, err)
+
+ sig := make(chan os.Signal, 1)
+ signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+
+ wg := &sync.WaitGroup{}
+ wg.Add(1)
+
+ tt := time.NewTimer(time.Second * 10)
+
+ go func() {
+ defer wg.Done()
+ for {
+ select {
+ case e := <-ch:
+ assert.Fail(t, "error", e.Error.Error())
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ case <-sig:
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ return
+ case <-tt.C:
+ // timeout
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ return
+ }
+ }
+ }()
+
+ wg.Wait()
+}
diff --git a/plugins/redis/tests/redis_plugin_tests.go b/plugins/redis/tests/redis_plugin_tests.go
deleted file mode 100644
index ca8701d2..00000000
--- a/plugins/redis/tests/redis_plugin_tests.go
+++ /dev/null
@@ -1 +0,0 @@
-package tests