diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 5e50fc8..5a859fe 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -26,21 +26,12 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v2 - - - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + - uses: actions/checkout@v5 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v6 with: - go-version: 1.18 + go-version-file: 'go.mod' - name: Build run: go build ./... @@ -50,4 +41,3 @@ jobs: REDIS_URL: redis://localhost:6379 run: go test -v -race ./... - diff --git a/go.mod b/go.mod index 76cad63..78189e8 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,5 @@ module github.com/timehop/jimmy -go 1.18 +go 1.22 -require ( - github.com/gomodule/redigo v1.8.8 - github.com/onsi/ginkgo v1.4.0 - github.com/onsi/gomega v1.2.0 -) - -require ( - github.com/golang/protobuf v1.5.2 // indirect - golang.org/x/net v0.0.0-20171115151908-9dfe39835686 // indirect - golang.org/x/sys v0.0.0-20171120170034-328643532ee3 // indirect - golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab // indirect -) +require github.com/gomodule/redigo v1.9.3 diff --git a/go.sum b/go.sum index 3a6a2bd..c702d6d 100644 --- a/go.sum +++ b/go.sum @@ -1,39 +1,10 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/gomodule/redigo v1.8.8 h1:f6cXq6RRfiyrOJEV7p3JhLDlmawGBVBBP1MggY8Mo4E= -github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/onsi/ginkgo v1.4.0 h1:n60/4GZK0Sr9O2iuGKq876Aoa0ER2ydgpMOBwzJ8e2c= -github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.2.0 h1:tQjc4uvqBp0z424R9V/S2L18penoUiwZftoY0t48IZ4= -github.com/onsi/gomega v1.2.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gomodule/redigo v1.9.3 h1:dNPSXeXv6HCq2jdyWfjgmhBdqnR6PRO3m/G05nvpPC8= +github.com/gomodule/redigo v1.9.3/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/net v0.0.0-20171115151908-9dfe39835686 h1:fxZ+mPcFhowcPZdlXrTF3GFhWVr/3wZyXQ8xW8WYGLU= -golang.org/x/net v0.0.0-20171115151908-9dfe39835686/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sys v0.0.0-20171120170034-328643532ee3 h1:nIfpWBHOSv0S4RLFElEzul1XVxkHjxl1Idi2K0v3avw= -golang.org/x/sys v0.0.0-20171120170034-328643532ee3/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 h1:OxMYHd6bm+jH+TI7NBCb/CaYk6pMJnBC8GIzIi68Hk4= -golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab h1:yZ6iByf7GKeJ3gsd1Dr/xaj1DyJ//wxKX1Cdh8LhoAw= -gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/redis/connection_test.go b/redis/connection_test.go index 2eccde5..d9355ac 100644 --- a/redis/connection_test.go +++ b/redis/connection_test.go @@ -2,355 +2,527 @@ package redis_test import ( "fmt" - netURL "net/url" + "testing" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" "github.com/timehop/jimmy/redis" ) -var _ = Describe("Connection", func() { - +func TestConnection(t *testing.T) { // Using an arbitrary password should fallback to using no password url := "redis://:foopass@localhost:6379/12" parsedURL, _ := netURL.Parse(url) c, err := redis.NewConnection(parsedURL) if err != nil { - panic(err) + t.Fatalf("failed to create connection: %v", err) } - BeforeEach(func() { + flushDB := func() { c.Do("FLUSHDB") - }) - - Describe("NewConnection", func() { - // Assumes redis' default state is auth-less + } - Context("server has no auth set", func() { - It("should ping without auth", func() { + t.Run("NewConnection", func(t *testing.T) { + t.Run("server has no auth set", func(t *testing.T) { + t.Run("should ping without auth", func(t *testing.T) { + flushDB() url := "redis://localhost:6379" parsedURL, _ := netURL.Parse(url) c, err := redis.NewConnection(parsedURL) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } _, err = c.Do("PING") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) - It("should fallback to ping without auth", func() { + + t.Run("should fallback to ping without auth", func(t *testing.T) { + flushDB() url := "redis://user:testpass@localhost:6379" parsedURL, _ := netURL.Parse(url) c, err := redis.NewConnection(parsedURL) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } _, err = c.Do("PING") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) }) - Context("server requires auth", func() { - BeforeEach(func() { + t.Run("server requires auth", func(t *testing.T) { + setupAuth := func() { url := "redis://localhost:6379" parsedURL, _ := netURL.Parse(url) c, _ := redis.NewConnection(parsedURL) c.Do("CONFIG", "SET", "requirepass", "testpass") - }) - AfterEach(func() { + } + teardownAuth := func() { url := "redis://:testpass@localhost:6379" parsedURL, _ := netURL.Parse(url) c, _ := redis.NewConnection(parsedURL) c.Do("CONFIG", "SET", "requirepass", "") - }) + } + + t.Run("should fail to ping without auth", func(t *testing.T) { + flushDB() + setupAuth() + t.Cleanup(teardownAuth) - It("should fail to ping without auth", func() { url := "redis://localhost:6379" parsedURL, _ := netURL.Parse(url) c, _ := redis.NewConnection(parsedURL) _, err := c.Do("PING") - Expect(err).ToNot(BeNil()) + if err == nil { + t.Error("expected error, got nil") + } }) - It("should successfully ping with auth", func() { + + t.Run("should successfully ping with auth", func(t *testing.T) { + flushDB() + setupAuth() + t.Cleanup(teardownAuth) + url := "redis://:testpass@localhost:6379" parsedURL, _ := netURL.Parse(url) c, _ := redis.NewConnection(parsedURL) _, err := c.Do("PING") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) }) }) - Describe("DEL", func() { - Context("Where no key exists", func() { - It("Should return 0 with no error.", func() { - i, err := c.Del("doesnotexist") - Expect(i).To(Equal(0)) - Expect(err).To(BeNil()) - }) + t.Run("DEL", func(t *testing.T) { + t.Run("no key exists returns 0", func(t *testing.T) { + flushDB() + i, err := c.Del("doesnotexist") + if i != 0 { + t.Errorf("got %d, want 0", i) + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) - Context("Where a key exists", func() { - It("Should return 1 with no error.", func() { - c.Set("exists", "The best leaders know when to follow.") - i, err := c.Del("exists") - Expect(i).To(Equal(1)) - Expect(err).To(BeNil()) - }) + + t.Run("key exists returns 1", func(t *testing.T) { + flushDB() + c.Set("exists", "The best leaders know when to follow.") + i, err := c.Del("exists") + if i != 1 { + t.Errorf("got %d, want 1", i) + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) }) - Describe("TTL", func() { - Context("Without a key.", func() { - It("Should return -2.", func() { - i, err := c.TTL("foo") - Expect(err).To(BeNil()) - Expect(i).To(Equal(-2)) - }) + t.Run("TTL", func(t *testing.T) { + t.Run("without key returns -2", func(t *testing.T) { + flushDB() + i, err := c.TTL("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != -2 { + t.Errorf("got %d, want -2", i) + } }) - Context("With a key without an expiration.", func() { - It("Should return -1.", func() { - c.Set("foo", "bar") - i, err := c.TTL("foo") - Expect(err).To(BeNil()) - Expect(i).To(Equal(-1)) - }) + t.Run("key without expiration returns -1", func(t *testing.T) { + flushDB() + c.Set("foo", "bar") + + i, err := c.TTL("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != -1 { + t.Errorf("got %d, want -1", i) + } }) - Context("With a key with an expiration.", func() { - It("Should return the time to live.", func() { - c.SetEx("biz", "baz", 15) - i, err := c.TTL("biz") - Expect(err).To(BeNil()) - Expect(i).To(Equal(15)) - }) + t.Run("key with expiration returns ttl", func(t *testing.T) { + flushDB() + c.SetEx("biz", "baz", 15) + + i, err := c.TTL("biz") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != 15 { + t.Errorf("got %d, want 15", i) + } }) }) - Describe("PFAdd", func() { - It("Should indicate HyperLogLog register was altered (ie: 1)", func() { + t.Run("PFAdd", func(t *testing.T) { + t.Run("should indicate HyperLogLog register was altered", func(t *testing.T) { + flushDB() i, err := c.PFAdd("_tests:jimmy:redis:foo1", "bar") - Expect(err).To(BeNil()) - Expect(i).To(Equal(1)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != 1 { + t.Errorf("got %d, want 1", i) + } }) - It("Should indicate HyperLogLog register was not altered (ie: 0)", func() { + + t.Run("should indicate HyperLogLog register was not altered", func(t *testing.T) { + flushDB() _, err := c.PFAdd("_tests:jimmy:redis:foo2", "bar") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } i, err := c.PFAdd("_tests:jimmy:redis:foo2", "bar") - Expect(err).To(BeNil()) - Expect(i).To(Equal(0)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != 0 { + t.Errorf("got %d, want 0", i) + } }) }) - Describe("PFCount", func() { - It("Should return the approximate cardinality of the HLL", func() { + t.Run("PFCount", func(t *testing.T) { + t.Run("should return approximate cardinality", func(t *testing.T) { + flushDB() var actualCardinality float64 = 20000 for i := 0; float64(i) < actualCardinality; i++ { _, err := c.PFAdd("_tests:jimmy:redis:foo3", fmt.Sprint(i)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } card, err := c.PFCount("_tests:jimmy:redis:foo3") - Expect(err).To(BeNil()) - // Check a VERY rough 20% accuracy - Expect(float64(card)).To(BeNumerically("<", actualCardinality*1.2)) - Expect(float64(card)).To(BeNumerically(">", actualCardinality*(1-0.2))) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if float64(card) >= actualCardinality*1.2 { + t.Errorf("cardinality %d too high (max %v)", card, actualCardinality*1.2) + } + if float64(card) <= actualCardinality*0.8 { + t.Errorf("cardinality %d too low (min %v)", card, actualCardinality*0.8) + } }) }) - Describe("PFMerge", func() { - It("Should return the approximate cardinality of the union of multiple HLLs", func() { + t.Run("PFMerge", func(t *testing.T) { + t.Run("should return approximate cardinality of union", func(t *testing.T) { + flushDB() setA := []int{1, 2, 3, 4, 5} setB := []int{3, 4, 5, 6, 7} setC := []int{8, 9, 10, 11, 12} for _, x := range setA { _, err := c.PFAdd("_tests:jimmy:redis:hll1", fmt.Sprint(x)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } - for _, x := range setB { _, err := c.PFAdd("_tests:jimmy:redis:hll2", fmt.Sprint(x)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } - for _, x := range setC { _, err := c.PFAdd("_tests:jimmy:redis:hll3", fmt.Sprint(x)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } for i := 1; i < 4; i++ { card, err := c.PFCount(fmt.Sprintf("_tests:jimmy:redis:hll%d", i)) - Expect(err).To(BeNil()) - Expect(card).To(Equal(5)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 5 { + t.Errorf("hll%d: got %d, want 5", i, card) + } } ok, err := c.PFMerge("_tests:jimmy:redis:hll1+2", "_tests:jimmy:redis:hll1", "_tests:jimmy:redis:hll2") - Expect(err).To(BeNil()) - Expect(ok).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } card, err := c.PFCount("_tests:jimmy:redis:hll1+2") - Expect(err).To(BeNil()) - Expect(card).To(Equal(7)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 7 { + t.Errorf("got %d, want 7", card) + } ok, err = c.PFMerge("_tests:jimmy:redis:hll1+3", "_tests:jimmy:redis:hll1", "_tests:jimmy:redis:hll3") - Expect(err).To(BeNil()) - Expect(ok).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } card, err = c.PFCount("_tests:jimmy:redis:hll1+3") - Expect(err).To(BeNil()) - Expect(card).To(Equal(10)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 10 { + t.Errorf("got %d, want 10", card) + } ok, err = c.PFMerge("_tests:jimmy:redis:hll1+2+3", "_tests:jimmy:redis:hll1", "_tests:jimmy:redis:hll2", "_tests:jimmy:redis:hll3") - Expect(err).To(BeNil()) - Expect(ok).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } card, err = c.PFCount("_tests:jimmy:redis:hll1+2+3") - Expect(err).To(BeNil()) - Expect(card).To(Equal(12)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 12 { + t.Errorf("got %d, want 12", card) + } }) }) - Describe("LTrim", func() { - Context("When a list is trimmed", func() { - It("Trims the list", func() { - key := "_tests:jimmy:redis:list" + t.Run("LTrim", func(t *testing.T) { + t.Run("when a list is trimmed", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:list" - for i := 0; i < 5; i++ { - c.LPush(key, fmt.Sprint(i)) - } + for i := range 5 { + c.LPush(key, fmt.Sprint(i)) + } - size, err := c.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(5)) + size, err := c.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 5 { + t.Errorf("got %d, want 5", size) + } - // Trim nothing - err = c.LTrim(key, 0, 4) - Expect(err).To(BeNil()) + // Trim nothing + err = c.LTrim(key, 0, 4) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - size, err = c.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(5)) + size, err = c.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 5 { + t.Errorf("got %d, want 5", size) + } - // Trim first element - err = c.LTrim(key, 1, 5) - Expect(err).To(BeNil()) + // Trim first element + err = c.LTrim(key, 1, 5) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - size, err = c.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(4)) + size, err = c.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 4 { + t.Errorf("got %d, want 4", size) + } - item, err := c.LPop(key) - Expect(err).To(BeNil()) - Expect(item).To(Equal("3")) + item, err := c.LPop(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if item != "3" { + t.Errorf("got %q, want %q", item, "3") + } - // Trim last element - err = c.LTrim(key, -4, -1) - Expect(err).To(BeNil()) + // Trim last element + err = c.LTrim(key, -4, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - size, err = c.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(3)) + size, err = c.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 3 { + t.Errorf("got %d, want 3", size) + } - item, err = c.LPop(key) - Expect(err).To(BeNil()) - Expect(item).To(Equal("2")) - }) + item, err = c.LPop(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if item != "2" { + t.Errorf("got %q, want %q", item, "2") + } }) - Context("When a not-list is trimmed", func() { - It("Returns an error", func() { - key := "_tests:jimmy:redis:not-list" + t.Run("when a not-list is trimmed returns error", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:not-list" - Expect(c.Set(key, "yay")).To(BeNil()) - Expect(c.LTrim(key, 0, 4)).ToNot(BeNil()) + if err := c.Set(key, "yay"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := c.LTrim(key, 0, 4); err == nil { + t.Error("expected error, got nil") + } - c.Del(key) - _, err := c.SAdd(key, "yay") - Expect(err).To(BeNil()) - Expect(c.LTrim(key, 0, 4)).ToNot(BeNil()) - }) + c.Del(key) + _, err := c.SAdd(key, "yay") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := c.LTrim(key, 0, 4); err == nil { + t.Error("expected error, got nil") + } }) }) - Describe("LRange", func() { - Context("When an empty list is ranged", func() { - It("Returns nothing, but no err", func() { - key := "_tests:jimmy:redis:list" - things, err := c.LRange(key, 0, -1) - Expect(err).To(BeNil()) - Expect(things).To(BeEmpty()) - }) + t.Run("LRange", func(t *testing.T) { + t.Run("empty list returns nothing", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:list" + things, err := c.LRange(key, 0, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 0 { + t.Errorf("expected empty, got %v", things) + } }) - Context("When a list is ranged", func() { - It("Returns the items", func() { - key := "_tests:jimmy:redis:list" - for i := 0; i < 5; i++ { - _, err := c.LPush(key, fmt.Sprint(i)) - Expect(err).To(BeNil()) + t.Run("list returns items", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:list" + for i := range 5 { + _, err := c.LPush(key, fmt.Sprint(i)) + if err != nil { + t.Fatalf("unexpected error: %v", err) } + } - things, err := c.LRange(key, 0, -1) - Expect(err).To(BeNil()) - Expect(len(things)).To(Equal(5)) + things, err := c.LRange(key, 0, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 5 { + t.Errorf("got len %d, want 5", len(things)) + } - things, err = c.LRange(key, 0, 0) - Expect(err).To(BeNil()) - Expect(len(things)).To(Equal(1)) - Expect(things[0]).To(Equal("4")) + things, err = c.LRange(key, 0, 0) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 1 { + t.Errorf("got len %d, want 1", len(things)) + } + if things[0] != "4" { + t.Errorf("got %q, want %q", things[0], "4") + } - things, err = c.LRange(key, -1, -1) - Expect(err).To(BeNil()) - Expect(len(things)).To(Equal(1)) - Expect(things[0]).To(Equal("0")) - }) + things, err = c.LRange(key, -1, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 1 { + t.Errorf("got len %d, want 1", len(things)) + } + if things[0] != "0" { + t.Errorf("got %q, want %q", things[0], "0") + } }) }) - Describe("SMove", func() { - It("Should move the member to the other set", func() { + t.Run("SMove", func(t *testing.T) { + t.Run("should move member to other set", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:smove" c.SAdd(key+":a", "foobar") moved, err := c.SMove(key+":a", key+":b", "foobar") - Expect(err).To(BeNil()) - Expect(moved).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !moved { + t.Error("expected true, got false") + } members, _ := c.SMembers(key + ":a") - Expect(len(members)).To(Equal(0)) + if len(members) != 0 { + t.Errorf("got len %d, want 0", len(members)) + } members, _ = c.SMembers(key + ":b") - Expect(members).To(Equal([]string{"foobar"})) + if len(members) != 1 || members[0] != "foobar" { + t.Errorf("got %v, want [foobar]", members) + } }) }) - Describe("SETNX", func() { - It("Should not set an existing key.", func() { + t.Run("SETNX", func(t *testing.T) { + t.Run("should not set existing key", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:setnx.existing" c.Set(key, "foo") ok, err := c.SetNX(key, "bar") - Expect(err).To(BeNil()) - Expect(ok).To(Equal(false)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { + t.Error("expected false, got true") + } foo, _ := c.Get(key) - Expect(foo).To(Equal("foo")) + if foo != "foo" { + t.Errorf("got %q, want %q", foo, "foo") + } }) - It("Should set a non-existent key.", func() { + + t.Run("should set non-existent key", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:setnx.notexisting" ok, err := c.SetNX(key, "bar") - Expect(err).To(BeNil()) - Expect(ok).To(Equal(true)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } foo, _ := c.Get(key) - Expect(foo).To(Equal("bar")) + if foo != "bar" { + t.Errorf("got %q, want %q", foo, "bar") + } }) }) - Describe("ZScan", func() { - It("Should scan the sorted set", func() { + t.Run("ZScan", func(t *testing.T) { + t.Run("should scan the sorted set", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:zscan" c.ZAdd(key, 1, "a") @@ -367,42 +539,41 @@ var _ = Describe("Connection", func() { var err error cursor, matches, scores, err = c.ZScan(key, cursor, "", 1) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } scanned = append(scanned, matches...) scannedScores = append(scannedScores, scores...) for cursor != 0 { cursor, matches, scores, err = c.ZScan(key, cursor, "", 1) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + scanned = append(scanned, matches...) scannedScores = append(scannedScores, scores...) } - Expect(len(scanned)).To(Equal(5)) - Expect(scanned).To(ContainElement("a")) - Expect(scanned).To(ContainElement("b")) - Expect(scanned).To(ContainElement("c")) - Expect(scanned).To(ContainElement("d")) - Expect(scanned).To(ContainElement("e")) + if len(scanned) != 5 { + t.Errorf("got len %d, want 5", len(scanned)) + } + for _, want := range []string{"a", "b", "c", "d", "e"} { + if !containsString(scanned, want) { + t.Errorf("expected %q in %v", want, scanned) + } + } + expectedScores := map[string]float64{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} for i, elem := range scanned { - switch elem { - case "a": - Expect(scannedScores[i]).To(Equal(float64(1))) - case "b": - Expect(scannedScores[i]).To(Equal(float64(2))) - case "c": - Expect(scannedScores[i]).To(Equal(float64(3))) - case "d": - Expect(scannedScores[i]).To(Equal(float64(4))) - case "e": - Expect(scannedScores[i]).To(Equal(float64(5))) + if scannedScores[i] != expectedScores[elem] { + t.Errorf("%s: got score %v, want %v", elem, scannedScores[i], expectedScores[elem]) } } - }) }) - Describe("SScan", func() { - It("Should scan the set", func() { + t.Run("SScan", func(t *testing.T) { + t.Run("should scan the set", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:sscan" c.SAdd(key, "a", "b", "c", "d", "e") @@ -413,321 +584,459 @@ var _ = Describe("Connection", func() { var err error cursor, matches, err = c.SScan(key, cursor, "", 1) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } scanned = append(scanned, matches...) for cursor != 0 { cursor, matches, err = c.SScan(key, cursor, "", 1) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } scanned = append(scanned, matches...) } - Expect(len(scanned)).To(Equal(5)) - Expect(scanned).To(ContainElement("a")) - Expect(scanned).To(ContainElement("b")) - Expect(scanned).To(ContainElement("c")) - Expect(scanned).To(ContainElement("d")) - Expect(scanned).To(ContainElement("e")) + if len(scanned) != 5 { + t.Errorf("got len %d, want 5", len(scanned)) + } + for _, want := range []string{"a", "b", "c", "d", "e"} { + if !containsString(scanned, want) { + t.Errorf("expected %q in %v", want, scanned) + } + } }) }) - Describe("HGet", func() { - Context("a key that exists and contains a hash that contains the requested field with a value", func() { - It("returns the value of that field of that key", func() { - mustSucceed2(c.HSet("foo", "bar", "baz")) - val, err := c.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("baz")) - }) + t.Run("HGet", func(t *testing.T) { + t.Run("key exists with field returns value", func(t *testing.T) { + flushDB() + if _, err := c.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + val, err := c.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "baz" { + t.Errorf("got %q, want %q", val, "baz") + } }) - Context("a key that exists and contains a hash that doesn’t contain the requested field", func() { - It("returns an error and an empty string", func() { - mustSucceed2(c.HSet("foo", "blah", "blech")) - val, err := c.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) - }) + t.Run("key exists without field returns error", func(t *testing.T) { + flushDB() + if _, err := c.HSet("foo", "blah", "blech"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + val, err := c.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } }) - Context("a key that doesn’t exist", func() { - It("returns an error and an empty string", func() { - val, err := c.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) - }) + t.Run("key does not exist returns error", func(t *testing.T) { + flushDB() + val, err := c.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } }) - Context("a key that exists but doesn’t contain a hash", func() { - It("returns an error and an empty string", func() { - mustSucceed1(c.Set("foo", "yo")) - val, err := c.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) - }) + t.Run("key exists but not hash returns error", func(t *testing.T) { + flushDB() + if err := c.Set("foo", "yo"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + val, err := c.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } }) }) - Describe("HGetAll", func() { - Context("a key that exists and contains 2 key/value pairs", func() { - It("returns the 2 pairs and no error", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := c.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := c.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("HGetAll", func(t *testing.T) { + t.Run("key exists with 2 pairs returns pairs", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := c.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that doesn’t exist", func() { - It("returns an empty map and no error", func() { - vals, err := c.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(0)) - }) + t.Run("key does not exist returns empty map", func(t *testing.T) { + flushDB() + vals, err := c.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 0 { + t.Errorf("got len %d, want 0", len(vals)) + } }) }) - Describe("HSet", func() { - Context("a key that doesn’t already exist and two strings", func() { - It("returns true and nil and contain the new pair", func() { - isNew, err := c.HSet("foo", "bar", "baz") - Expect(err).To(BeNil()) - Expect(isNew).To(Equal(true)) + t.Run("HSet", func(t *testing.T) { + t.Run("new key returns true", func(t *testing.T) { + flushDB() + isNew, err := c.HSet("foo", "bar", "baz") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !isNew { + t.Error("expected true, got false") + } - val, err := c.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("baz")) - }) + val, err := c.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "baz" { + t.Errorf("got %q, want %q", val, "baz") + } }) - Context("a key that already exists and a field that it doesn’t already contain", func() { - It("returns true and nil and contain both fields", func() { - mustSucceed2(c.HSet("foo", "bar", "baz")) - isNew, err := c.HSet("foo", "yo", "oy") - Expect(err).To(BeNil()) - Expect(isNew).To(Equal(true)) + t.Run("existing key new field returns true", func(t *testing.T) { + flushDB() + if _, err := c.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + isNew, err := c.HSet("foo", "yo", "oy") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !isNew { + t.Error("expected true, got false") + } - val, err := c.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("baz")) + val, err := c.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "baz" { + t.Errorf("got %q, want %q", val, "baz") + } - val, err = c.HGet("foo", "yo") - Expect(err).To(BeNil()) - Expect(val).To(Equal("oy")) - }) + val, err = c.HGet("foo", "yo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "oy" { + t.Errorf("got %q, want %q", val, "oy") + } }) - Context("a key that already exists and a field that it already contains", func() { - It("returns false and nil and change the value of the field", func() { - mustSucceed2(c.HSet("foo", "bar", "baz")) - isNew, err := c.HSet("foo", "bar", "yo") - Expect(err).To(BeNil()) - Expect(isNew).To(Equal(false)) + t.Run("existing key existing field returns false", func(t *testing.T) { + flushDB() + if _, err := c.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + isNew, err := c.HSet("foo", "bar", "yo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if isNew { + t.Error("expected false, got true") + } - val, err := c.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("yo")) - }) + val, err := c.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "yo" { + t.Errorf("got %q, want %q", val, "yo") + } }) - Context("a key that already exists and is not a hash", func() { - It("returns false and an error", func() { - mustSucceed1(c.Set("foo", "bar")) - isNew, err := c.HSet("foo", "bar", "yo") - Expect(err).ToNot(BeNil()) - Expect(isNew).To(Equal(false)) + t.Run("existing key not hash returns error", func(t *testing.T) { + flushDB() + if err := c.Set("foo", "bar"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + isNew, err := c.HSet("foo", "bar", "yo") + if err == nil { + t.Error("expected error, got nil") + } + if isNew { + t.Error("expected false, got true") + } - val, err := c.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) + val, err := c.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } - val, err = c.Get("foo") - Expect(err).To(BeNil()) - Expect(val).To(Equal("bar")) - }) + val, err = c.Get("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "bar" { + t.Errorf("got %q, want %q", val, "bar") + } }) }) - Describe("HMGet", func() { - Context("a key that exists and contains the 2 specified keys", func() { - It("returns the 2 pairs and no error", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := c.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := c.HMGet("foo", "bar", "blah") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("HMGet", func(t *testing.T) { + t.Run("key exists with 2 specified keys", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := c.HMGet("foo", "bar", "blah") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that exists and contains the 2 of the 3 specified keys", func() { - It("returns the 2 pairs and no error", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := c.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := c.HMGet("foo", "bar", "yo", "blah") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(3)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("yo", "")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("key exists with 2 of 3 specified keys", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := c.HMGet("foo", "bar", "yo", "blah") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 3 { + t.Errorf("got len %d, want 3", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["yo"] != "" { + t.Errorf("yo: got %q, want empty string", vals["yo"]) + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that doesn’t exist", func() { - It("returns nil values and no error", func() { - vals, err := c.HMGet("foo", "bar", "blah") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "")) - Expect(vals).To(HaveKeyWithValue("blah", "")) - }) + t.Run("key does not exist", func(t *testing.T) { + flushDB() + vals, err := c.HMGet("foo", "bar", "blah") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "" { + t.Errorf("bar: got %q, want empty string", vals["bar"]) + } + if vals["blah"] != "" { + t.Errorf("blah: got %q, want empty string", vals["blah"]) + } }) - Context("no fields", func() { - It("returns nil values and an error", func() { - vals, err := c.HMGet("foo") - Expect(err).ToNot(BeNil()) - Expect(vals).To(HaveLen(0)) - }) + t.Run("no fields returns error", func(t *testing.T) { + flushDB() + vals, err := c.HMGet("foo") + if err == nil { + t.Error("expected error, got nil") + } + if len(vals) != 0 { + t.Errorf("got len %d, want 0", len(vals)) + } }) }) - Describe("HMSet", func() { - Context("a key that doesn’t already exist and a map with 2 string pairs", func() { - It("returns nil and creates the hash containing the new pairs", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := c.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := c.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("HMSet", func(t *testing.T) { + t.Run("new key with 2 string pairs", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := c.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that doesn’t already exist and a map with 2 int pairs", func() { - It("returns nil and creates the hash containing the new pairs", func() { - in := map[string]interface{}{ - "bar": 18, - "blah": 42, - } - err := c.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := c.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "18")) - Expect(vals).To(HaveKeyWithValue("blah", "42")) - }) + t.Run("new key with 2 int pairs", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": 18, "blah": 42} + err := c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := c.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "18" { + t.Errorf("bar: got %q, want %q", vals["bar"], "18") + } + if vals["blah"] != "42" { + t.Errorf("blah: got %q, want %q", vals["blah"], "42") + } }) - Context("a key that already exists with 3 pairs and a map with 2 pairs that it already contains", func() { - It("returns nil and changes the hash to contain the fields with their new values, but leaves other fields alone", func() { - in := map[string]interface{}{ - "bar": 18, - "blah": 42, - "yo": "oy", - } - err := c.HMSet("foo", in) - Expect(err).To(BeNil()) + t.Run("existing key with 3 pairs update 2", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": 18, "blah": 42, "yo": "oy"} + err := c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - in = map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err = c.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := c.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(3)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - Expect(vals).To(HaveKeyWithValue("yo", "oy")) - }) + in = map[string]interface{}{"bar": "baz", "blah": "blech"} + err = c.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := c.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 3 { + t.Errorf("got len %d, want 3", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } + if vals["yo"] != "oy" { + t.Errorf("yo: got %q, want %q", vals["yo"], "oy") + } }) - Context("a key that already exists and is not a hash", func() { - It("returns false and an error", func() { - mustSucceed1(c.Set("foo", "bar")) + t.Run("existing key not hash returns error", func(t *testing.T) { + flushDB() + if err := c.Set("foo", "bar"); err != nil { + t.Fatalf("unexpected error: %v", err) + } - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := c.HMSet("foo", in) - Expect(err).ToNot(BeNil()) + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := c.HMSet("foo", in) + if err == nil { + t.Error("expected error, got nil") + } - val, err := c.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) + val, err := c.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } - val, err = c.Get("foo") - Expect(err).To(BeNil()) - Expect(val).To(Equal("bar")) - }) + val, err = c.Get("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "bar" { + t.Errorf("got %q, want %q", val, "bar") + } }) - Context("a key that already exists and an empty map", func() { - It("returns an error and doesn’t change existing the key", func() { - mustSucceed2(c.HSet("foo", "bar", "baz")) - in := map[string]interface{}{} - err := c.HMSet("foo", in) - Expect(err).ToNot(BeNil()) + t.Run("existing key empty map returns error", func(t *testing.T) { + flushDB() + if _, err := c.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + in := map[string]interface{}{} + err := c.HMSet("foo", in) + if err == nil { + t.Error("expected error, got nil") + } - vals, err := c.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(1)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - }) + vals, err := c.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 1 { + t.Errorf("got len %d, want 1", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } }) - Context("a key that doesn’t already exist and an empty map", func() { - It("returns an error and doesn’t create the key", func() { - in := map[string]interface{}{} - err := c.HMSet("foo", in) - Expect(err).ToNot(BeNil()) + t.Run("new key empty map returns error", func(t *testing.T) { + flushDB() + in := map[string]interface{}{} + err := c.HMSet("foo", in) + if err == nil { + t.Error("expected error, got nil") + } - exists, err := c.Exists("foo") - Expect(err).To(BeNil()) - Expect(exists).To(BeFalse()) - }) + exists, err := c.Exists("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists { + t.Error("expected false, got true") + } }) }) -}) - -func mustSucceed1(err error) { - if err != nil { - Fail("Expected " + err.Error() + " to be nil") - } } -func mustSucceed2(_ interface{}, err error) { - if err != nil { - Fail("Expected " + err.Error() + " to be nil") +// containsString checks if a string slice contains a given string. +func containsString(slice []string, s string) bool { + for _, v := range slice { + if v == s { + return true + } } + return false } + diff --git a/redis/convert_test.go b/redis/convert_test.go index b80c8d3..49cdad5 100644 --- a/redis/convert_test.go +++ b/redis/convert_test.go @@ -2,85 +2,93 @@ package redis import ( "errors" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" + "testing" ) -// TODO: this mostly tests error cases. Add tests for success cases! - -var _ = Describe("stringMap", func() { - Context("A nil slice arg and a nil error arg", func() { - It("returns nil and an error", func() { - result, err := stringMap(nil, nil) - Expect(err).ToNot(BeNil()) - Expect(result).To(BeNil()) - }) +func TestStringMap(t *testing.T) { + t.Run("nil slice and nil error returns error", func(t *testing.T) { + result, err := stringMap(nil, nil) + if err == nil { + t.Fatal("expected error, got nil") + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) - Context("A nil slice arg and a non-nil error arg", func() { - It("returns nil and the error that was passed in", func() { - inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") - result, err := stringMap(nil, inputErr) - Expect(err).To(Equal(inputErr)) - Expect(&err).To(Equal(&inputErr)) - Expect(result).To(BeNil()) - }) + t.Run("nil slice and non-nil error returns that error", func(t *testing.T) { + inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") + result, err := stringMap(nil, inputErr) + if err != inputErr { + t.Errorf("got %v, want %v", err, inputErr) + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) - Context("An odd-length slice arg and a nil error arg", func() { - It("returns nil and an error", func() { - result, err := stringMap([]string{"foo"}, nil) - Expect(err).ToNot(BeNil()) - Expect(result).To(BeNil()) - }) + t.Run("odd-length slice and nil error returns error", func(t *testing.T) { + result, err := stringMap([]string{"foo"}, nil) + if err == nil { + t.Fatal("expected error, got nil") + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) - Context("An odd-length slice arg and a non-nil error arg", func() { - It("returns nil and the error that was passed in", func() { - inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") - result, err := stringMap([]string{"foo"}, inputErr) - Expect(err).To(Equal(inputErr)) - Expect(&err).To(Equal(&inputErr)) - Expect(result).To(BeNil()) - }) + t.Run("odd-length slice and non-nil error returns that error", func(t *testing.T) { + inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") + result, err := stringMap([]string{"foo"}, inputErr) + if err != inputErr { + t.Errorf("got %v, want %v", err, inputErr) + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) -}) +} -var _ = Describe("spliceMap", func() { - Context("All nil args", func() { - It("returns nil and an error", func() { - result, err := spliceMap(nil, nil, nil) - Expect(err).ToNot(BeNil()) - Expect(result).To(BeNil()) - }) +func TestSpliceMap(t *testing.T) { + t.Run("all nil args returns error", func(t *testing.T) { + result, err := spliceMap(nil, nil, nil) + if err == nil { + t.Fatal("expected error, got nil") + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) - Context("nil keys, nil vals, and a non-nil error", func() { - It("returns nil and the error that was passed in", func() { - inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") - result, err := spliceMap(nil, nil, inputErr) - Expect(err).To(Equal(inputErr)) - Expect(&err).To(Equal(&inputErr)) - Expect(result).To(BeNil()) - }) + t.Run("nil keys nil vals and non-nil error returns that error", func(t *testing.T) { + inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") + result, err := spliceMap(nil, nil, inputErr) + if err != inputErr { + t.Errorf("got %v, want %v", err, inputErr) + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) - Context("2 keys, 1 val, and a nil error", func() { - It("returns nil and an error", func() { - result, err := spliceMap([]string{"foo", "bar"}, []string{"baz"}, nil) - Expect(err).ToNot(BeNil()) - Expect(result).To(BeNil()) - }) + t.Run("2 keys 1 val and nil error returns error", func(t *testing.T) { + result, err := spliceMap([]string{"foo", "bar"}, []string{"baz"}, nil) + if err == nil { + t.Fatal("expected error, got nil") + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) - Context("1 key, 2 vals, and a non-nil error arg", func() { - It("returns nil and the error that was passed in", func() { - inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") - result, err := spliceMap([]string{"foo"}, []string{"foo", "bar"}, inputErr) - Expect(err).To(Equal(inputErr)) - Expect(&err).To(Equal(&inputErr)) - Expect(result).To(BeNil()) - }) + t.Run("1 key 2 vals and non-nil error returns that error", func(t *testing.T) { + inputErr := errors.New("The cheese is old and moldy, where is the bathroom?") + result, err := spliceMap([]string{"foo"}, []string{"foo", "bar"}, inputErr) + if err != inputErr { + t.Errorf("got %v, want %v", err, inputErr) + } + if result != nil { + t.Errorf("expected nil result, got %v", result) + } }) -}) +} diff --git a/redis/pool.go b/redis/pool.go index 1278e14..59f4bcb 100644 --- a/redis/pool.go +++ b/redis/pool.go @@ -50,11 +50,11 @@ func (m *hosts) Get(host string) bool { } func generateConnection(url *netURL.URL) (redigo.Conn, error) { - // Then we expec the server to not ask for a password + // Then we expect the server to not ask for a password if hostsNotUsingAuth.Get(url.Host) { url.User = nil conn, err := redisurl.ConnectToURL(url.String()) - if err == redigoErrNoAuth { + if errors.Is(err, redigoErrNoAuth) { hostsNotUsingAuth.Remove(url.Host) return generateConnection(url) } @@ -63,7 +63,7 @@ func generateConnection(url *netURL.URL) (redigo.Conn, error) { // Then we expect the server to potentially ask for a password conn, err := redisurl.ConnectToURL(url.String()) - if err == redigoErrSentAuth { + if errors.Is(err, redigoErrSentAuth) || errors.Is(err, redigoErrSentAuth2) { hostsNotUsingAuth.Add(url.Host) return generateConnection(url) } diff --git a/redis/pool_test.go b/redis/pool_test.go index 31ab08d..9178eca 100644 --- a/redis/pool_test.go +++ b/redis/pool_test.go @@ -2,278 +2,416 @@ package redis_test import ( "fmt" + "testing" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" "github.com/timehop/jimmy/redis" ) -var _ = Describe("Pool", func() { - +func TestPool(t *testing.T) { redisURL := "redis://:foopass@localhost:6379/10" p, err := redis.NewPool(redisURL, redis.DefaultConfig) if err != nil { - panic(err) + t.Fatalf("failed to create pool: %v", err) } - BeforeEach(func() { + flushDB := func() { p.Do(func(c redis.Connection) { c.Do("FLUSHDB") }) - }) - - Describe("NewPool", func() { - // Assumes redis' default state is auth-less + } - Context("server has no auth set", func() { - It("should ping without auth", func() { + t.Run("NewPool", func(t *testing.T) { + t.Run("server has no auth set", func(t *testing.T) { + t.Run("should ping without auth", func(t *testing.T) { + flushDB() p, _ := redis.NewPool("redis://localhost:6379", redis.DefaultConfig) - Expect(p).ToNot(BeNil()) + if p == nil { + t.Fatal("expected non-nil pool") + } c, err := p.GetConnection() - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } _, err = c.Do("PING") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) - It("should fallback to ping without auth", func() { + + t.Run("should fallback to ping without auth", func(t *testing.T) { + flushDB() p, _ := redis.NewPool("redis://user:testpass@localhost:6379", redis.DefaultConfig) c, err := p.GetConnection() - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } _, err = c.Do("PING") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) }) - Context("server requires auth", func() { - BeforeEach(func() { + t.Run("server requires auth", func(t *testing.T) { + setupAuth := func() { p, _ := redis.NewPool("redis://localhost:6379", redis.DefaultConfig) - c, _ := p.GetConnection() c.Do("CONFIG", "SET", "requirepass", "testpass") - }) - AfterEach(func() { + } + teardownAuth := func() { p, _ := redis.NewPool("redis://:testpass@localhost:6379", redis.DefaultConfig) - c, _ := p.GetConnection() c.Do("CONFIG", "SET", "requirepass", "") - }) + } - It("should fail to ping without auth", func() { - p, _ := redis.NewPool("redis://localhost:6379", redis.DefaultConfig) + t.Run("should fail to ping without auth", func(t *testing.T) { + flushDB() + setupAuth() + t.Cleanup(teardownAuth) + p, _ := redis.NewPool("redis://localhost:6379", redis.DefaultConfig) c, _ := p.GetConnection() _, err := c.Do("PING") - Expect(err).ToNot(BeNil()) + if err == nil { + t.Error("expected error, got nil") + } }) - It("should successfully ping with auth", func() { - p, _ := redis.NewPool("redis://user:testpass@localhost:6379", redis.DefaultConfig) + t.Run("should successfully ping with auth", func(t *testing.T) { + flushDB() + setupAuth() + t.Cleanup(teardownAuth) + + p, _ := redis.NewPool("redis://user:testpass@localhost:6379", redis.DefaultConfig) c, _ := p.GetConnection() _, err := c.Do("PING") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } }) }) }) - Describe("PFAdd", func() { - It("Should indicate HyperLogLog register was altered (ie: 1)", func() { + t.Run("PFAdd", func(t *testing.T) { + t.Run("should indicate HyperLogLog register was altered", func(t *testing.T) { + flushDB() i, err := p.PFAdd("_tests:jimmy:redis:foo1", "bar") - Expect(err).To(BeNil()) - Expect(i).To(Equal(1)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != 1 { + t.Errorf("got %d, want 1", i) + } }) - It("Should indicate HyperLogLog register was not altered (ie: 0)", func() { + + t.Run("should indicate HyperLogLog register was not altered", func(t *testing.T) { + flushDB() _, err := p.PFAdd("_tests:jimmy:redis:foo2", "bar") - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } i, err := p.PFAdd("_tests:jimmy:redis:foo2", "bar") - Expect(err).To(BeNil()) - Expect(i).To(Equal(0)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if i != 0 { + t.Errorf("got %d, want 0", i) + } }) }) - Describe("PFCount", func() { - It("Should return the approximate cardinality of the HLL", func() { + t.Run("PFCount", func(t *testing.T) { + t.Run("should return approximate cardinality", func(t *testing.T) { + flushDB() var actualCardinality float64 = 20000 for i := 0; float64(i) < actualCardinality; i++ { _, err := p.PFAdd("_tests:jimmy:redis:foo3", fmt.Sprint(i)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } card, err := p.PFCount("_tests:jimmy:redis:foo3") - Expect(err).To(BeNil()) - // Check a VERY rough 20% accuracy - Expect(float64(card)).To(BeNumerically("<", actualCardinality*1.2)) - Expect(float64(card)).To(BeNumerically(">", actualCardinality*(1-0.2))) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if float64(card) >= actualCardinality*1.2 { + t.Errorf("cardinality %d too high (max %v)", card, actualCardinality*1.2) + } + if float64(card) <= actualCardinality*0.8 { + t.Errorf("cardinality %d too low (min %v)", card, actualCardinality*0.8) + } }) }) - Describe("PFMerge", func() { - It("Should return the approximate cardinality of the union of multiple HLLs", func() { + t.Run("PFMerge", func(t *testing.T) { + t.Run("should return approximate cardinality of union", func(t *testing.T) { + flushDB() setA := []int{1, 2, 3, 4, 5} setB := []int{3, 4, 5, 6, 7} setC := []int{8, 9, 10, 11, 12} for _, x := range setA { _, err := p.PFAdd("_tests:jimmy:redis:hll1", fmt.Sprint(x)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } - for _, x := range setB { _, err := p.PFAdd("_tests:jimmy:redis:hll2", fmt.Sprint(x)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } - for _, x := range setC { _, err := p.PFAdd("_tests:jimmy:redis:hll3", fmt.Sprint(x)) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } for i := 1; i < 4; i++ { card, err := p.PFCount(fmt.Sprintf("_tests:jimmy:redis:hll%d", i)) - Expect(err).To(BeNil()) - Expect(card).To(Equal(5)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 5 { + t.Errorf("hll%d: got %d, want 5", i, card) + } } ok, err := p.PFMerge("_tests:jimmy:redis:hll1+2", "_tests:jimmy:redis:hll1", "_tests:jimmy:redis:hll2") - Expect(err).To(BeNil()) - Expect(ok).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } card, err := p.PFCount("_tests:jimmy:redis:hll1+2") - Expect(err).To(BeNil()) - Expect(card).To(Equal(7)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 7 { + t.Errorf("got %d, want 7", card) + } ok, err = p.PFMerge("_tests:jimmy:redis:hll1+3", "_tests:jimmy:redis:hll1", "_tests:jimmy:redis:hll3") - Expect(err).To(BeNil()) - Expect(ok).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } card, err = p.PFCount("_tests:jimmy:redis:hll1+3") - Expect(err).To(BeNil()) - Expect(card).To(Equal(10)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 10 { + t.Errorf("got %d, want 10", card) + } ok, err = p.PFMerge("_tests:jimmy:redis:hll1+2+3", "_tests:jimmy:redis:hll1", "_tests:jimmy:redis:hll2", "_tests:jimmy:redis:hll3") - Expect(err).To(BeNil()) - Expect(ok).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Error("expected true, got false") + } card, err = p.PFCount("_tests:jimmy:redis:hll1+2+3") - Expect(err).To(BeNil()) - Expect(card).To(Equal(12)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if card != 12 { + t.Errorf("got %d, want 12", card) + } }) }) - Describe("LTrim", func() { - Context("When a list is trimmed", func() { - It("Trims the list", func() { - key := "_tests:jimmy:redis:list" + t.Run("LTrim", func(t *testing.T) { + t.Run("when a list is trimmed", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:list" - for i := 0; i < 5; i++ { - p.LPush(key, fmt.Sprint(i)) - } + for i := range 5 { + p.LPush(key, fmt.Sprint(i)) + } - size, err := p.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(5)) + size, err := p.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 5 { + t.Errorf("got %d, want 5", size) + } - // Trim nothing - err = p.LTrim(key, 0, 4) - Expect(err).To(BeNil()) + // Trim nothing + err = p.LTrim(key, 0, 4) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - size, err = p.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(5)) + size, err = p.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 5 { + t.Errorf("got %d, want 5", size) + } - // Trim first element - err = p.LTrim(key, 1, 5) - Expect(err).To(BeNil()) + // Trim first element + err = p.LTrim(key, 1, 5) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - size, err = p.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(4)) + size, err = p.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 4 { + t.Errorf("got %d, want 4", size) + } - item, err := p.LPop(key) - Expect(err).To(BeNil()) - Expect(item).To(Equal("3")) + item, err := p.LPop(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if item != "3" { + t.Errorf("got %q, want %q", item, "3") + } - // Trim last element - err = p.LTrim(key, -4, -1) - Expect(err).To(BeNil()) + // Trim last element + err = p.LTrim(key, -4, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - size, err = p.LLen(key) - Expect(err).To(BeNil()) - Expect(size).To(Equal(3)) + size, err = p.LLen(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if size != 3 { + t.Errorf("got %d, want 3", size) + } - item, err = p.LPop(key) - Expect(err).To(BeNil()) - Expect(item).To(Equal("2")) - }) + item, err = p.LPop(key) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if item != "2" { + t.Errorf("got %q, want %q", item, "2") + } }) - Context("When a not-list is trimmed", func() { - It("Returns an error", func() { - key := "_tests:jimmy:redis:not-list" + t.Run("when a not-list is trimmed returns error", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:not-list" - Expect(p.Set(key, "yay")).To(BeNil()) - Expect(p.LTrim(key, 0, 4)).ToNot(BeNil()) + if err := p.Set(key, "yay"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := p.LTrim(key, 0, 4); err == nil { + t.Error("expected error, got nil") + } - p.Del(key) - _, err := p.SAdd(key, "yay") - Expect(err).To(BeNil()) - Expect(p.LTrim(key, 0, 4)).ToNot(BeNil()) - }) + p.Del(key) + _, err := p.SAdd(key, "yay") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := p.LTrim(key, 0, 4); err == nil { + t.Error("expected error, got nil") + } }) }) - Describe("LRange", func() { - Context("When an empty list is ranged", func() { - It("Returns nothing, but no err", func() { - key := "_tests:jimmy:redis:list" - things, err := p.LRange(key, 0, -1) - Expect(err).To(BeNil()) - Expect(things).To(BeEmpty()) - }) + t.Run("LRange", func(t *testing.T) { + t.Run("empty list returns nothing", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:list" + things, err := p.LRange(key, 0, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 0 { + t.Errorf("expected empty, got %v", things) + } }) - Context("When a list is ranged", func() { - It("Returns the items", func() { - key := "_tests:jimmy:redis:list" - for i := 0; i < 5; i++ { - _, err := p.LPush(key, fmt.Sprint(i)) - Expect(err).To(BeNil()) + t.Run("list returns items", func(t *testing.T) { + flushDB() + key := "_tests:jimmy:redis:list" + for i := range 5 { + _, err := p.LPush(key, fmt.Sprint(i)) + if err != nil { + t.Fatalf("unexpected error: %v", err) } + } - things, err := p.LRange(key, 0, -1) - Expect(err).To(BeNil()) - Expect(len(things)).To(Equal(5)) + things, err := p.LRange(key, 0, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 5 { + t.Errorf("got len %d, want 5", len(things)) + } - things, err = p.LRange(key, 0, 0) - Expect(err).To(BeNil()) - Expect(len(things)).To(Equal(1)) - Expect(things[0]).To(Equal("4")) + things, err = p.LRange(key, 0, 0) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 1 { + t.Errorf("got len %d, want 1", len(things)) + } + if things[0] != "4" { + t.Errorf("got %q, want %q", things[0], "4") + } - things, err = p.LRange(key, -1, -1) - Expect(err).To(BeNil()) - Expect(len(things)).To(Equal(1)) - Expect(things[0]).To(Equal("0")) - }) + things, err = p.LRange(key, -1, -1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(things) != 1 { + t.Errorf("got len %d, want 1", len(things)) + } + if things[0] != "0" { + t.Errorf("got %q, want %q", things[0], "0") + } }) }) - Describe("SMove", func() { - It("Should move the member to the other set", func() { + t.Run("SMove", func(t *testing.T) { + t.Run("should move member to other set", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:smove" p.SAdd(key+":a", "foobar") moved, err := p.SMove(key+":a", key+":b", "foobar") - Expect(err).To(BeNil()) - Expect(moved).To(BeTrue()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !moved { + t.Error("expected true, got false") + } members, _ := p.SMembers(key + ":a") - Expect(len(members)).To(Equal(0)) + if len(members) != 0 { + t.Errorf("got len %d, want 0", len(members)) + } members, _ = p.SMembers(key + ":b") - Expect(members).To(Equal([]string{"foobar"})) + if len(members) != 1 || members[0] != "foobar" { + t.Errorf("got %v, want [foobar]", members) + } }) }) - Describe("SScan", func() { - It("Should scan the set", func() { + t.Run("SScan", func(t *testing.T) { + t.Run("should scan the set", func(t *testing.T) { + flushDB() key := "_tests:jimmy:redis:sscan" p.SAdd(key, "a", "b", "c", "d", "e") @@ -284,440 +422,660 @@ var _ = Describe("Pool", func() { var err error cursor, matches, err = p.SScan(key, cursor, "", 1) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } scanned = append(scanned, matches...) for cursor != 0 { cursor, matches, err = p.SScan(key, cursor, "", 1) - Expect(err).To(BeNil()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } scanned = append(scanned, matches...) } - Expect(len(scanned)).To(Equal(5)) - Expect(scanned).To(ContainElement("a")) - Expect(scanned).To(ContainElement("b")) - Expect(scanned).To(ContainElement("c")) - Expect(scanned).To(ContainElement("d")) - Expect(scanned).To(ContainElement("e")) + if len(scanned) != 5 { + t.Errorf("got len %d, want 5", len(scanned)) + } + for _, want := range []string{"a", "b", "c", "d", "e"} { + if !containsString(scanned, want) { + t.Errorf("expected %q in %v", want, scanned) + } + } }) }) - Describe("HGet", func() { - Context("a key that exists and contains a hash that contains the requested field with a value", func() { - It("returns the value of that field of that key", func() { - mustSucceed2(p.HSet("foo", "bar", "baz")) - val, err := p.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("baz")) - }) + t.Run("HGet", func(t *testing.T) { + t.Run("key exists with field returns value", func(t *testing.T) { + flushDB() + if _, err := p.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + val, err := p.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "baz" { + t.Errorf("got %q, want %q", val, "baz") + } }) - Context("a key that exists and contains a hash that doesn’t contain the requested field", func() { - It("returns an error and an empty string", func() { - mustSucceed2(p.HSet("foo", "blah", "blech")) - val, err := p.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) - }) + t.Run("key exists without field returns error", func(t *testing.T) { + flushDB() + if _, err := p.HSet("foo", "blah", "blech"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + val, err := p.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } }) - Context("a key that doesn’t exist", func() { - It("returns an error and an empty string", func() { - val, err := p.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) - }) + t.Run("key does not exist returns error", func(t *testing.T) { + flushDB() + val, err := p.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } }) - Context("a key that exists but doesn’t contain a hash", func() { - It("returns an error and an empty string", func() { - mustSucceed1(p.Set("foo", "yo")) - val, err := p.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) - }) + t.Run("key exists but not hash returns error", func(t *testing.T) { + flushDB() + if err := p.Set("foo", "yo"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + val, err := p.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } }) }) - Describe("HGetAll", func() { - Context("a key that exists and contains 2 key/value pairs", func() { - It("returns the 2 pairs and no error", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := p.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := p.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("HGetAll", func(t *testing.T) { + t.Run("key exists with 2 pairs returns pairs", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := p.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that doesn’t exist", func() { - It("returns an empty map and no error", func() { - vals, err := p.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(0)) - }) + t.Run("key does not exist returns empty map", func(t *testing.T) { + flushDB() + vals, err := p.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 0 { + t.Errorf("got len %d, want 0", len(vals)) + } }) }) - Describe("HSet", func() { - Context("a key that doesn’t already exist and two strings", func() { - It("returns true and nil and contain the new pair", func() { - isNew, err := p.HSet("foo", "bar", "baz") - Expect(err).To(BeNil()) - Expect(isNew).To(Equal(true)) + t.Run("HSet", func(t *testing.T) { + t.Run("new key returns true", func(t *testing.T) { + flushDB() + isNew, err := p.HSet("foo", "bar", "baz") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !isNew { + t.Error("expected true, got false") + } - val, err := p.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("baz")) - }) + val, err := p.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "baz" { + t.Errorf("got %q, want %q", val, "baz") + } }) - Context("a key that already exists and a field that it doesn’t already contain", func() { - It("returns true and nil and contain both fields", func() { - mustSucceed2(p.HSet("foo", "bar", "baz")) - isNew, err := p.HSet("foo", "yo", "oy") - Expect(err).To(BeNil()) - Expect(isNew).To(Equal(true)) + t.Run("existing key new field returns true", func(t *testing.T) { + flushDB() + if _, err := p.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + isNew, err := p.HSet("foo", "yo", "oy") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !isNew { + t.Error("expected true, got false") + } - val, err := p.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("baz")) + val, err := p.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "baz" { + t.Errorf("got %q, want %q", val, "baz") + } - val, err = p.HGet("foo", "yo") - Expect(err).To(BeNil()) - Expect(val).To(Equal("oy")) - }) + val, err = p.HGet("foo", "yo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "oy" { + t.Errorf("got %q, want %q", val, "oy") + } }) - Context("a key that already exists and a field that it already contains", func() { - It("returns false and nil and change the value of the field", func() { - mustSucceed2(p.HSet("foo", "bar", "baz")) - isNew, err := p.HSet("foo", "bar", "yo") - Expect(err).To(BeNil()) - Expect(isNew).To(Equal(false)) + t.Run("existing key existing field returns false", func(t *testing.T) { + flushDB() + if _, err := p.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + isNew, err := p.HSet("foo", "bar", "yo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if isNew { + t.Error("expected false, got true") + } - val, err := p.HGet("foo", "bar") - Expect(err).To(BeNil()) - Expect(val).To(Equal("yo")) - }) + val, err := p.HGet("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "yo" { + t.Errorf("got %q, want %q", val, "yo") + } }) - Context("a key that already exists and is not a hash", func() { - It("returns false and an error", func() { - mustSucceed1(p.Set("foo", "bar")) - isNew, err := p.HSet("foo", "bar", "yo") - Expect(err).ToNot(BeNil()) - Expect(isNew).To(Equal(false)) + t.Run("existing key not hash returns error", func(t *testing.T) { + flushDB() + if err := p.Set("foo", "bar"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + isNew, err := p.HSet("foo", "bar", "yo") + if err == nil { + t.Error("expected error, got nil") + } + if isNew { + t.Error("expected false, got true") + } - val, err := p.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) + val, err := p.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } - val, err = p.Get("foo") - Expect(err).To(BeNil()) - Expect(val).To(Equal("bar")) - }) + val, err = p.Get("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "bar" { + t.Errorf("got %q, want %q", val, "bar") + } }) }) - Describe("HMGet", func() { - Context("a key that exists and contains the 2 specified keys", func() { - It("returns the 2 pairs and no error", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := p.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := p.HMGet("foo", "bar", "blah") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("HMGet", func(t *testing.T) { + t.Run("key exists with 2 specified keys", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := p.HMGet("foo", "bar", "blah") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that exists and contains the 2 of the 3 specified keys", func() { - It("returns the 2 pairs and no error", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := p.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := p.HMGet("foo", "bar", "yo", "blah") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(3)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("yo", "")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("key exists with 2 of 3 specified keys", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := p.HMGet("foo", "bar", "yo", "blah") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 3 { + t.Errorf("got len %d, want 3", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["yo"] != "" { + t.Errorf("yo: got %q, want empty string", vals["yo"]) + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that doesn’t exist", func() { - It("returns nil values and no error", func() { - vals, err := p.HMGet("foo", "bar", "blah") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "")) - Expect(vals).To(HaveKeyWithValue("blah", "")) - }) + t.Run("key does not exist", func(t *testing.T) { + flushDB() + vals, err := p.HMGet("foo", "bar", "blah") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "" { + t.Errorf("bar: got %q, want empty string", vals["bar"]) + } + if vals["blah"] != "" { + t.Errorf("blah: got %q, want empty string", vals["blah"]) + } }) - Context("no fields", func() { - It("returns nil values and an error", func() { - vals, err := p.HMGet("foo") - Expect(err).ToNot(BeNil()) - Expect(vals).To(HaveLen(0)) - }) + t.Run("no fields returns error", func(t *testing.T) { + flushDB() + vals, err := p.HMGet("foo") + if err == nil { + t.Error("expected error, got nil") + } + if len(vals) != 0 { + t.Errorf("got len %d, want 0", len(vals)) + } }) }) - Describe("HMSet", func() { - Context("a key that doesn’t already exist and a map with 2 string pairs", func() { - It("returns nil and creates the hash containing the new pairs", func() { - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := p.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := p.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - }) + t.Run("HMSet", func(t *testing.T) { + t.Run("new key with 2 string pairs", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := p.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } }) - Context("a key that doesn’t already exist and a map with 2 int pairs", func() { - It("returns nil and creates the hash containing the new pairs", func() { - in := map[string]interface{}{ - "bar": 18, - "blah": 42, - } - err := p.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := p.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(2)) - Expect(vals).To(HaveKeyWithValue("bar", "18")) - Expect(vals).To(HaveKeyWithValue("blah", "42")) - }) + t.Run("new key with 2 int pairs", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": 18, "blah": 42} + err := p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := p.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 2 { + t.Errorf("got len %d, want 2", len(vals)) + } + if vals["bar"] != "18" { + t.Errorf("bar: got %q, want %q", vals["bar"], "18") + } + if vals["blah"] != "42" { + t.Errorf("blah: got %q, want %q", vals["blah"], "42") + } }) - Context("a key that already exists with 3 pairs and a map with 2 pairs that it already contains", func() { - It("returns nil and changes the hash to contain the fields with their new values, but leaves other fields alone", func() { - in := map[string]interface{}{ - "bar": 18, - "blah": 42, - "yo": "oy", - } - err := p.HMSet("foo", in) - Expect(err).To(BeNil()) + t.Run("existing key with 3 pairs update 2", func(t *testing.T) { + flushDB() + in := map[string]interface{}{"bar": 18, "blah": 42, "yo": "oy"} + err := p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } - in = map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err = p.HMSet("foo", in) - Expect(err).To(BeNil()) - - vals, err := p.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(3)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - Expect(vals).To(HaveKeyWithValue("blah", "blech")) - Expect(vals).To(HaveKeyWithValue("yo", "oy")) - }) + in = map[string]interface{}{"bar": "baz", "blah": "blech"} + err = p.HMSet("foo", in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + vals, err := p.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 3 { + t.Errorf("got len %d, want 3", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } + if vals["blah"] != "blech" { + t.Errorf("blah: got %q, want %q", vals["blah"], "blech") + } + if vals["yo"] != "oy" { + t.Errorf("yo: got %q, want %q", vals["yo"], "oy") + } }) - Context("a key that already exists and is not a hash", func() { - It("returns false and an error", func() { - mustSucceed1(p.Set("foo", "bar")) + t.Run("existing key not hash returns error", func(t *testing.T) { + flushDB() + if err := p.Set("foo", "bar"); err != nil { + t.Fatalf("unexpected error: %v", err) + } - in := map[string]interface{}{ - "bar": "baz", - "blah": "blech", - } - err := p.HMSet("foo", in) - Expect(err).ToNot(BeNil()) + in := map[string]interface{}{"bar": "baz", "blah": "blech"} + err := p.HMSet("foo", in) + if err == nil { + t.Error("expected error, got nil") + } - val, err := p.HGet("foo", "bar") - Expect(err).ToNot(BeNil()) - Expect(val).To(Equal("")) + val, err := p.HGet("foo", "bar") + if err == nil { + t.Error("expected error, got nil") + } + if val != "" { + t.Errorf("got %q, want empty string", val) + } - val, err = p.Get("foo") - Expect(err).To(BeNil()) - Expect(val).To(Equal("bar")) - }) + val, err = p.Get("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if val != "bar" { + t.Errorf("got %q, want %q", val, "bar") + } }) - Context("a key that already exists and an empty map", func() { - It("returns an error and doesn’t change existing the key", func() { - mustSucceed2(p.HSet("foo", "bar", "baz")) - in := map[string]interface{}{} - err := p.HMSet("foo", in) - Expect(err).ToNot(BeNil()) + t.Run("existing key empty map returns error", func(t *testing.T) { + flushDB() + if _, err := p.HSet("foo", "bar", "baz"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + in := map[string]interface{}{} + err := p.HMSet("foo", in) + if err == nil { + t.Error("expected error, got nil") + } - vals, err := p.HGetAll("foo") - Expect(err).To(BeNil()) - Expect(vals).To(HaveLen(1)) - Expect(vals).To(HaveKeyWithValue("bar", "baz")) - }) + vals, err := p.HGetAll("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(vals) != 1 { + t.Errorf("got len %d, want 1", len(vals)) + } + if vals["bar"] != "baz" { + t.Errorf("bar: got %q, want %q", vals["bar"], "baz") + } }) - Context("a key that doesn’t already exist and an empty map", func() { - It("returns an error and doesn’t create the key", func() { - in := map[string]interface{}{} - err := p.HMSet("foo", in) - Expect(err).ToNot(BeNil()) + t.Run("new key empty map returns error", func(t *testing.T) { + flushDB() + in := map[string]interface{}{} + err := p.HMSet("foo", in) + if err == nil { + t.Error("expected error, got nil") + } - exists, err := p.Exists("foo") - Expect(err).To(BeNil()) - Expect(exists).To(BeFalse()) - }) + exists, err := p.Exists("foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists { + t.Error("expected false, got true") + } }) }) - Describe("ZAdd", func() { - Context("happy path", func() { - It("succeeds", func() { - added, err := p.ZAdd("foo", 0.123, "bar") - Expect(err).To(BeNil()) - Expect(added).To(Equal(1)) - }) + t.Run("ZAdd", func(t *testing.T) { + t.Run("happy path", func(t *testing.T) { + flushDB() + added, err := p.ZAdd("foo", 0.123, "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if added != 1 { + t.Errorf("got %d, want 1", added) + } }) }) - Describe("ZRank", func() { - Context("a key that exists", func() { - It("returns a rank", func() { - p.ZAdd("foo", 0.123, "bar") - p.ZAdd("foo", 0.127, "barfu") - rank, err := p.ZRank("foo", "bar") - Expect(err).To(BeNil()) - Expect(rank).To(Equal(0)) - rank, err = p.ZRank("foo", "barfu") - Expect(err).To(BeNil()) - Expect(rank).To(Equal(1)) - }) + t.Run("ZRank", func(t *testing.T) { + t.Run("key exists returns rank", func(t *testing.T) { + flushDB() + p.ZAdd("foo", 0.123, "bar") + p.ZAdd("foo", 0.127, "barfu") + rank, err := p.ZRank("foo", "bar") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if rank != 0 { + t.Errorf("got %d, want 0", rank) + } + rank, err = p.ZRank("foo", "barfu") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if rank != 1 { + t.Errorf("got %d, want 1", rank) + } }) }) - Describe("ZRemRangeByRank", func() { - Context("the rank of a member", func() { - It("removes members with lower or equal rank", func() { - p.ZAdd("foo", 0.123, "bar") - p.ZAdd("foo", 0.127, "barfu") - p.ZAdd("foo", 0.132, "barfoo") - rank, err := p.ZRank("foo", "barfu") - Expect(err).To(BeNil()) - Expect(rank).To(Equal(1)) - total, err := p.ZRemRangeByRank("foo", 0, 1) - Expect(err).To(BeNil()) - Expect(total).To(Equal(2)) - rank, err = p.ZRank("foo", "barfoo") - Expect(err).To(BeNil()) - Expect(rank).To(Equal(0)) - }) + t.Run("ZRemRangeByRank", func(t *testing.T) { + t.Run("removes members with lower or equal rank", func(t *testing.T) { + flushDB() + p.ZAdd("foo", 0.123, "bar") + p.ZAdd("foo", 0.127, "barfu") + p.ZAdd("foo", 0.132, "barfoo") + rank, err := p.ZRank("foo", "barfu") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if rank != 1 { + t.Errorf("got %d, want 1", rank) + } + total, err := p.ZRemRangeByRank("foo", 0, 1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if total != 2 { + t.Errorf("got %d, want 2", total) + } + rank, err = p.ZRank("foo", "barfoo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if rank != 0 { + t.Errorf("got %d, want 0", rank) + } }) }) - Describe("ZRange", func() { - It("returns all elements by range", func() { + t.Run("ZRange", func(t *testing.T) { + t.Run("returns elements by range", func(t *testing.T) { + flushDB() p.ZAdd("foo", 0.123, "bar") p.ZAdd("foo", 0.127, "barfu") p.ZAdd("foo", 0.132, "barfoo") p.ZAdd("foo", 0.133, "barfubar") values, err := p.ZRange("foo", 1, 2) - Expect(err).To(BeNil()) - Expect(values).To(HaveLen(2)) - Expect(values[0]).To(Equal("barfu")) - Expect(values[1]).To(Equal("barfoo")) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(values) != 2 { + t.Fatalf("got len %d, want 2", len(values)) + } + if values[0] != "barfu" { + t.Errorf("got %q, want %q", values[0], "barfu") + } + if values[1] != "barfoo" { + t.Errorf("got %q, want %q", values[1], "barfoo") + } }) }) - Describe("ZRangeWithScores", func() { - It("returns all elements by range", func() { + t.Run("ZRangeWithScores", func(t *testing.T) { + t.Run("returns elements with scores", func(t *testing.T) { + flushDB() p.ZAdd("foo", 0.123, "bar") p.ZAdd("foo", 0.127, "barfu") p.ZAdd("foo", 0.132, "barfoo") p.ZAdd("foo", 0.133, "barfubar") values, err := p.ZRangeWithScores("foo", 1, 2) - Expect(err).To(BeNil()) - Expect(values).To(HaveLen(2)) - Expect(values[0].Value).To(Equal("barfu")) - Expect(values[0].Score).To(Equal(0.127)) - Expect(values[1].Value).To(Equal("barfoo")) - Expect(values[1].Score).To(Equal(0.132)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(values) != 2 { + t.Fatalf("got len %d, want 2", len(values)) + } + if values[0].Value != "barfu" { + t.Errorf("got %q, want %q", values[0].Value, "barfu") + } + if values[0].Score != 0.127 { + t.Errorf("got %v, want %v", values[0].Score, 0.127) + } + if values[1].Value != "barfoo" { + t.Errorf("got %q, want %q", values[1].Value, "barfoo") + } + if values[1].Score != 0.132 { + t.Errorf("got %v, want %v", values[1].Score, 0.132) + } }) }) - Describe("ZRangeByScore", func() { - It("returns all elements by range", func() { + t.Run("ZRangeByScore", func(t *testing.T) { + t.Run("returns elements by score range", func(t *testing.T) { + flushDB() p.ZAdd("foo", 0.123, "bar") p.ZAdd("foo", 0.127, "barfu") p.ZAdd("foo", 0.132, "barfoo") p.ZAdd("foo", 0.133, "barfubar") values, err := p.ZRangeByScore("foo", "(0.123", "0.132") - Expect(err).To(BeNil()) - Expect(values).To(HaveLen(2)) - Expect(values[0]).To(Equal("barfu")) - Expect(values[1]).To(Equal("barfoo")) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(values) != 2 { + t.Fatalf("got len %d, want 2", len(values)) + } + if values[0] != "barfu" { + t.Errorf("got %q, want %q", values[0], "barfu") + } + if values[1] != "barfoo" { + t.Errorf("got %q, want %q", values[1], "barfoo") + } }) }) - Describe("ZRangeByScoreWithScores", func() { - It("returns all elements by range", func() { + t.Run("ZRangeByScoreWithScores", func(t *testing.T) { + t.Run("returns elements with scores by range", func(t *testing.T) { + flushDB() p.ZAdd("foo", 0.123, "bar") p.ZAdd("foo", 0.127, "barfu") p.ZAdd("foo", 0.132, "barfoo") p.ZAdd("foo", 0.133, "barfubar") values, err := p.ZRangeByScoreWithScores("foo", "(0.123", "0.132") - Expect(err).To(BeNil()) - Expect(values).To(HaveLen(2)) - Expect(values[0].Value).To(Equal("barfu")) - Expect(values[0].Score).To(Equal(0.127)) - Expect(values[1].Value).To(Equal("barfoo")) - Expect(values[1].Score).To(Equal(0.132)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(values) != 2 { + t.Fatalf("got len %d, want 2", len(values)) + } + if values[0].Value != "barfu" { + t.Errorf("got %q, want %q", values[0].Value, "barfu") + } + if values[0].Score != 0.127 { + t.Errorf("got %v, want %v", values[0].Score, 0.127) + } + if values[1].Value != "barfoo" { + t.Errorf("got %q, want %q", values[1].Value, "barfoo") + } + if values[1].Score != 0.132 { + t.Errorf("got %v, want %v", values[1].Score, 0.132) + } }) }) - Describe("ZRangeByScoreWithLimit", func() { - It("returns all elements by range", func() { + t.Run("ZRangeByScoreWithLimit", func(t *testing.T) { + t.Run("returns limited elements", func(t *testing.T) { + flushDB() p.ZAdd("foo", 0.123, "bar") p.ZAdd("foo", 0.127, "barfu") p.ZAdd("foo", 0.132, "barfoo") p.ZAdd("foo", 0.133, "barfubar") values, err := p.ZRangeByScoreWithLimit("foo", "(0.123", "0.132", 1, 1) - Expect(err).To(BeNil()) - Expect(values).To(HaveLen(1)) - Expect(values[0]).To(Equal("barfoo")) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(values) != 1 { + t.Fatalf("got len %d, want 1", len(values)) + } + if values[0] != "barfoo" { + t.Errorf("got %q, want %q", values[0], "barfoo") + } }) }) - Describe("ZRangeByScoreWithScoresWithLimit", func() { - It("returns all elements by range", func() { + t.Run("ZRangeByScoreWithScoresWithLimit", func(t *testing.T) { + t.Run("returns limited elements with scores", func(t *testing.T) { + flushDB() p.ZAdd("foo", 0.123, "bar") p.ZAdd("foo", 0.127, "barfu") p.ZAdd("foo", 0.132, "barfoo") p.ZAdd("foo", 0.133, "barfubar") values, err := p.ZRangeByScoreWithScoresWithLimit("foo", "(0.123", "0.132", 1, 1) - Expect(err).To(BeNil()) - Expect(values).To(HaveLen(1)) - Expect(values[0].Value).To(Equal("barfoo")) - Expect(values[0].Score).To(Equal(0.132)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(values) != 1 { + t.Fatalf("got len %d, want 1", len(values)) + } + if values[0].Value != "barfoo" { + t.Errorf("got %q, want %q", values[0].Value, "barfoo") + } + if values[0].Score != 0.132 { + t.Errorf("got %v, want %v", values[0].Score, 0.132) + } }) }) -}) +} diff --git a/redis/redis.go b/redis/redis.go index 3411afe..86e416e 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -7,8 +7,9 @@ import ( var ( ErrNil = redigo.ErrNil - redigoErrNoAuth = redigo.Error("NOAUTH Authentication required.") - redigoErrSentAuth = redigo.Error("ERR Client sent AUTH, but no password is set") + redigoErrNoAuth = redigo.Error("NOAUTH Authentication required.") + redigoErrSentAuth = redigo.Error("ERR Client sent AUTH, but no password is set") + redigoErrSentAuth2 = redigo.Error("ERR AUTH called without any password configured for the default user. Are you sure your configuration is correct?") ) type Z struct { diff --git a/redis/redis_suite_test.go b/redis/redis_suite_test.go deleted file mode 100644 index 593ff0c..0000000 --- a/redis/redis_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package redis_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "testing" -) - -func TestRedis(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Redis Suite") -} diff --git a/redis/redisurl/redisurl.go b/redis/redisurl/redisurl.go index a02a3cd..92e6bbd 100644 --- a/redis/redisurl/redisurl.go +++ b/redis/redisurl/redisurl.go @@ -17,13 +17,11 @@ func Connect() (redis.Conn, error) { func ConnectToURL(s string) (c redis.Conn, err error) { redisURL, err := url.Parse(s) - if err != nil { - return + return nil, err } auth := "" - if redisURL.User != nil { if password, ok := redisURL.User.Password(); ok { auth = password @@ -31,25 +29,26 @@ func ConnectToURL(s string) (c redis.Conn, err error) { } c, err = redis.Dial("tcp", redisURL.Host) - if err != nil { fmt.Println(err) - return + return nil, err } if len(auth) > 0 { _, err = c.Do("AUTH", auth) - if err != nil { fmt.Println(err) - return + return c, err } } if len(redisURL.Path) > 1 { db := strings.TrimPrefix(redisURL.Path, "/") - c.Do("SELECT", db) + _, err = c.Do("SELECT", db) + if err != nil { + return c, err + } } - return + return c, err } diff --git a/redis/redisurl/redisurl_test.go b/redis/redisurl/redisurl_test.go index 3fb1921..1b0b34d 100644 --- a/redis/redisurl/redisurl_test.go +++ b/redis/redisurl/redisurl_test.go @@ -9,10 +9,14 @@ import ( func TestConnect(t *testing.T) { c, err := redisurl.Connect() - if err != nil { - t.Errorf("Error returned") + t.Fatalf("Error returned: %v", err) + } + + if c == nil { + t.Fatal("Connection is nil") } + defer c.Close() pong, err := redis.String(c.Do("PING")) @@ -24,3 +28,42 @@ func TestConnect(t *testing.T) { t.Errorf("Wanted PONG, got %v\n", pong) } } + +func TestConnectToURL_InvalidURL(t *testing.T) { + c, err := redisurl.ConnectToURL("://invalid url") + if err == nil { + t.Error("Expected error for invalid URL, got nil") + } + + if c != nil { + t.Error("Expected nil connection for invalid URL") + } +} + +func TestConnectToURL_InvalidHost(t *testing.T) { + c, err := redisurl.ConnectToURL("redis://nonexistent-host-12345:6379") + if err == nil { + t.Error("Expected error for invalid host, got nil") + } + + // This is the critical check - connection should be nil on error + if c != nil { + t.Error("Expected nil connection when dial fails") + } +} + +func TestConnectToURL_WithAuth(t *testing.T) { + c, err := redisurl.ConnectToURL("redis://:password@localhost:6379/10") + // When AUTH fails, connection is returned so caller can check error type and retry + if err != nil { + if c == nil { + t.Error("Connection should be returned even when AUTH fails (for fallback logic)") + } else { + c.Close() // Caller's responsibility to close on error + } + } + + if c != nil && err == nil { + defer c.Close() + } +}