From d54e848055afe1ba941931048087fb043a02aa58 Mon Sep 17 00:00:00 2001 From: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> Date: Wed, 30 Apr 2025 09:33:40 +0300 Subject: [PATCH] feat(options): panic when options are nil (#3363) Client creation should panic when options are nil. --- osscluster.go | 3 +++ redis.go | 3 +++ redis_test.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ ring.go | 3 +++ sentinel.go | 11 +++++++++++ universal.go | 4 ++++ 6 files changed, 75 insertions(+) diff --git a/osscluster.go b/osscluster.go index 3b46cbe3..c0278ed0 100644 --- a/osscluster.go +++ b/osscluster.go @@ -924,6 +924,9 @@ type ClusterClient struct { // NewClusterClient returns a Redis Cluster client as described in // http://redis.io/topics/cluster-spec. func NewClusterClient(opt *ClusterOptions) *ClusterClient { + if opt == nil { + panic("redis: NewClusterClient nil options") + } opt.init() c := &ClusterClient{ diff --git a/redis.go b/redis.go index e0159294..f50df568 100644 --- a/redis.go +++ b/redis.go @@ -661,6 +661,9 @@ type Client struct { // NewClient returns a client to the Redis Server specified by Options. func NewClient(opt *Options) *Client { + if opt == nil { + panic("redis: NewClient nil options") + } opt.init() c := Client{ diff --git a/redis_test.go b/redis_test.go index 7d9bf1ce..80e28341 100644 --- a/redis_test.go +++ b/redis_test.go @@ -727,3 +727,54 @@ var _ = Describe("Dialer connection timeouts", func() { Expect(time.Since(start)).To(BeNumerically("<", 2*dialSimulatedDelay)) }) }) +var _ = Describe("Client creation", func() { + Context("simple client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewClient(nil) + }).To(Panic()) + }) + }) + Context("cluster client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewClusterClient(nil) + }).To(Panic()) + }) + }) + Context("ring client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewRing(nil) + }).To(Panic()) + }) + }) + Context("universal client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewUniversalClient(nil) + }).To(Panic()) + }) + }) + Context("failover client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewFailoverClient(nil) + }).To(Panic()) + }) + }) + Context("failover cluster client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewFailoverClusterClient(nil) + }).To(Panic()) + }) + }) + Context("sentinel client with nil options", func() { + It("panics", func() { + Expect(func() { + redis.NewSentinelClient(nil) + }).To(Panic()) + }) + }) +}) diff --git a/ring.go b/ring.go index 8f2dd3c4..555ea2a1 100644 --- a/ring.go +++ b/ring.go @@ -523,6 +523,9 @@ type Ring struct { } func NewRing(opt *RingOptions) *Ring { + if opt == nil { + panic("redis: NewRing nil options") + } opt.init() hbCtx, hbCancel := context.WithCancel(context.Background()) diff --git a/sentinel.go b/sentinel.go index f5b9a52d..cfc848cf 100644 --- a/sentinel.go +++ b/sentinel.go @@ -224,6 +224,10 @@ func (opt *FailoverOptions) clusterOptions() *ClusterOptions { // for automatic failover. It's safe for concurrent use by multiple // goroutines. func NewFailoverClient(failoverOpt *FailoverOptions) *Client { + if failoverOpt == nil { + panic("redis: NewFailoverClient nil options") + } + if failoverOpt.RouteByLatency { panic("to route commands by latency, use NewFailoverClusterClient") } @@ -313,6 +317,9 @@ type SentinelClient struct { } func NewSentinelClient(opt *Options) *SentinelClient { + if opt == nil { + panic("redis: NewSentinelClient nil options") + } opt.init() c := &SentinelClient{ baseClient: &baseClient{ @@ -828,6 +835,10 @@ func contains(slice []string, str string) bool { // NewFailoverClusterClient returns a client that supports routing read-only commands // to a replica node. func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient { + if failoverOpt == nil { + panic("redis: NewFailoverClusterClient nil options") + } + sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs)) copy(sentinelAddrs, failoverOpt.SentinelAddrs) diff --git a/universal.go b/universal.go index 46d5640d..a1ce17ba 100644 --- a/universal.go +++ b/universal.go @@ -267,6 +267,10 @@ var ( // a ClusterClient is returned. // 4. Otherwise, a single-node Client is returned. func NewUniversalClient(opts *UniversalOptions) UniversalClient { + if opts == nil { + panic("redis: NewUniversalClient nil options") + } + switch { case opts.MasterName != "" && (opts.RouteByLatency || opts.RouteRandomly || opts.IsClusterMode): return NewFailoverClusterClient(opts.Failover())