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