redis_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. package redis_test
  2. import (
  3. "bytes"
  4. "net"
  5. "time"
  6. "gopkg.in/redis.v5"
  7. . "github.com/onsi/ginkgo"
  8. . "github.com/onsi/gomega"
  9. )
  10. var _ = Describe("Client", func() {
  11. var client *redis.Client
  12. BeforeEach(func() {
  13. client = redis.NewClient(redisOptions())
  14. Expect(client.FlushDb().Err()).NotTo(HaveOccurred())
  15. })
  16. AfterEach(func() {
  17. client.Close()
  18. })
  19. It("should Stringer", func() {
  20. Expect(client.String()).To(Equal("Redis<:6380 db:15>"))
  21. })
  22. It("should ping", func() {
  23. val, err := client.Ping().Result()
  24. Expect(err).NotTo(HaveOccurred())
  25. Expect(val).To(Equal("PONG"))
  26. })
  27. It("should return pool stats", func() {
  28. Expect(client.PoolStats()).To(BeAssignableToTypeOf(&redis.PoolStats{}))
  29. })
  30. It("should support custom dialers", func() {
  31. custom := redis.NewClient(&redis.Options{
  32. Addr: ":1234",
  33. Dialer: func() (net.Conn, error) {
  34. return net.Dial("tcp", redisAddr)
  35. },
  36. })
  37. val, err := custom.Ping().Result()
  38. Expect(err).NotTo(HaveOccurred())
  39. Expect(val).To(Equal("PONG"))
  40. Expect(custom.Close()).NotTo(HaveOccurred())
  41. })
  42. It("should close", func() {
  43. Expect(client.Close()).NotTo(HaveOccurred())
  44. err := client.Ping().Err()
  45. Expect(err).To(MatchError("redis: client is closed"))
  46. })
  47. It("should close pubsub without closing the client", func() {
  48. pubsub, err := client.Subscribe()
  49. Expect(pubsub.Close()).NotTo(HaveOccurred())
  50. _, err = pubsub.Receive()
  51. Expect(err).To(MatchError("redis: client is closed"))
  52. Expect(client.Ping().Err()).NotTo(HaveOccurred())
  53. })
  54. It("should close Tx without closing the client", func() {
  55. err := client.Watch(func(tx *redis.Tx) error {
  56. _, err := tx.Pipelined(func(pipe *redis.Pipeline) error {
  57. pipe.Ping()
  58. return nil
  59. })
  60. return err
  61. })
  62. Expect(err).NotTo(HaveOccurred())
  63. Expect(client.Ping().Err()).NotTo(HaveOccurred())
  64. })
  65. It("should close pipeline without closing the client", func() {
  66. pipeline := client.Pipeline()
  67. Expect(pipeline.Close()).NotTo(HaveOccurred())
  68. pipeline.Ping()
  69. _, err := pipeline.Exec()
  70. Expect(err).To(MatchError("redis: client is closed"))
  71. Expect(client.Ping().Err()).NotTo(HaveOccurred())
  72. })
  73. It("should close pubsub when client is closed", func() {
  74. pubsub, err := client.Subscribe()
  75. Expect(client.Close()).NotTo(HaveOccurred())
  76. _, err = pubsub.Receive()
  77. Expect(err).To(HaveOccurred())
  78. Expect(pubsub.Close()).NotTo(HaveOccurred())
  79. })
  80. It("should close pipeline when client is closed", func() {
  81. pipeline := client.Pipeline()
  82. Expect(client.Close()).NotTo(HaveOccurred())
  83. Expect(pipeline.Close()).NotTo(HaveOccurred())
  84. })
  85. It("should select DB", func() {
  86. db2 := redis.NewClient(&redis.Options{
  87. Addr: redisAddr,
  88. DB: 2,
  89. })
  90. Expect(db2.FlushDb().Err()).NotTo(HaveOccurred())
  91. Expect(db2.Get("db").Err()).To(Equal(redis.Nil))
  92. Expect(db2.Set("db", 2, 0).Err()).NotTo(HaveOccurred())
  93. n, err := db2.Get("db").Int64()
  94. Expect(err).NotTo(HaveOccurred())
  95. Expect(n).To(Equal(int64(2)))
  96. Expect(client.Get("db").Err()).To(Equal(redis.Nil))
  97. Expect(db2.FlushDb().Err()).NotTo(HaveOccurred())
  98. Expect(db2.Close()).NotTo(HaveOccurred())
  99. })
  100. It("processes custom commands", func() {
  101. cmd := redis.NewCmd("PING")
  102. client.Process(cmd)
  103. // Flush buffers.
  104. Expect(client.Echo("hello").Err()).NotTo(HaveOccurred())
  105. Expect(cmd.Err()).NotTo(HaveOccurred())
  106. Expect(cmd.Val()).To(Equal("PONG"))
  107. })
  108. It("should retry command on network error", func() {
  109. Expect(client.Close()).NotTo(HaveOccurred())
  110. client = redis.NewClient(&redis.Options{
  111. Addr: redisAddr,
  112. MaxRetries: 1,
  113. })
  114. // Put bad connection in the pool.
  115. cn, _, err := client.Pool().Get()
  116. Expect(err).NotTo(HaveOccurred())
  117. cn.SetNetConn(&badConn{})
  118. err = client.Pool().Put(cn)
  119. Expect(err).NotTo(HaveOccurred())
  120. err = client.Ping().Err()
  121. Expect(err).NotTo(HaveOccurred())
  122. })
  123. It("should update conn.UsedAt on read/write", func() {
  124. cn, _, err := client.Pool().Get()
  125. Expect(err).NotTo(HaveOccurred())
  126. Expect(cn.UsedAt).NotTo(BeZero())
  127. createdAt := cn.UsedAt()
  128. err = client.Pool().Put(cn)
  129. Expect(err).NotTo(HaveOccurred())
  130. Expect(cn.UsedAt().Equal(createdAt)).To(BeTrue())
  131. err = client.Ping().Err()
  132. Expect(err).NotTo(HaveOccurred())
  133. cn, _, err = client.Pool().Get()
  134. Expect(err).NotTo(HaveOccurred())
  135. Expect(cn).NotTo(BeNil())
  136. Expect(cn.UsedAt().After(createdAt)).To(BeTrue())
  137. })
  138. It("should process command with special chars", func() {
  139. set := client.Set("key", "hello1\r\nhello2\r\n", 0)
  140. Expect(set.Err()).NotTo(HaveOccurred())
  141. Expect(set.Val()).To(Equal("OK"))
  142. get := client.Get("key")
  143. Expect(get.Err()).NotTo(HaveOccurred())
  144. Expect(get.Val()).To(Equal("hello1\r\nhello2\r\n"))
  145. })
  146. It("should handle big vals", func() {
  147. bigVal := bytes.Repeat([]byte{'*'}, 2e6)
  148. err := client.Set("key", bigVal, 0).Err()
  149. Expect(err).NotTo(HaveOccurred())
  150. // Reconnect to get new connection.
  151. Expect(client.Close()).NotTo(HaveOccurred())
  152. client = redis.NewClient(redisOptions())
  153. got, err := client.Get("key").Bytes()
  154. Expect(err).NotTo(HaveOccurred())
  155. Expect(got).To(Equal(bigVal))
  156. })
  157. It("should call WrapProcess", func() {
  158. var wrapperFnCalled bool
  159. client.WrapProcess(func(oldProcess func(redis.Cmder) error) func(redis.Cmder) error {
  160. return func(cmd redis.Cmder) error {
  161. wrapperFnCalled = true
  162. return oldProcess(cmd)
  163. }
  164. })
  165. Expect(client.Ping().Err()).NotTo(HaveOccurred())
  166. Expect(wrapperFnCalled).To(BeTrue())
  167. })
  168. })
  169. var _ = Describe("Client timeout", func() {
  170. var client *redis.Client
  171. AfterEach(func() {
  172. Expect(client.Close()).NotTo(HaveOccurred())
  173. })
  174. testTimeout := func() {
  175. It("Ping timeouts", func() {
  176. err := client.Ping().Err()
  177. Expect(err).To(HaveOccurred())
  178. Expect(err.(net.Error).Timeout()).To(BeTrue())
  179. })
  180. It("Pipeline timeouts", func() {
  181. _, err := client.Pipelined(func(pipe *redis.Pipeline) error {
  182. pipe.Ping()
  183. return nil
  184. })
  185. Expect(err).To(HaveOccurred())
  186. Expect(err.(net.Error).Timeout()).To(BeTrue())
  187. })
  188. It("Subscribe timeouts", func() {
  189. _, err := client.Subscribe("_")
  190. Expect(err).To(HaveOccurred())
  191. Expect(err.(net.Error).Timeout()).To(BeTrue())
  192. })
  193. It("Tx timeouts", func() {
  194. err := client.Watch(func(tx *redis.Tx) error {
  195. return tx.Ping().Err()
  196. })
  197. Expect(err).To(HaveOccurred())
  198. Expect(err.(net.Error).Timeout()).To(BeTrue())
  199. })
  200. It("Tx Pipeline timeouts", func() {
  201. err := client.Watch(func(tx *redis.Tx) error {
  202. _, err := tx.Pipelined(func(pipe *redis.Pipeline) error {
  203. pipe.Ping()
  204. return nil
  205. })
  206. return err
  207. })
  208. Expect(err).To(HaveOccurred())
  209. Expect(err.(net.Error).Timeout()).To(BeTrue())
  210. })
  211. }
  212. Context("read timeout", func() {
  213. BeforeEach(func() {
  214. opt := redisOptions()
  215. opt.ReadTimeout = time.Nanosecond
  216. opt.WriteTimeout = -1
  217. client = redis.NewClient(opt)
  218. })
  219. testTimeout()
  220. })
  221. Context("write timeout", func() {
  222. BeforeEach(func() {
  223. opt := redisOptions()
  224. opt.ReadTimeout = -1
  225. opt.WriteTimeout = time.Nanosecond
  226. client = redis.NewClient(opt)
  227. })
  228. testTimeout()
  229. })
  230. })