1 # TODO # test pipelining
6 proc test
{name code okpattern
} {
7 puts -nonewline [format "%-70s " $name]
9 set retval
[uplevel 1 $code]
10 if {$okpattern eq
$retval ||
[string match
$okpattern $retval]} {
14 puts "!! ERROR expected\n'$okpattern'\nbut got\n'$retval'"
19 proc main
{server port
} {
20 set fd
[redis_connect
$server $port]
22 test
{DEL all keys to start with a clean DB
} {
23 foreach key
[redis_keys
$fd *] {
29 test
{SET and GET an item
} {
30 redis_set
$fd x foobar
34 test
{DEL against a single item
} {
39 test
{KEYS with pattern
} {
40 foreach key
{key_x key_y key_z foo_a foo_b foo_c
} {
41 redis_set
$fd $key hello
43 lsort [redis_keys
$fd foo
*]
46 test
{KEYS to get all keys
} {
47 lsort [redis_keys
$fd *]
48 } {foo_a foo_b foo_c key_x key_y key_z
}
55 foreach key
[redis_keys
$fd *] {
61 test
{Very big payload in GET
/SET
} {
62 set buf
[string repeat
"abcd" 1000000]
63 redis_set
$fd foo
$buf
65 } [string repeat
"abcd" 1000000]
67 test
{SET
10000 numeric keys and access all them in reverse order
} {
68 for {set x
0} {$x < 10000} {incr x
} {
72 for {set x
9999} {$x >= 0} {incr x
-1} {
73 incr sum
[redis_get
$fd $x]
78 test
{DBSIZE should be
10001 now
} {
82 test
{INCR against non existing key
} {
84 append res
[redis_incr
$fd novar
]
85 append res
[redis_get
$fd novar
]
88 test
{INCR against key created by
incr itself
} {
92 test
{INCR against key originally
set with SET
} {
93 redis_set
$fd novar
100
97 test
{SETNX target key missing
} {
98 redis_setnx
$fd novar2 foobared
102 test
{SETNX target key exists
} {
103 redis_setnx
$fd novar2 blabla
109 redis_set
$fd newkey test
110 append res
[redis_exists
$fd newkey
]
112 append res
[redis_exists
$fd newkey
]
115 test
{Zero length value in key. SET
/GET
/EXISTS
} {
116 redis_set
$fd emptykey
{}
117 set res
[redis_get
$fd emptykey
]
118 append res
[redis_exists
$fd emptykey
]
119 redis_del
$fd emptykey
120 append res
[redis_exists
$fd emptykey
]
123 test
{Commands pipelining
} {
124 puts -nonewline $fd "SET k1 4\r\nxyzk\r\nGET k1\r\nPING\r\n"
127 append res
[string match
+OK
* [redis_read_retcode
$fd]]
128 append res
[redis_bulk_read
$fd]
129 append res
[string match
+PONG
* [redis_read_retcode
$fd]]
133 test
{Non existing command
} {
134 puts -nonewline $fd "foo\r\n"
136 string match
-ERR* [redis_read_retcode
$fd]
139 test
{Basic LPUSH
, RPUSH
, LLENGTH
, LINDEX
} {
140 redis_lpush
$fd mylist a
141 redis_lpush
$fd mylist b
142 redis_rpush
$fd mylist c
143 set res
[redis_llen
$fd mylist
]
144 append res
[redis_lindex
$fd mylist
0]
145 append res
[redis_lindex
$fd mylist
1]
146 append res
[redis_lindex
$fd mylist
2]
151 redis_exists
$fd mylist
154 test
{Create a long
list and check every single element with LINDEX
} {
156 for {set i
0} {$i < 1000} {incr i
} {
157 redis_rpush
$fd mylist
$i
159 for {set i
0} {$i < 1000} {incr i
} {
160 if {[redis_lindex
$fd mylist
$i] eq
$i} {incr ok
}
161 if {[redis_lindex
$fd mylist
[expr (-$i)-1]] eq
[expr 999-$i]} {
168 test
{Test elements with LINDEX in random access
} {
170 for {set i
0} {$i < 1000} {incr i
} {
171 set r
[expr int
(rand
()*1000)]
172 if {[redis_lindex
$fd mylist
$r] eq
$r} {incr ok
}
173 if {[redis_lindex
$fd mylist
[expr (-$r)-1]] eq
[expr 999-$r]} {
180 test
{LLEN against non-list value
error} {
182 redis_set
$fd mylist foobar
183 redis_llen
$fd mylist
186 test
{LINDEX against non-list value
error} {
187 redis_lindex
$fd mylist
0
190 test
{LPUSH against non-list value
error} {
191 redis_lpush
$fd mylist
0
194 test
{RPUSH against non-list value
error} {
195 redis_rpush
$fd mylist
0
198 test
{RENAME basic usage
} {
199 redis_set
$fd mykey hello
200 redis_rename
$fd mykey mykey1
201 redis_rename
$fd mykey1 mykey2
205 test
{RENAME
source key should no longer exist
} {
206 redis_exists
$fd mykey
209 test
{RENAME against already existing key
} {
210 redis_set
$fd mykey a
211 redis_set
$fd mykey2 b
212 redis_rename
$fd mykey2 mykey
213 set res
[redis_get
$fd mykey
]
214 append res
[redis_exists
$fd mykey2
]
217 test
{RENAMENX basic usage
} {
220 redis_set
$fd mykey foobar
221 redis_renamenx
$fd mykey mykey2
222 set res
[redis_get
$fd mykey2
]
223 append res
[redis_exists
$fd mykey
]
226 test
{RENAMENX against already existing key
} {
227 redis_set
$fd mykey foo
228 redis_set
$fd mykey2 bar
229 redis_renamenx
$fd mykey mykey2
232 test
{RENAMENX against already existing key
(2)} {
233 set res
[redis_get
$fd mykey
]
234 append res
[redis_get
$fd mykey2
]
237 test
{RENAME against non existing
source key
} {
238 redis_rename
$fd nokey foobar
241 test
{RENAME where
source and dest key is the same
} {
242 redis_rename
$fd mykey mykey
245 test
{DEL all keys again
(DB
0)} {
246 foreach key
[redis_keys
$fd *] {
252 test
{DEL all keys again
(DB
1)} {
254 foreach key
[redis_keys
$fd *] {
257 set res
[redis_dbsize
$fd]
262 test
{MOVE basic usage
} {
263 redis_set
$fd mykey foobar
264 redis_move
$fd mykey
1
266 lappend res
[redis_exists
$fd mykey
]
267 lappend res
[redis_dbsize
$fd]
269 lappend res
[redis_get
$fd mykey
]
270 lappend res
[redis_dbsize
$fd]
273 } [list 0 0 foobar
1]
275 test
{MOVE against key existing in the target DB
} {
276 redis_set
$fd mykey hello
277 redis_move
$fd mykey
1
280 test
{SET
/GET keys in different DBs
} {
281 redis_set
$fd a hello
282 redis_set
$fd b world
285 redis_set
$fd b bared
288 lappend res
[redis_get
$fd a
]
289 lappend res
[redis_get
$fd b
]
291 lappend res
[redis_get
$fd a
]
292 lappend res
[redis_get
$fd b
]
295 } {hello world foo bared
}
297 test
{Basic LPOP
/RPOP
} {
299 redis_rpush
$fd mylist
1
300 redis_rpush
$fd mylist
2
301 redis_lpush
$fd mylist
0
302 list [redis_lpop
$fd mylist
] [redis_rpop
$fd mylist
] [redis_lpop
$fd mylist
] [redis_llen
$fd mylist
]
305 test
{LPOP
/RPOP against empty
list} {
306 redis_lpop
$fd mylist
309 test
{LPOP against non
list value
} {
310 redis_set
$fd notalist foo
311 redis_lpop
$fd notalist
314 test
{Mass LPUSH
/LPOP
} {
316 for {set i
0} {$i < 1000} {incr i
} {
317 redis_lpush
$fd mylist
$i
321 for {set i
0} {$i < 500} {incr i
} {
322 incr sum2
[redis_lpop
$fd mylist
]
323 incr sum2
[redis_rpop
$fd mylist
]
328 test
{LRANGE basics
} {
329 for {set i
0} {$i < 10} {incr i
} {
330 redis_rpush
$fd mylist
$i
332 list [redis_lrange
$fd mylist
1 -2] \
333 [redis_lrange
$fd mylist
-3 -1] \
334 [redis_lrange
$fd mylist
4 4]
335 } {{1 2 3 4 5 6 7 8} {7 8 9} 4}
337 test
{LRANGE inverted indexes
} {
338 redis_lrange
$fd mylist
6 2
341 test
{LRANGE out of range indexes including the full
list} {
342 redis_lrange
$fd mylist
-1000 1000
343 } {0 1 2 3 4 5 6 7 8 9}
345 test
{LRANGE against non existing key
} {
346 redis_lrange
$fd nosuchkey
0 1
349 test
{LTRIM basics
} {
351 for {set i
0} {$i < 100} {incr i
} {
352 redis_lpush
$fd mylist
$i
353 redis_ltrim
$fd mylist
0 4
355 redis_lrange
$fd mylist
0 -1
359 redis_lset
$fd mylist
1 foo
360 redis_lset
$fd mylist
-1 bar
361 redis_lrange
$fd mylist
0 -1
364 test
{LSET out of range index
} {
365 redis_lset
$fd mylist
10 foo
368 test
{LSET against non existing key
} {
369 redis_lset
$fd nosuchkey
10 foo
372 test
{LSET against non
list value
} {
373 redis_set
$fd nolist foobar
374 redis_lset
$fd nolist
0 foo
377 test
{SADD
, SCARD
, SISMEMBER
, SMEMBERS basics
} {
378 redis_sadd
$fd myset foo
379 redis_sadd
$fd myset bar
380 list [redis_scard
$fd myset
] [redis_sismember
$fd myset foo
] \
381 [redis_sismember
$fd myset bar
] [redis_sismember
$fd myset bla
] \
382 [lsort [redis_smembers
$fd myset
]]
383 } {2 1 1 0 {bar foo
}}
385 test
{SADD adding the same element multiple times
} {
386 redis_sadd
$fd myset foo
387 redis_sadd
$fd myset foo
388 redis_sadd
$fd myset foo
389 redis_scard
$fd myset
392 test
{SADD against non
set} {
393 redis_sadd
$fd mylist foo
397 redis_sadd
$fd myset ciao
398 redis_srem
$fd myset foo
399 lsort [redis_smembers
$fd myset
]
402 test
{Mass SADD and SINTER with two sets
} {
403 for {set i
0} {$i < 1000} {incr i
} {
404 redis_sadd
$fd set1
$i
405 redis_sadd
$fd set2
[expr $i+995]
407 lsort [redis_sinter
$fd set1 set2
]
408 } {995 996 997 998 999}
410 test
{SINTERSTORE with two sets
} {
411 redis_sinterstore
$fd setres set1 set2
412 lsort [redis_smembers
$fd setres
]
413 } {995 996 997 998 999}
415 test
{SINTER against three sets
} {
416 redis_sadd
$fd set3
999
417 redis_sadd
$fd set3
995
418 redis_sadd
$fd set3
1000
419 redis_sadd
$fd set3
2000
420 lsort [redis_sinter
$fd set1 set2 set3
]
423 test
{SINTERSTORE with three sets
} {
424 redis_sinterstore
$fd setres set1 set2 set3
425 lsort [redis_smembers
$fd setres
]
428 test
{SAVE
- make sure there are all the types as values
} {
429 redis_lpush
$fd mysavelist hello
430 redis_lpush
$fd mysavelist world
431 redis_set
$fd myemptykey
{}
432 redis_set
$fd mynormalkey
{blablablba
}
436 test
{Create a random
list} {
438 array set seenrand
{}
439 for {set i
0} {$i < 10000} {incr i
} {
441 # Make sure all the weights are different because
442 # Redis does not use a stable sort but Tcl does.
443 set r
[expr int
(rand
()*1000000)]
444 if {![info exists seenrand
($r)]} break
447 redis_lpush
$fd tosort
$i
448 redis_set
$fd weight_
$i $r
449 lappend tosort
[list $i $r]
451 set sorted
[lsort -index 1 -real $tosort]
453 for {set i
0} {$i < 10000} {incr i
} {
454 lappend res
[lindex $sorted $i 0]
459 test
{SORT with BY against the newly created
list} {
460 redis_sort
$fd tosort
{BY weight_
*}
463 test
{SORT direct
, numeric
, against the newly created
list} {
464 redis_sort
$fd tosort
465 } [lsort -integer $res]
467 test
{SORT decreasing sort
} {
468 redis_sort
$fd tosort
{DESC
}
469 } [lsort -decreasing -integer $res]
471 test
{SORT speed
, sorting
10000 elements
list using BY
, 100 times
} {
472 set start
[clock clicks
-milliseconds]
473 for {set i
0} {$i < 100} {incr i
} {
474 set sorted
[redis_sort
$fd tosort
{BY weight_
* LIMIT
0 10}]
476 set elapsed
[expr [clock clicks
-milliseconds]-$start]
477 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
482 test
{SORT speed
, sorting
10000 elements
list directly
, 100 times
} {
483 set start
[clock clicks
-milliseconds]
484 for {set i
0} {$i < 100} {incr i
} {
485 set sorted
[redis_sort
$fd tosort
{LIMIT
0 10}]
487 set elapsed
[expr [clock clicks
-milliseconds]-$start]
488 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
493 test
{SORT speed
, pseudo-sorting
10000 elements
list, BY
<const
>, 100 times
} {
494 set start
[clock clicks
-milliseconds]
495 for {set i
0} {$i < 100} {incr i
} {
496 set sorted
[redis_sort
$fd tosort
{BY nokey LIMIT
0 10}]
498 set elapsed
[expr [clock clicks
-milliseconds]-$start]
499 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
504 test
{SORT regression
for issue
#19, sorting floats} {
506 foreach x
{1.1 5.10 3.10 7.44 2.1 5.75 6.12 0.25 1.15} {
507 redis_lpush
$fd mylist
$x
509 redis_sort
$fd mylist
510 } [lsort -real {1.1 5.10 3.10 7.44 2.1 5.75 6.12 0.25 1.15}]
512 test
{LREM
, remove all the occurrences
} {
514 redis_rpush
$fd mylist foo
515 redis_rpush
$fd mylist bar
516 redis_rpush
$fd mylist foobar
517 redis_rpush
$fd mylist foobared
518 redis_rpush
$fd mylist zap
519 redis_rpush
$fd mylist bar
520 redis_rpush
$fd mylist test
521 redis_rpush
$fd mylist foo
522 set res
[redis_lrem
$fd mylist
0 bar
]
523 list [redis_lrange
$fd mylist
0 -1] $res
524 } {{foo foobar foobared zap test foo
} 2}
526 test
{LREM
, remove the first occurrence
} {
527 set res
[redis_lrem
$fd mylist
1 foo
]
528 list [redis_lrange
$fd mylist
0 -1] $res
529 } {{foobar foobared zap test foo
} 1}
531 test
{LREM
, remove non existing element
} {
532 set res
[redis_lrem
$fd mylist
1 nosuchelement
]
533 list [redis_lrange
$fd mylist
0 -1] $res
534 } {{foobar foobared zap test foo
} 0}
536 test
{LREM
, starting from tail with negative count
} {
538 redis_rpush
$fd mylist foo
539 redis_rpush
$fd mylist bar
540 redis_rpush
$fd mylist foobar
541 redis_rpush
$fd mylist foobared
542 redis_rpush
$fd mylist zap
543 redis_rpush
$fd mylist bar
544 redis_rpush
$fd mylist test
545 redis_rpush
$fd mylist foo
546 redis_rpush
$fd mylist foo
547 set res
[redis_lrem
$fd mylist
-1 bar
]
548 list [redis_lrange
$fd mylist
0 -1] $res
549 } {{foo bar foobar foobared zap test foo foo
} 1}
551 test
{LREM
, starting from tail with negative count
(2)} {
552 set res
[redis_lrem
$fd mylist
-2 foo
]
553 list [redis_lrange
$fd mylist
0 -1] $res
554 } {{foo bar foobar foobared zap test
} 2}
558 redis_set
$fd foo BAR
559 redis_set
$fd bar FOO
560 redis_mget
$fd foo bar
563 test
{MGET against non existing key
} {
564 redis_mget
$fd foo baazz bar
567 test
{MGET against non-string key
} {
568 redis_sadd
$fd myset ciao
569 redis_sadd
$fd myset bau
570 redis_mget
$fd foo baazz bar myset
573 # Leave the user with a clean DB before to exit
579 puts "\n[expr $::passed+$::failed] tests, $::passed passed, $::failed failed"
581 puts "\n*** WARNING!!! $::failed FAILED TESTS ***\n"
586 proc redis_connect
{server port
} {
587 set fd
[socket $server $port]
588 fconfigure $fd -translation binary
592 proc redis_write
{fd buf
} {
593 puts -nonewline $fd $buf
596 proc redis_writenl
{fd buf
} {
599 redis_write
$fd "\r\n"
603 proc redis_readnl
{fd len
} {
604 set buf
[read $fd $len]
605 read $fd 2 ; # discard CR LF
609 proc redis_bulk_read
{fd
{multi
0}} {
610 set count
[redis_read_integer
$fd]
611 if {$count eq
{nil
}} return {}
612 if {$multi && $count == -1} return {}
613 set len
[expr {abs
($count)}]
614 set buf
[redis_readnl
$fd $len]
615 if {$count < 0} {return "***ERROR*** $buf"}
619 proc redis_multi_bulk_read fd
{
620 set count
[redis_read_integer
$fd]
621 if {$count eq
{nil
}} return {}
623 set len
[expr {abs
($count)}]
624 set buf
[redis_readnl
$fd $len]
625 return "***ERROR*** $buf"
628 for {set i
0} {$i < $count} {incr i
} {
629 lappend l
[redis_bulk_read
$fd 1]
634 proc redis_read_retcode fd
{
635 set retcode
[string trim
[gets $fd]]
640 proc redis_read_integer fd
{
641 string trim
[gets $fd]
646 proc redis_set
{fd key val
} {
647 redis_writenl
$fd "set $key [string length $val]\r\n$val"
648 redis_read_retcode
$fd
651 proc redis_setnx
{fd key val
} {
652 redis_writenl
$fd "setnx $key [string length $val]\r\n$val"
653 redis_read_integer
$fd
656 proc redis_get
{fd key
} {
657 redis_writenl
$fd "get $key"
661 proc redis_select
{fd id
} {
662 redis_writenl
$fd "select $id"
663 redis_read_retcode
$fd
666 proc redis_move
{fd key id
} {
667 redis_writenl
$fd "move $key $id"
668 redis_read_integer
$fd
671 proc redis_del
{fd key
} {
672 redis_writenl
$fd "del $key"
673 redis_read_integer
$fd
676 proc redis_keys
{fd pattern
} {
677 redis_writenl
$fd "keys $pattern"
678 split [redis_bulk_read
$fd]
681 proc redis_dbsize
{fd
} {
682 redis_writenl
$fd "dbsize"
683 redis_read_integer
$fd
686 proc redis_incr
{fd key
} {
687 redis_writenl
$fd "incr $key"
688 redis_read_integer
$fd
691 proc redis_decr
{fd key
} {
692 redis_writenl
$fd "decr $key"
693 redis_read_integer
$fd
696 proc redis_exists
{fd key
} {
697 redis_writenl
$fd "exists $key"
698 redis_read_integer
$fd
701 proc redis_lpush
{fd key val
} {
702 redis_writenl
$fd "lpush $key [string length $val]\r\n$val"
703 redis_read_retcode
$fd
706 proc redis_rpush
{fd key val
} {
707 redis_writenl
$fd "rpush $key [string length $val]\r\n$val"
708 redis_read_retcode
$fd
711 proc redis_llen
{fd key
} {
712 redis_writenl
$fd "llen $key"
713 redis_read_integer
$fd
716 proc redis_scard
{fd key
} {
717 redis_writenl
$fd "scard $key"
718 redis_read_integer
$fd
721 proc redis_lindex
{fd key index
} {
722 redis_writenl
$fd "lindex $key $index"
726 proc redis_lrange
{fd key first last
} {
727 redis_writenl
$fd "lrange $key $first $last"
728 redis_multi_bulk_read
$fd
731 proc redis_mget
{fd args
} {
732 redis_writenl
$fd "mget [join $args]"
733 redis_multi_bulk_read
$fd
736 proc redis_sort
{fd key
{params
{}}} {
737 redis_writenl
$fd "sort $key $params"
738 redis_multi_bulk_read
$fd
741 proc redis_ltrim
{fd key first last
} {
742 redis_writenl
$fd "ltrim $key $first $last"
743 redis_read_retcode
$fd
746 proc redis_rename
{fd key1 key2
} {
747 redis_writenl
$fd "rename $key1 $key2"
748 redis_read_retcode
$fd
751 proc redis_renamenx
{fd key1 key2
} {
752 redis_writenl
$fd "renamenx $key1 $key2"
753 redis_read_integer
$fd
756 proc redis_lpop
{fd key
} {
757 redis_writenl
$fd "lpop $key"
761 proc redis_rpop
{fd key
} {
762 redis_writenl
$fd "rpop $key"
766 proc redis_lset
{fd key index val
} {
767 redis_writenl
$fd "lset $key $index [string length $val]\r\n$val"
768 redis_read_retcode
$fd
771 proc redis_sadd
{fd key val
} {
772 redis_writenl
$fd "sadd $key [string length $val]\r\n$val"
773 redis_read_integer
$fd
776 proc redis_srem
{fd key val
} {
777 redis_writenl
$fd "srem $key [string length $val]\r\n$val"
778 redis_read_integer
$fd
781 proc redis_sismember
{fd key val
} {
782 redis_writenl
$fd "sismember $key [string length $val]\r\n$val"
783 redis_read_integer
$fd
786 proc redis_sinter
{fd args
} {
787 redis_writenl
$fd "sinter [join $args]"
788 redis_multi_bulk_read
$fd
791 proc redis_sinterstore
{fd args
} {
792 redis_writenl
$fd "sinterstore [join $args]"
793 redis_read_retcode
$fd
796 proc redis_smembers
{fd key
} {
797 redis_writenl
$fd "smembers $key"
798 redis_multi_bulk_read
$fd
801 proc redis_echo
{fd str
} {
802 redis_writenl
$fd "echo [string length $str]\r\n$str"
803 redis_writenl
$fd "smembers $key"
806 proc redis_save
{fd
} {
807 redis_writenl
$fd "save"
808 redis_read_retcode
$fd
811 proc redis_flushall
{fd
} {
812 redis_writenl
$fd "flushall"
813 redis_read_retcode
$fd
816 proc redis_flushdb
{fd
} {
817 redis_writenl
$fd "flushdb"
818 redis_read_retcode
$fd
821 proc redis_lrem
{fd key count val
} {
822 redis_writenl
$fd "lrem $key $count [string length $val]\r\n$val"
823 redis_read_integer
$fd
827 set fd
[socket 127.0.0.1 6379]
828 fconfigure $fd -translation binary
831 set randkey
[expr int
(rand
()*10000)]
832 set randval
[expr int
(rand
()*10000)]
833 set randidx0
[expr int
(rand
()*10)]
834 set randidx1
[expr int
(rand
()*10)]
835 set cmd
[expr int
(rand
()*10)]
836 if {$cmd == 0} {redis_set
$fd $randkey $randval}
837 if {$cmd == 1} {redis_get
$fd $randkey}
838 if {$cmd == 2} {redis_incr
$fd $randkey}
839 if {$cmd == 3} {redis_lpush
$fd $randkey $randval}
840 if {$cmd == 4} {redis_rpop
$fd $randkey}
841 if {$cmd == 5} {redis_del
$fd $randkey}
842 if {$cmd == 6} {redis_lrange
$fd $randkey $randidx0 $randidx1}
843 if {$cmd == 7} {redis_ltrim
$fd $randkey $randidx0 $randidx1}
844 if {$cmd == 8} {redis_lindex
$fd $randkey $randidx0}
845 if {$cmd == 9} {redis_lset
$fd $randkey $randidx0 $randval}
851 if {[llength $argv] == 0} {
853 } elseif
{[llength $argv] == 1 && [lindex $argv 0] eq
{stress
}} {
856 main
[lindex $argv 0] [lindex $argv 1]