race_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. package redis_test
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "net"
  7. "strconv"
  8. "sync/atomic"
  9. "testing"
  10. "time"
  11. "github.com/go-redis/redis/v7"
  12. . "github.com/onsi/ginkgo"
  13. . "github.com/onsi/gomega"
  14. )
  15. var _ = Describe("races", func() {
  16. var client *redis.Client
  17. var C, N int
  18. BeforeEach(func() {
  19. client = redis.NewClient(redisOptions())
  20. Expect(client.FlushDB().Err()).To(BeNil())
  21. C, N = 10, 1000
  22. if testing.Short() {
  23. C = 4
  24. N = 100
  25. }
  26. })
  27. AfterEach(func() {
  28. err := client.Close()
  29. Expect(err).NotTo(HaveOccurred())
  30. })
  31. It("should echo", func() {
  32. perform(C, func(id int) {
  33. for i := 0; i < N; i++ {
  34. msg := fmt.Sprintf("echo %d %d", id, i)
  35. echo, err := client.Echo(msg).Result()
  36. Expect(err).NotTo(HaveOccurred())
  37. Expect(echo).To(Equal(msg))
  38. }
  39. })
  40. })
  41. It("should incr", func() {
  42. key := "TestIncrFromGoroutines"
  43. perform(C, func(id int) {
  44. for i := 0; i < N; i++ {
  45. err := client.Incr(key).Err()
  46. Expect(err).NotTo(HaveOccurred())
  47. }
  48. })
  49. val, err := client.Get(key).Int64()
  50. Expect(err).NotTo(HaveOccurred())
  51. Expect(val).To(Equal(int64(C * N)))
  52. })
  53. It("should handle many keys", func() {
  54. perform(C, func(id int) {
  55. for i := 0; i < N; i++ {
  56. err := client.Set(
  57. fmt.Sprintf("keys.key-%d-%d", id, i),
  58. fmt.Sprintf("hello-%d-%d", id, i),
  59. 0,
  60. ).Err()
  61. Expect(err).NotTo(HaveOccurred())
  62. }
  63. })
  64. keys := client.Keys("keys.*")
  65. Expect(keys.Err()).NotTo(HaveOccurred())
  66. Expect(len(keys.Val())).To(Equal(C * N))
  67. })
  68. It("should handle many keys 2", func() {
  69. perform(C, func(id int) {
  70. keys := []string{"non-existent-key"}
  71. for i := 0; i < N; i++ {
  72. key := fmt.Sprintf("keys.key-%d", i)
  73. keys = append(keys, key)
  74. err := client.Set(key, fmt.Sprintf("hello-%d", i), 0).Err()
  75. Expect(err).NotTo(HaveOccurred())
  76. }
  77. keys = append(keys, "non-existent-key")
  78. vals, err := client.MGet(keys...).Result()
  79. Expect(err).NotTo(HaveOccurred())
  80. Expect(len(vals)).To(Equal(N + 2))
  81. for i := 0; i < N; i++ {
  82. Expect(vals[i+1]).To(Equal(fmt.Sprintf("hello-%d", i)))
  83. }
  84. Expect(vals[0]).To(BeNil())
  85. Expect(vals[N+1]).To(BeNil())
  86. })
  87. })
  88. It("should handle big vals in Get", func() {
  89. C, N = 4, 100
  90. bigVal := bigVal()
  91. err := client.Set("key", bigVal, 0).Err()
  92. Expect(err).NotTo(HaveOccurred())
  93. // Reconnect to get new connection.
  94. Expect(client.Close()).To(BeNil())
  95. client = redis.NewClient(redisOptions())
  96. perform(C, func(id int) {
  97. for i := 0; i < N; i++ {
  98. got, err := client.Get("key").Bytes()
  99. Expect(err).NotTo(HaveOccurred())
  100. Expect(got).To(Equal(bigVal))
  101. }
  102. })
  103. })
  104. It("should handle big vals in Set", func() {
  105. C, N = 4, 100
  106. bigVal := bigVal()
  107. perform(C, func(id int) {
  108. for i := 0; i < N; i++ {
  109. err := client.Set("key", bigVal, 0).Err()
  110. Expect(err).NotTo(HaveOccurred())
  111. }
  112. })
  113. })
  114. It("should select db", func() {
  115. err := client.Set("db", 1, 0).Err()
  116. Expect(err).NotTo(HaveOccurred())
  117. perform(C, func(id int) {
  118. opt := redisOptions()
  119. opt.DB = id
  120. client := redis.NewClient(opt)
  121. for i := 0; i < N; i++ {
  122. err := client.Set("db", id, 0).Err()
  123. Expect(err).NotTo(HaveOccurred())
  124. n, err := client.Get("db").Int64()
  125. Expect(err).NotTo(HaveOccurred())
  126. Expect(n).To(Equal(int64(id)))
  127. }
  128. err := client.Close()
  129. Expect(err).NotTo(HaveOccurred())
  130. })
  131. n, err := client.Get("db").Int64()
  132. Expect(err).NotTo(HaveOccurred())
  133. Expect(n).To(Equal(int64(1)))
  134. })
  135. It("should select DB with read timeout", func() {
  136. perform(C, func(id int) {
  137. opt := redisOptions()
  138. opt.DB = id
  139. opt.ReadTimeout = time.Nanosecond
  140. client := redis.NewClient(opt)
  141. perform(C, func(id int) {
  142. err := client.Ping().Err()
  143. Expect(err).To(HaveOccurred())
  144. Expect(err.(net.Error).Timeout()).To(BeTrue())
  145. })
  146. err := client.Close()
  147. Expect(err).NotTo(HaveOccurred())
  148. })
  149. })
  150. It("should Watch/Unwatch", func() {
  151. err := client.Set("key", "0", 0).Err()
  152. Expect(err).NotTo(HaveOccurred())
  153. perform(C, func(id int) {
  154. for i := 0; i < N; i++ {
  155. err := client.Watch(func(tx *redis.Tx) error {
  156. val, err := tx.Get("key").Result()
  157. Expect(err).NotTo(HaveOccurred())
  158. Expect(val).NotTo(Equal(redis.Nil))
  159. num, err := strconv.ParseInt(val, 10, 64)
  160. Expect(err).NotTo(HaveOccurred())
  161. cmds, err := tx.TxPipelined(func(pipe redis.Pipeliner) error {
  162. pipe.Set("key", strconv.FormatInt(num+1, 10), 0)
  163. return nil
  164. })
  165. Expect(cmds).To(HaveLen(1))
  166. return err
  167. }, "key")
  168. if err == redis.TxFailedErr {
  169. i--
  170. continue
  171. }
  172. Expect(err).NotTo(HaveOccurred())
  173. }
  174. })
  175. val, err := client.Get("key").Int64()
  176. Expect(err).NotTo(HaveOccurred())
  177. Expect(val).To(Equal(int64(C * N)))
  178. })
  179. It("should Pipeline", func() {
  180. perform(C, func(id int) {
  181. pipe := client.Pipeline()
  182. for i := 0; i < N; i++ {
  183. pipe.Echo(fmt.Sprint(i))
  184. }
  185. cmds, err := pipe.Exec()
  186. Expect(err).NotTo(HaveOccurred())
  187. Expect(cmds).To(HaveLen(N))
  188. for i := 0; i < N; i++ {
  189. Expect(cmds[i].(*redis.StringCmd).Val()).To(Equal(fmt.Sprint(i)))
  190. }
  191. })
  192. })
  193. It("should Pipeline", func() {
  194. pipe := client.Pipeline()
  195. perform(N, func(id int) {
  196. pipe.Incr("key")
  197. })
  198. cmds, err := pipe.Exec()
  199. Expect(err).NotTo(HaveOccurred())
  200. Expect(cmds).To(HaveLen(N))
  201. n, err := client.Get("key").Int64()
  202. Expect(err).NotTo(HaveOccurred())
  203. Expect(n).To(Equal(int64(N)))
  204. })
  205. It("should TxPipeline", func() {
  206. pipe := client.TxPipeline()
  207. perform(N, func(id int) {
  208. pipe.Incr("key")
  209. })
  210. cmds, err := pipe.Exec()
  211. Expect(err).NotTo(HaveOccurred())
  212. Expect(cmds).To(HaveLen(N))
  213. n, err := client.Get("key").Int64()
  214. Expect(err).NotTo(HaveOccurred())
  215. Expect(n).To(Equal(int64(N)))
  216. })
  217. It("should BLPop", func() {
  218. var received uint32
  219. wg := performAsync(C, func(id int) {
  220. for {
  221. v, err := client.BLPop(3*time.Second, "list").Result()
  222. if err != nil {
  223. break
  224. }
  225. Expect(v).To(Equal([]string{"list", "hello"}))
  226. atomic.AddUint32(&received, 1)
  227. }
  228. })
  229. perform(C, func(id int) {
  230. for i := 0; i < N; i++ {
  231. err := client.LPush("list", "hello").Err()
  232. Expect(err).NotTo(HaveOccurred())
  233. }
  234. })
  235. wg.Wait()
  236. Expect(received).To(Equal(uint32(C * N)))
  237. })
  238. It("should WithContext", func() {
  239. perform(C, func(_ int) {
  240. err := client.WithContext(context.Background()).Ping().Err()
  241. Expect(err).NotTo(HaveOccurred())
  242. })
  243. })
  244. })
  245. var _ = Describe("cluster races", func() {
  246. var client *redis.ClusterClient
  247. var C, N int
  248. BeforeEach(func() {
  249. opt := redisClusterOptions()
  250. client = cluster.clusterClient(opt)
  251. C, N = 10, 1000
  252. if testing.Short() {
  253. C = 4
  254. N = 100
  255. }
  256. })
  257. AfterEach(func() {
  258. err := client.Close()
  259. Expect(err).NotTo(HaveOccurred())
  260. })
  261. It("should echo", func() {
  262. perform(C, func(id int) {
  263. for i := 0; i < N; i++ {
  264. msg := fmt.Sprintf("echo %d %d", id, i)
  265. echo, err := client.Echo(msg).Result()
  266. Expect(err).NotTo(HaveOccurred())
  267. Expect(echo).To(Equal(msg))
  268. }
  269. })
  270. })
  271. It("should get", func() {
  272. perform(C, func(id int) {
  273. for i := 0; i < N; i++ {
  274. key := fmt.Sprintf("key_%d_%d", id, i)
  275. _, err := client.Get(key).Result()
  276. Expect(err).To(Equal(redis.Nil))
  277. }
  278. })
  279. })
  280. It("should incr", func() {
  281. key := "TestIncrFromGoroutines"
  282. perform(C, func(id int) {
  283. for i := 0; i < N; i++ {
  284. err := client.Incr(key).Err()
  285. Expect(err).NotTo(HaveOccurred())
  286. }
  287. })
  288. val, err := client.Get(key).Int64()
  289. Expect(err).NotTo(HaveOccurred())
  290. Expect(val).To(Equal(int64(C * N)))
  291. })
  292. })
  293. func bigVal() []byte {
  294. return bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
  295. }