]> git.saurik.com Git - redis.git/blob - test-redis.tcl
New protocol fix for LREM
[redis.git] / test-redis.tcl
1 # TODO # test pipelining
2
3 source client-libraries/tcl/redis.tcl
4
5 set ::passed 0
6 set ::failed 0
7
8 proc test {name code okpattern} {
9 puts -nonewline [format "%-70s " $name]
10 flush stdout
11 set retval [uplevel 1 $code]
12 if {$okpattern eq $retval || [string match $okpattern $retval]} {
13 puts "PASSED"
14 incr ::passed
15 } else {
16 puts "!! ERROR expected\n'$okpattern'\nbut got\n'$retval'"
17 incr ::failed
18 }
19 }
20
21 proc main {server port} {
22 set r [redis $server $port]
23 set err ""
24
25 test {DEL all keys to start with a clean DB} {
26 foreach key [$r keys *] {$r del $key}
27 $r dbsize
28 } {0}
29
30 test {SET and GET an item} {
31 $r set x foobar
32 $r get x
33 } {foobar}
34
35 test {DEL against a single item} {
36 $r del x
37 $r get x
38 } {}
39
40 test {KEYS with pattern} {
41 foreach key {key_x key_y key_z foo_a foo_b foo_c} {
42 $r set $key hello
43 }
44 lsort [$r keys foo*]
45 } {foo_a foo_b foo_c}
46
47 test {KEYS to get all keys} {
48 lsort [$r keys *]
49 } {foo_a foo_b foo_c key_x key_y key_z}
50
51 test {DBSIZE} {
52 $r dbsize
53 } {6}
54
55 test {DEL all keys} {
56 foreach key [$r keys *] {$r del $key}
57 $r dbsize
58 } {0}
59
60 test {Very big payload in GET/SET} {
61 set buf [string repeat "abcd" 1000000]
62 $r set foo $buf
63 $r get foo
64 } [string repeat "abcd" 1000000]
65
66 test {SET 10000 numeric keys and access all them in reverse order} {
67 for {set x 0} {$x < 10000} {incr x} {
68 $r set $x $x
69 }
70 set sum 0
71 for {set x 9999} {$x >= 0} {incr x -1} {
72 incr sum [$r get $x]
73 }
74 format $sum
75 } {49995000}
76
77 test {DBSIZE should be 10001 now} {
78 $r dbsize
79 } {10001}
80
81 test {INCR against non existing key} {
82 set res {}
83 append res [$r incr novar]
84 append res [$r get novar]
85 } {11}
86
87 test {INCR against key created by incr itself} {
88 $r incr novar
89 } {2}
90
91 test {INCR against key originally set with SET} {
92 $r set novar 100
93 $r incr novar
94 } {101}
95
96 test {SETNX target key missing} {
97 $r setnx novar2 foobared
98 $r get novar2
99 } {foobared}
100
101 test {SETNX target key exists} {
102 $r setnx novar2 blabla
103 $r get novar2
104 } {foobared}
105
106 test {EXISTS} {
107 set res {}
108 $r set newkey test
109 append res [$r exists newkey]
110 $r del newkey
111 append res [$r exists newkey]
112 } {10}
113
114 test {Zero length value in key. SET/GET/EXISTS} {
115 $r set emptykey {}
116 set res [$r get emptykey]
117 append res [$r exists emptykey]
118 $r del emptykey
119 append res [$r exists emptykey]
120 } {10}
121
122 test {Commands pipelining} {
123 set fd [$r channel]
124 puts -nonewline $fd "SET k1 4\r\nxyzk\r\nGET k1\r\nPING\r\n"
125 flush $fd
126 set res {}
127 append res [string match OK* [::redis::redis_read_reply $fd]]
128 append res [::redis::redis_read_reply $fd]
129 append res [string match PONG* [::redis::redis_read_reply $fd]]
130 format $res
131 } {1xyzk1}
132
133 test {Non existing command} {
134 catch {$r foobaredcommand} err
135 string match ERR* $err
136 } {1}
137
138 test {Basic LPUSH, RPUSH, LLENGTH, LINDEX} {
139 $r lpush mylist a
140 $r lpush mylist b
141 $r rpush mylist c
142 set res [$r llen mylist]
143 append res [$r lindex mylist 0]
144 append res [$r lindex mylist 1]
145 append res [$r lindex mylist 2]
146 } {3bac}
147
148 test {DEL a list} {
149 $r del mylist
150 $r exists mylist
151 } {0}
152
153 test {Create a long list and check every single element with LINDEX} {
154 set ok 0
155 for {set i 0} {$i < 1000} {incr i} {
156 $r rpush mylist $i
157 }
158 for {set i 0} {$i < 1000} {incr i} {
159 if {[$r lindex mylist $i] eq $i} {incr ok}
160 if {[$r lindex mylist [expr (-$i)-1]] eq [expr 999-$i]} {
161 incr ok
162 }
163 }
164 format $ok
165 } {2000}
166
167 test {Test elements with LINDEX in random access} {
168 set ok 0
169 for {set i 0} {$i < 1000} {incr i} {
170 set rint [expr int(rand()*1000)]
171 if {[$r lindex mylist $rint] eq $rint} {incr ok}
172 if {[$r lindex mylist [expr (-$rint)-1]] eq [expr 999-$rint]} {
173 incr ok
174 }
175 }
176 format $ok
177 } {2000}
178
179 test {LLEN against non-list value error} {
180 $r del mylist
181 $r set mylist foobar
182 catch {$r llen mylist} err
183 format $err
184 } {ERR*}
185
186 test {LINDEX against non-list value error} {
187 catch {$r lindex mylist 0} err
188 format $err
189 } {ERR*}
190
191 test {LPUSH against non-list value error} {
192 catch {$r lpush mylist 0} err
193 format $err
194 } {ERR*}
195
196 test {RPUSH against non-list value error} {
197 catch {$r rpush mylist 0} err
198 format $err
199 } {ERR*}
200
201 test {RENAME basic usage} {
202 $r set mykey hello
203 $r rename mykey mykey1
204 $r rename mykey1 mykey2
205 $r get mykey2
206 } {hello}
207
208 test {RENAME source key should no longer exist} {
209 $r exists mykey
210 } {0}
211
212 test {RENAME against already existing key} {
213 $r set mykey a
214 $r set mykey2 b
215 $r rename mykey2 mykey
216 set res [$r get mykey]
217 append res [$r exists mykey2]
218 } {b0}
219
220 test {RENAMENX basic usage} {
221 $r del mykey
222 $r del mykey2
223 $r set mykey foobar
224 $r renamenx mykey mykey2
225 set res [$r get mykey2]
226 append res [$r exists mykey]
227 } {foobar0}
228
229 test {RENAMENX against already existing key} {
230 $r set mykey foo
231 $r set mykey2 bar
232 $r renamenx mykey mykey2
233 } {0}
234
235 test {RENAMENX against already existing key (2)} {
236 set res [$r get mykey]
237 append res [$r get mykey2]
238 } {foobar}
239
240 test {RENAME against non existing source key} {
241 catch {$r rename nokey foobar} err
242 format $err
243 } {ERR*}
244
245 test {RENAME where source and dest key is the same} {
246 catch {$r rename mykey mykey} err
247 format $err
248 } {ERR*}
249
250 test {DEL all keys again (DB 0)} {
251 foreach key [$r keys *] {
252 $r del $key
253 }
254 $r dbsize
255 } {0}
256
257 test {DEL all keys again (DB 1)} {
258 $r select 1
259 foreach key [$r keys *] {
260 $r del $key
261 }
262 set res [$r dbsize]
263 $r select 0
264 format $res
265 } {0}
266
267 test {MOVE basic usage} {
268 $r set mykey foobar
269 $r move mykey 1
270 set res {}
271 lappend res [$r exists mykey]
272 lappend res [$r dbsize]
273 $r select 1
274 lappend res [$r get mykey]
275 lappend res [$r dbsize]
276 $r select 0
277 format $res
278 } [list 0 0 foobar 1]
279
280 test {MOVE against key existing in the target DB} {
281 $r set mykey hello
282 $r move mykey 1
283 } {0}
284
285 test {SET/GET keys in different DBs} {
286 $r set a hello
287 $r set b world
288 $r select 1
289 $r set a foo
290 $r set b bared
291 $r select 0
292 set res {}
293 lappend res [$r get a]
294 lappend res [$r get b]
295 $r select 1
296 lappend res [$r get a]
297 lappend res [$r get b]
298 $r select 0
299 format $res
300 } {hello world foo bared}
301
302 test {Basic LPOP/RPOP} {
303 $r del mylist
304 $r rpush mylist 1
305 $r rpush mylist 2
306 $r lpush mylist 0
307 list [$r lpop mylist] [$r rpop mylist] [$r lpop mylist] [$r llen mylist]
308 } [list 0 2 1 0]
309
310 test {LPOP/RPOP against empty list} {
311 $r lpop mylist
312 } {}
313
314 test {LPOP against non list value} {
315 $r set notalist foo
316 catch {$r lpop notalist} err
317 format $err
318 } {ERR*kind*}
319
320 test {Mass LPUSH/LPOP} {
321 set sum 0
322 for {set i 0} {$i < 1000} {incr i} {
323 $r lpush mylist $i
324 incr sum $i
325 }
326 set sum2 0
327 for {set i 0} {$i < 500} {incr i} {
328 incr sum2 [$r lpop mylist]
329 incr sum2 [$r rpop mylist]
330 }
331 expr $sum == $sum2
332 } {1}
333
334 test {LRANGE basics} {
335 for {set i 0} {$i < 10} {incr i} {
336 $r rpush mylist $i
337 }
338 list [$r lrange mylist 1 -2] \
339 [$r lrange mylist -3 -1] \
340 [$r lrange mylist 4 4]
341 } {{1 2 3 4 5 6 7 8} {7 8 9} 4}
342
343 test {LRANGE inverted indexes} {
344 $r lrange mylist 6 2
345 } {}
346
347 test {LRANGE out of range indexes including the full list} {
348 $r lrange mylist -1000 1000
349 } {0 1 2 3 4 5 6 7 8 9}
350
351 test {LRANGE against non existing key} {
352 $r lrange nosuchkey 0 1
353 } {}
354
355 test {LTRIM basics} {
356 $r del mylist
357 for {set i 0} {$i < 100} {incr i} {
358 $r lpush mylist $i
359 $r ltrim mylist 0 4
360 }
361 $r lrange mylist 0 -1
362 } {99 98 97 96 95}
363
364 test {LSET} {
365 $r lset mylist 1 foo
366 $r lset mylist -1 bar
367 $r lrange mylist 0 -1
368 } {99 foo 97 96 bar}
369
370 test {LSET out of range index} {
371 catch {$r lset mylist 10 foo} err
372 format $err
373 } {ERR*range*}
374
375 test {LSET against non existing key} {
376 catch {$r lset nosuchkey 10 foo} err
377 format $err
378 } {ERR*key*}
379
380 test {LSET against non list value} {
381 $r set nolist foobar
382 catch {$r lset nolist 0 foo} err
383 format $err
384 } {ERR*value*}
385
386 test {SADD, SCARD, SISMEMBER, SMEMBERS basics} {
387 $r sadd myset foo
388 $r sadd myset bar
389 list [$r scard myset] [$r sismember myset foo] \
390 [$r sismember myset bar] [$r sismember myset bla] \
391 [lsort [$r smembers myset]]
392 } {2 1 1 0 {bar foo}}
393
394 test {SADD adding the same element multiple times} {
395 $r sadd myset foo
396 $r sadd myset foo
397 $r sadd myset foo
398 $r scard myset
399 } {2}
400
401 test {SADD against non set} {
402 catch {$r sadd mylist foo} err
403 format $err
404 } {ERR*kind*}
405
406 test {SREM basics} {
407 $r sadd myset ciao
408 $r srem myset foo
409 lsort [$r smembers myset]
410 } {bar ciao}
411
412 test {Mass SADD and SINTER with two sets} {
413 for {set i 0} {$i < 1000} {incr i} {
414 $r sadd set1 $i
415 $r sadd set2 [expr $i+995]
416 }
417 lsort [$r sinter set1 set2]
418 } {995 996 997 998 999}
419
420 test {SINTERSTORE with two sets} {
421 $r sinterstore setres set1 set2
422 lsort [$r smembers setres]
423 } {995 996 997 998 999}
424
425 test {SINTER against three sets} {
426 $r sadd set3 999
427 $r sadd set3 995
428 $r sadd set3 1000
429 $r sadd set3 2000
430 lsort [$r sinter set1 set2 set3]
431 } {995 999}
432
433 test {SINTERSTORE with three sets} {
434 $r sinterstore setres set1 set2 set3
435 lsort [$r smembers setres]
436 } {995 999}
437
438 test {SAVE - make sure there are all the types as values} {
439 $r lpush mysavelist hello
440 $r lpush mysavelist world
441 $r set myemptykey {}
442 $r set mynormalkey {blablablba}
443 $r save
444 } {OK}
445
446 test {Create a random list} {
447 set tosort {}
448 array set seenrand {}
449 for {set i 0} {$i < 10000} {incr i} {
450 while 1 {
451 # Make sure all the weights are different because
452 # Redis does not use a stable sort but Tcl does.
453 set rint [expr int(rand()*1000000)]
454 if {![info exists seenrand($rint)]} break
455 }
456 set seenrand($rint) x
457 $r lpush tosort $i
458 $r set weight_$i $rint
459 lappend tosort [list $i $rint]
460 }
461 set sorted [lsort -index 1 -real $tosort]
462 set res {}
463 for {set i 0} {$i < 10000} {incr i} {
464 lappend res [lindex $sorted $i 0]
465 }
466 format {}
467 } {}
468
469 test {SORT with BY against the newly created list} {
470 $r sort tosort {BY weight_*}
471 } $res
472
473 test {SORT direct, numeric, against the newly created list} {
474 $r sort tosort
475 } [lsort -integer $res]
476
477 test {SORT decreasing sort} {
478 $r sort tosort {DESC}
479 } [lsort -decreasing -integer $res]
480
481 test {SORT speed, sorting 10000 elements list using BY, 100 times} {
482 set start [clock clicks -milliseconds]
483 for {set i 0} {$i < 100} {incr i} {
484 set sorted [$r sort tosort {BY weight_* LIMIT 0 10}]
485 }
486 set elapsed [expr [clock clicks -milliseconds]-$start]
487 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
488 flush stdout
489 format {}
490 } {}
491
492 test {SORT speed, sorting 10000 elements list directly, 100 times} {
493 set start [clock clicks -milliseconds]
494 for {set i 0} {$i < 100} {incr i} {
495 set sorted [$r sort tosort {LIMIT 0 10}]
496 }
497 set elapsed [expr [clock clicks -milliseconds]-$start]
498 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
499 flush stdout
500 format {}
501 } {}
502
503 test {SORT speed, pseudo-sorting 10000 elements list, BY <const>, 100 times} {
504 set start [clock clicks -milliseconds]
505 for {set i 0} {$i < 100} {incr i} {
506 set sorted [$r sort tosort {BY nokey LIMIT 0 10}]
507 }
508 set elapsed [expr [clock clicks -milliseconds]-$start]
509 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
510 flush stdout
511 format {}
512 } {}
513
514 test {SORT regression for issue #19, sorting floats} {
515 $r flushdb
516 foreach x {1.1 5.10 3.10 7.44 2.1 5.75 6.12 0.25 1.15} {
517 $r lpush mylist $x
518 }
519 $r sort mylist
520 } [lsort -real {1.1 5.10 3.10 7.44 2.1 5.75 6.12 0.25 1.15}]
521
522 test {LREM, remove all the occurrences} {
523 $r flushall
524 $r rpush mylist foo
525 $r rpush mylist bar
526 $r rpush mylist foobar
527 $r rpush mylist foobared
528 $r rpush mylist zap
529 $r rpush mylist bar
530 $r rpush mylist test
531 $r rpush mylist foo
532 set res [$r lrem mylist 0 bar]
533 list [$r lrange mylist 0 -1] $res
534 } {{foo foobar foobared zap test foo} 2}
535
536 test {LREM, remove the first occurrence} {
537 set res [$r lrem mylist 1 foo]
538 list [$r lrange mylist 0 -1] $res
539 } {{foobar foobared zap test foo} 1}
540
541 test {LREM, remove non existing element} {
542 set res [$r lrem mylist 1 nosuchelement]
543 list [$r lrange mylist 0 -1] $res
544 } {{foobar foobared zap test foo} 0}
545
546 test {LREM, starting from tail with negative count} {
547 $r flushall
548 $r rpush mylist foo
549 $r rpush mylist bar
550 $r rpush mylist foobar
551 $r rpush mylist foobared
552 $r rpush mylist zap
553 $r rpush mylist bar
554 $r rpush mylist test
555 $r rpush mylist foo
556 $r rpush mylist foo
557 set res [$r lrem mylist -1 bar]
558 list [$r lrange mylist 0 -1] $res
559 } {{foo bar foobar foobared zap test foo foo} 1}
560
561 test {LREM, starting from tail with negative count (2)} {
562 set res [$r lrem mylist -2 foo]
563 list [$r lrange mylist 0 -1] $res
564 } {{foo bar foobar foobared zap test} 2}
565
566 test {MGET} {
567 $r flushall
568 $r set foo BAR
569 $r set bar FOO
570 $r mget foo bar
571 } {BAR FOO}
572
573 test {MGET against non existing key} {
574 $r mget foo baazz bar
575 } {BAR {} FOO}
576
577 test {MGET against non-string key} {
578 $r sadd myset ciao
579 $r sadd myset bau
580 $r mget foo baazz bar myset
581 } {BAR {} FOO {}}
582
583 # Leave the user with a clean DB before to exit
584 test {FLUSHALL} {
585 $r flushall
586 $r dbsize
587 } {0}
588
589 puts "\n[expr $::passed+$::failed] tests, $::passed passed, $::failed failed"
590 if {$::failed > 0} {
591 puts "\n*** WARNING!!! $::failed FAILED TESTS ***\n"
592 }
593 close $fd
594 }
595
596 proc stress {} {
597 set r [redis]
598 $r flushall
599 while 1 {
600 set randkey [expr int(rand()*10000)]
601 set randval [expr int(rand()*10000)]
602 set randidx0 [expr int(rand()*10)]
603 set randidx1 [expr int(rand()*10)]
604 set cmd [expr int(rand()*10)]
605 catch {
606 if {$cmd == 0} {$r set $randkey $randval}
607 if {$cmd == 1} {$r get $randkey}
608 if {$cmd == 2} {$r incr $randkey}
609 if {$cmd == 3} {$r lpush $randkey $randval}
610 if {$cmd == 4} {$r rpop $randkey}
611 if {$cmd == 5} {$r del $randkey}
612 if {$cmd == 6} {$r lrange $randkey $randidx0 $randidx1}
613 if {$cmd == 7} {$r ltrim $randkey $randidx0 $randidx1}
614 if {$cmd == 8} {$r lindex $randkey $randidx0}
615 if {$cmd == 9} {$r lset $randkey $randidx0 $randval}
616 }
617 flush stdout
618 }
619 $r close
620 }
621
622 if {[llength $argv] == 0} {
623 main 127.0.0.1 6379
624 } elseif {[llength $argv] == 1 && [lindex $argv 0] eq {stress}} {
625 stress
626 } else {
627 main [lindex $argv 0] [lindex $argv 1]
628 }