mirror of
https://github.com/hanzokv/go.git
synced 2026-09-24 00:31:51 +00:00
* Add DoRaw and DoRawWriteTo for raw RESP protocol access * fix augment comments * Pipeline retry fix * Fix Missing NoRetry check in cluster and ring retry loops
544 lines
16 KiB
Go
544 lines
16 KiB
Go
package redis_test
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
|
|
. "github.com/bsm/ginkgo/v2"
|
|
. "github.com/bsm/gomega"
|
|
)
|
|
|
|
// parseRESPType returns the RESP type character and validates basic structure
|
|
func parseRESPType(data []byte) (byte, bool) {
|
|
if len(data) < 3 {
|
|
return 0, false
|
|
}
|
|
// Check for CRLF at the end
|
|
if !bytes.HasSuffix(data, []byte("\r\n")) {
|
|
return 0, false
|
|
}
|
|
return data[0], true
|
|
}
|
|
|
|
// countRESPElements counts the number of elements in a RESP array/map response
|
|
func countRESPElements(data []byte) (int, bool) {
|
|
if len(data) < 4 {
|
|
return 0, false
|
|
}
|
|
// Find first CRLF
|
|
idx := bytes.Index(data, []byte("\r\n"))
|
|
if idx < 2 {
|
|
return 0, false
|
|
}
|
|
count, err := strconv.Atoi(string(data[1:idx]))
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
return count, true
|
|
}
|
|
|
|
var _ = Describe("Cmd", func() {
|
|
var client *redis.Client
|
|
|
|
BeforeEach(func() {
|
|
client = redis.NewClient(redisOptions())
|
|
Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
|
|
})
|
|
|
|
AfterEach(func() {
|
|
Expect(client.Close()).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("implements Stringer", func() {
|
|
set := client.Set(ctx, "foo", "bar", 0)
|
|
Expect(set.String()).To(Equal("set foo bar: OK"))
|
|
|
|
get := client.Get(ctx, "foo")
|
|
Expect(get.String()).To(Equal("get foo: bar"))
|
|
})
|
|
|
|
It("has val/err", func() {
|
|
set := client.Set(ctx, "key", "hello", 0)
|
|
Expect(set.Err()).NotTo(HaveOccurred())
|
|
Expect(set.Val()).To(Equal("OK"))
|
|
|
|
get := client.Get(ctx, "key")
|
|
Expect(get.Err()).NotTo(HaveOccurred())
|
|
Expect(get.Val()).To(Equal("hello"))
|
|
|
|
Expect(set.Err()).NotTo(HaveOccurred())
|
|
Expect(set.Val()).To(Equal("OK"))
|
|
})
|
|
|
|
It("has helpers", func() {
|
|
set := client.Set(ctx, "key", "10", 0)
|
|
Expect(set.Err()).NotTo(HaveOccurred())
|
|
|
|
n, err := client.Get(ctx, "key").Int64()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(n).To(Equal(int64(10)))
|
|
|
|
un, err := client.Get(ctx, "key").Uint64()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(un).To(Equal(uint64(10)))
|
|
|
|
f, err := client.Get(ctx, "key").Float64()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(f).To(Equal(float64(10)))
|
|
})
|
|
|
|
It("supports float32", func() {
|
|
f := float32(66.97)
|
|
|
|
err := client.Set(ctx, "float_key", f, 0).Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
val, err := client.Get(ctx, "float_key").Float32()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(val).To(Equal(f))
|
|
})
|
|
|
|
It("supports time.Time", func() {
|
|
tm := time.Date(2019, 1, 1, 9, 45, 10, 222125, time.UTC)
|
|
|
|
err := client.Set(ctx, "time_key", tm, 0).Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
s, err := client.Get(ctx, "time_key").Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(s).To(Equal("2019-01-01T09:45:10.000222125Z"))
|
|
|
|
tm2, err := client.Get(ctx, "time_key").Time()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(tm2).To(BeTemporally("==", tm))
|
|
})
|
|
|
|
It("allows to set custom error", func() {
|
|
e := errors.New("custom error")
|
|
cmd := redis.Cmd{}
|
|
cmd.SetErr(e)
|
|
_, err := cmd.Result()
|
|
Expect(err).To(Equal(e))
|
|
})
|
|
})
|
|
|
|
var _ = Describe("RawCmd", func() {
|
|
var client *redis.Client
|
|
|
|
BeforeEach(func() {
|
|
client = redis.NewClient(redisOptions())
|
|
Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
|
|
})
|
|
|
|
AfterEach(func() {
|
|
Expect(client.Close()).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("returns raw RESP bytes for simple string (PING)", func() {
|
|
cmd := client.DoRaw(ctx, "PING")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(Equal("+PONG\r\n"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for bulk string (GET)", func() {
|
|
err := client.Set(ctx, "rawtest", "hello", 0).Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
cmd := client.DoRaw(ctx, "GET", "rawtest")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(Equal("$5\r\nhello\r\n"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for integer (INCR)", func() {
|
|
err := client.Set(ctx, "counter", "10", 0).Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
cmd := client.DoRaw(ctx, "INCR", "counter")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(Equal(":11\r\n"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for array (KEYS) with validation", func() {
|
|
err := client.Set(ctx, "key1", "val1", 0).Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
err = client.Set(ctx, "key2", "val2", 0).Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
cmd := client.DoRaw(ctx, "KEYS", "key*")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Validate RESP structure
|
|
respType, valid := parseRESPType(rawBytes)
|
|
Expect(valid).To(BeTrue())
|
|
Expect(respType).To(Equal(byte('*')), "Should be array type")
|
|
|
|
// Verify element count
|
|
count, ok := countRESPElements(rawBytes)
|
|
Expect(ok).To(BeTrue())
|
|
Expect(count).To(Equal(2))
|
|
|
|
// Verify keys are present in the raw bytes
|
|
rawStr := string(rawBytes)
|
|
Expect(rawStr).To(ContainSubstring("key1"))
|
|
Expect(rawStr).To(ContainSubstring("key2"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for HGETALL with complete validation", func() {
|
|
err := client.HSet(ctx, "myhash", "field1", "value1", "field2", "value2").Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
cmd := client.DoRaw(ctx, "HGETALL", "myhash")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Validate RESP structure
|
|
respType, valid := parseRESPType(rawBytes)
|
|
Expect(valid).To(BeTrue(), "Response should be valid RESP")
|
|
|
|
// HGETALL returns array (RESP2) or map (RESP3)
|
|
Expect(respType).To(BeElementOf(byte('*'), byte('%')), "Should be array or map type")
|
|
|
|
// Count elements: array has 4 elements (2 key-value pairs), map has 2 pairs
|
|
count, ok := countRESPElements(rawBytes)
|
|
Expect(ok).To(BeTrue())
|
|
if respType == '*' {
|
|
Expect(count).To(Equal(4), "Array should have 4 elements (2 key-value pairs)")
|
|
} else {
|
|
Expect(count).To(Equal(2), "Map should have 2 pairs")
|
|
}
|
|
|
|
rawStr := string(rawBytes)
|
|
Expect(rawStr).To(ContainSubstring("field1"))
|
|
Expect(rawStr).To(ContainSubstring("value1"))
|
|
Expect(rawStr).To(ContainSubstring("field2"))
|
|
Expect(rawStr).To(ContainSubstring("value2"))
|
|
|
|
// Verify response ends with CRLF
|
|
Expect(rawBytes[len(rawBytes)-2:]).To(Equal([]byte("\r\n")))
|
|
})
|
|
|
|
It("returns raw RESP bytes for nil value", func() {
|
|
cmd := client.DoRaw(ctx, "GET", "nonexistent")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
rawStr := string(rawBytes)
|
|
Expect(rawStr == "$-1\r\n" || rawStr == "_\r\n").To(BeTrue())
|
|
})
|
|
|
|
It("returns raw RESP bytes for empty array", func() {
|
|
cmd := client.DoRaw(ctx, "KEYS", "nonexistent*")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(Equal("*0\r\n"))
|
|
})
|
|
|
|
It("has Val and Bytes methods", func() {
|
|
cmd := client.DoRaw(ctx, "PING")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
|
|
val := cmd.Val()
|
|
Expect(string(val)).To(Equal("+PONG\r\n"))
|
|
|
|
bytes, err := cmd.Bytes()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(bytes)).To(Equal("+PONG\r\n"))
|
|
})
|
|
|
|
It("implements Stringer", func() {
|
|
cmd := client.DoRaw(ctx, "PING")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
Expect(cmd.String()).To(ContainSubstring("PING"))
|
|
})
|
|
|
|
It("allows to set custom error", func() {
|
|
e := errors.New("custom error")
|
|
cmd := redis.RawCmd{}
|
|
cmd.SetErr(e)
|
|
_, err := cmd.Result()
|
|
Expect(err).To(Equal(e))
|
|
})
|
|
|
|
It("can be cloned", func() {
|
|
cmd := client.DoRaw(ctx, "PING")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
|
|
cloned := cmd.Clone().(*redis.RawCmd)
|
|
Expect(cloned.Val()).To(Equal(cmd.Val()))
|
|
originalVal := cmd.Val()
|
|
clonedVal := cloned.Val()
|
|
Expect(&originalVal[0]).NotTo(BeIdenticalTo(&clonedVal[0]))
|
|
})
|
|
|
|
It("returns raw RESP bytes for error response", func() {
|
|
cmd := client.DoRaw(ctx, "INVALIDCMD")
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(HavePrefix("-"))
|
|
Expect(string(rawBytes)).To(ContainSubstring("ERR"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for empty hash (nil map)", func() {
|
|
// HGETALL on non-existent hash returns empty array/map
|
|
cmd := client.DoRaw(ctx, "HGETALL", "nonexistent_hash")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
respType, valid := parseRESPType(rawBytes)
|
|
Expect(valid).To(BeTrue())
|
|
// Should be empty array or empty map
|
|
Expect(respType).To(BeElementOf(byte('*'), byte('%')))
|
|
|
|
count, ok := countRESPElements(rawBytes)
|
|
Expect(ok).To(BeTrue())
|
|
Expect(count).To(Equal(0), "Empty hash should return 0 elements")
|
|
})
|
|
|
|
It("returns raw RESP bytes for nested array structures (SMEMBERS)", func() {
|
|
// Create a set with multiple members
|
|
err := client.SAdd(ctx, "myset", "member1", "member2", "member3").Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
cmd := client.DoRaw(ctx, "SMEMBERS", "myset")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Validate basic RESP structure
|
|
respType, valid := parseRESPType(rawBytes)
|
|
Expect(valid).To(BeTrue())
|
|
// SMEMBERS returns array (RESP2) or set (RESP3)
|
|
Expect(respType).To(BeElementOf(byte('*'), byte('~')))
|
|
|
|
// Verify count
|
|
count, ok := countRESPElements(rawBytes)
|
|
Expect(ok).To(BeTrue())
|
|
Expect(count).To(Equal(3))
|
|
|
|
// Verify members are present
|
|
rawStr := string(rawBytes)
|
|
Expect(rawStr).To(ContainSubstring("member1"))
|
|
Expect(rawStr).To(ContainSubstring("member2"))
|
|
Expect(rawStr).To(ContainSubstring("member3"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for LRANGE with exact byte validation", func() {
|
|
// Create a list with multiple elements
|
|
err := client.RPush(ctx, "mylist", "elem1", "elem2", "elem3").Err()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
cmd := client.DoRaw(ctx, "LRANGE", "mylist", "0", "-1")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// LRANGE returns elements in order, so we can validate exact bytes
|
|
expectedResp := "*3\r\n$5\r\nelem1\r\n$5\r\nelem2\r\n$5\r\nelem3\r\n"
|
|
Expect(string(rawBytes)).To(Equal(expectedResp))
|
|
})
|
|
|
|
It("returns raw RESP bytes for LPUSH with exact integer response", func() {
|
|
// LPUSH returns the length of the list after push
|
|
cmd := client.DoRaw(ctx, "LPUSH", "newlist", "item")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(Equal(":1\r\n"))
|
|
})
|
|
|
|
It("returns raw RESP bytes for ECHO with exact bulk string", func() {
|
|
cmd := client.DoRaw(ctx, "ECHO", "testmsg")
|
|
Expect(cmd.Err()).NotTo(HaveOccurred())
|
|
rawBytes, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(rawBytes)).To(Equal("$7\r\ntestmsg\r\n"))
|
|
})
|
|
})
|
|
|
|
var _ = Describe("RawWriteToCmd", func() {
|
|
var client *redis.Client
|
|
|
|
BeforeEach(func() {
|
|
client = redis.NewClient(redisOptions())
|
|
Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
|
|
})
|
|
|
|
AfterEach(func() {
|
|
Expect(client.Close()).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("streams raw RESP bytes for PING", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "PING")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(7)))
|
|
Expect(buf.String()).To(Equal("+PONG\r\n"))
|
|
})
|
|
|
|
It("streams raw RESP bytes for bulk string (GET)", func() {
|
|
client.Set(ctx, "rawkey", "rawvalue", 0)
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "GET", "rawkey")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(BeNumerically(">", 0))
|
|
Expect(buf.String()).To(Equal("$8\r\nrawvalue\r\n"))
|
|
})
|
|
|
|
It("streams raw RESP bytes for integer (INCR)", func() {
|
|
client.Set(ctx, "writeto_counter", "10", 0)
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "INCR", "writeto_counter")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(5)))
|
|
Expect(buf.String()).To(Equal(":11\r\n"))
|
|
})
|
|
|
|
It("streams raw RESP bytes for nil value (GET non-existent)", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "GET", "nonexistent_key")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(buf.Len())))
|
|
rawStr := buf.String()
|
|
// RESP2 returns $-1\r\n, RESP3 returns _\r\n
|
|
Expect(rawStr == "$-1\r\n" || rawStr == "_\r\n").To(BeTrue())
|
|
})
|
|
|
|
It("streams raw RESP bytes for array (LRANGE) with exact validation", func() {
|
|
client.RPush(ctx, "writeto_list", "a", "b", "c")
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "LRANGE", "writeto_list", "0", "-1")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(buf.Len())))
|
|
// LRANGE returns elements in order
|
|
expectedResp := "*3\r\n$1\r\na\r\n$1\r\nb\r\n$1\r\nc\r\n"
|
|
Expect(buf.String()).To(Equal(expectedResp))
|
|
})
|
|
|
|
It("streams raw RESP bytes for empty array (LRANGE empty list)", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "LRANGE", "nonexistent_list", "0", "-1")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(buf.Len())))
|
|
Expect(buf.String()).To(Equal("*0\r\n"))
|
|
})
|
|
|
|
It("streams raw RESP bytes for HGETALL", func() {
|
|
client.HSet(ctx, "rawhash", "f1", "v1", "f2", "v2")
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "HGETALL", "rawhash")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(BeNumerically(">", 0))
|
|
raw := buf.String()
|
|
Expect(raw).To(ContainSubstring("f1"))
|
|
Expect(raw).To(ContainSubstring("v1"))
|
|
})
|
|
|
|
It("returns correct byte count", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "PING")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(buf.Len())))
|
|
})
|
|
|
|
It("implements Stringer", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "PING")
|
|
Expect(cmd.String()).To(ContainSubstring("PING"))
|
|
})
|
|
|
|
It("can be cloned", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "PING")
|
|
clone := cmd.Clone().(*redis.RawWriteToCmd)
|
|
Expect(clone.Val()).To(Equal(cmd.Val()))
|
|
})
|
|
|
|
It("streams HGETALL with complete validation", func() {
|
|
client.HSet(ctx, "rawhash2", "key1", "val1", "key2", "val2")
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "HGETALL", "rawhash2")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Verify written bytes match buffer length
|
|
Expect(written).To(Equal(int64(buf.Len())))
|
|
|
|
// Validate RESP structure
|
|
rawBytes := buf.Bytes()
|
|
respType, valid := parseRESPType(rawBytes)
|
|
Expect(valid).To(BeTrue())
|
|
Expect(respType).To(BeElementOf(byte('*'), byte('%')))
|
|
|
|
// Verify all data present
|
|
rawStr := buf.String()
|
|
Expect(rawStr).To(ContainSubstring("key1"))
|
|
Expect(rawStr).To(ContainSubstring("val1"))
|
|
Expect(rawStr).To(ContainSubstring("key2"))
|
|
Expect(rawStr).To(ContainSubstring("val2"))
|
|
})
|
|
|
|
It("streams empty hash correctly", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "HGETALL", "nonexistent_hash")
|
|
written, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(written).To(Equal(int64(buf.Len())))
|
|
|
|
rawBytes := buf.Bytes()
|
|
respType, valid := parseRESPType(rawBytes)
|
|
Expect(valid).To(BeTrue())
|
|
Expect(respType).To(BeElementOf(byte('*'), byte('%')))
|
|
|
|
count, ok := countRESPElements(rawBytes)
|
|
Expect(ok).To(BeTrue())
|
|
Expect(count).To(Equal(0))
|
|
})
|
|
|
|
It("streams error response correctly", func() {
|
|
var buf bytes.Buffer
|
|
cmd := client.DoRawWriteTo(ctx, &buf, "INVALIDCMD")
|
|
_, err := cmd.Result()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
rawStr := buf.String()
|
|
Expect(rawStr).To(HavePrefix("-"))
|
|
Expect(rawStr).To(ContainSubstring("ERR"))
|
|
})
|
|
})
|
|
|
|
var _ = Describe("NoRetry behavior", func() {
|
|
It("RawCmd does not have NoRetry set", func() {
|
|
cmd := redis.NewRawCmd(ctx, "PING")
|
|
Expect(cmd.NoRetry()).To(BeFalse())
|
|
})
|
|
|
|
It("RawWriteToCmd has NoRetry set to prevent data corruption", func() {
|
|
var buf bytes.Buffer
|
|
cmd := redis.NewRawWriteToCmd(ctx, &buf, "PING")
|
|
Expect(cmd.NoRetry()).To(BeTrue())
|
|
})
|
|
})
|