From 161c60fcf4b94bd1f9196e2708ce188b11cec659 Mon Sep 17 00:00:00 2001 From: camba1 Date: Mon, 6 Jul 2020 07:59:32 -0500 Subject: [PATCH] Added ability to use username and password in Redis url (#572) * Added ability to use username and password in the url used to access redis. Upgraded redis client from 5 to 7. * Commented out the test that tried to write to the redis instance and thus caused automated test to fail * Added code to skip test_Store test during automated CI run Co-authored-by: Juan Peredo --- go.mod | 3 +- go.sum | 12 ++++- redis.go | 25 +++++++---- redis_test.go | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 12 deletions(-) create mode 100644 redis_test.go diff --git a/go.mod b/go.mod index 495fb96..1b2e91f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/micro/go-plugins/store/redis/v2 go 1.13 require ( + github.com/go-redis/redis/v7 v7.4.0 github.com/micro/go-micro/v2 v2.8.0 - gopkg.in/redis.v5 v5.2.9 + gopkg.in/yaml.v2 v2.2.7 // indirect ) diff --git a/go.sum b/go.sum index 9d21b6b..8f40eb3 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,8 @@ github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= +github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= @@ -177,6 +179,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -308,8 +311,12 @@ github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXW github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -507,6 +514,7 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= @@ -602,8 +610,6 @@ gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdOD gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= -gopkg.in/redis.v5 v5.2.9 h1:MNZYOLPomQzZMfpN3ZtD1uyJ2IDonTTlxYiV/pEApiw= -gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY= gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= @@ -620,6 +626,8 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/redis.go b/redis.go index feffe62..ba641f1 100644 --- a/redis.go +++ b/redis.go @@ -3,9 +3,9 @@ package redis import ( "fmt" + "github.com/go-redis/redis/v7" log "github.com/micro/go-micro/v2/logger" "github.com/micro/go-micro/v2/store" - redis "gopkg.in/redis.v5" ) type rkv struct { @@ -39,8 +39,8 @@ func (r *rkv) Read(key string, opts ...store.ReadOption) ([]*store.Record, error // Handle Prefix // TODO suffix if options.Prefix { - prefix_key := fmt.Sprintf("%s*", rkey) - fkeys, err := r.Client.Keys(prefix_key).Result() + prefixKey := fmt.Sprintf("%s*", rkey) + fkeys, err := r.Client.Keys(prefixKey).Result() if err != nil { return nil, err } @@ -147,17 +147,24 @@ func NewStore(opts ...store.Option) store.Store { } func (r *rkv) configure() error { + var redisOptions *redis.Options nodes := r.options.Nodes if len(nodes) == 0 { - nodes = []string{"127.0.0.1:6379"} + nodes = []string{"redis://127.0.0.1:6379"} } - r.Client = redis.NewClient(&redis.Options{ - Addr: nodes[0], - Password: "", // no password set - DB: 0, // use default DB - }) + redisOptions, err := redis.ParseURL(nodes[0]) + if err != nil { + //Backwards compatibility + redisOptions = &redis.Options{ + Addr: nodes[0], + Password: "", // no password set + DB: 0, // use default DB + } + } + + r.Client = redis.NewClient(redisOptions) return nil } diff --git a/redis_test.go b/redis_test.go new file mode 100644 index 0000000..87145a8 --- /dev/null +++ b/redis_test.go @@ -0,0 +1,122 @@ +package redis + +import ( + "github.com/go-redis/redis/v7" + "github.com/micro/go-micro/v2/store" + "os" + "testing" + "time" +) + +func Test_rkv_configure(t *testing.T) { + type fields struct { + options store.Options + Client *redis.Client + } + type wantValues struct { + username string + password string + address string + } + + tests := []struct { + name string + fields fields + wantErr bool + want wantValues + }{ + {name: "No Url", fields: fields{options: store.Options{}, Client: nil}, + wantErr: false, want: wantValues{ + username: "", + password: "", + address: "127.0.0.1:6379", + }}, + {name: "legacy Url", fields: fields{options: store.Options{Nodes: []string{"127.0.0.1:6379"}}, Client: nil}, + wantErr: false, want: wantValues{ + username: "", + password: "", + address: "127.0.0.1:6379", + }}, + {name: "New Url", fields: fields{options: store.Options{Nodes: []string{"redis://127.0.0.1:6379"}}, Client: nil}, + wantErr: false, want: wantValues{ + username: "", + password: "", + address: "127.0.0.1:6379", + }}, + {name: "Url with Pwd", fields: fields{options: store.Options{Nodes: []string{"redis://:password@redis:6379"}}, Client: nil}, + wantErr: false, want: wantValues{ + username: "", + password: "password", + address: "redis:6379", + }}, + {name: "Url with username and Pwd", fields: fields{options: store.Options{Nodes: []string{"redis://username:password@redis:6379"}}, Client: nil}, + wantErr: false, want: wantValues{ + username: "username", + password: "password", + address: "redis:6379", + }}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &rkv{ + options: tt.fields.options, + Client: tt.fields.Client, + } + err := r.configure() + if (err != nil) != tt.wantErr { + t.Errorf("configure() error = %v, wantErr %v", err, tt.wantErr) + return + } + if r.Client.Options().Addr != tt.want.address { + t.Errorf("configure() Address = %v, want address %v", r.Client.Options().Addr, tt.want.address) + } + if r.Client.Options().Password != tt.want.password { + t.Errorf("configure() password = %v, want password %v", r.Client.Options().Password, tt.want.password) + } + if r.Client.Options().Username != tt.want.username { + t.Errorf("configure() username = %v, want username %v", r.Client.Options().Username, tt.want.username) + } + + }) + } +} + +func Test_Store(t *testing.T) { + if tr := os.Getenv("TRAVIS"); len(tr) > 0 { + t.Skip() + } + r := new(rkv) + + //r.options = store.Options{Nodes: []string{"redis://:password@127.0.0.1:6379"}} + //r.options = store.Options{Nodes: []string{"127.0.0.1:6379"}} + r.options = store.Options{Nodes: []string{"redis://127.0.0.1:6379"}} + + if err := r.configure(); err != nil { + t.Error(err) + return + } + + key := "myTest" + rec := store.Record{ + Key: key, + Value: []byte("myValue"), + Expiry: 2 * time.Minute, + } + + err := r.Write(&rec) + if err != nil { + t.Errorf("Write Erroe. Error: %v", err) + } + rec1, err := r.Read(key) + if err != nil { + t.Errorf("Read Error. Error: %v\n", err) + } + err = r.Delete(rec1[0].Key) + if err != nil { + t.Errorf("Delete error %v\n", err) + } + _, err = r.List() + if err != nil { + t.Errorf("listing error %v\n", err) + } +}