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