]> git.saurik.com Git - redis.git/blame - test-redis.tcl
Now MONITOR/SYNC cannot be issued multiple times
[redis.git] / test-redis.tcl
CommitLineData
ed9b544e 1# TODO # test pipelining
2
3set ::passed 0
4set ::failed 0
5
6proc test {name code okpattern} {
7 puts -nonewline [format "%-70s " $name]
8 flush stdout
9 set retval [uplevel 1 $code]
10 if {$okpattern eq $retval || [string match $okpattern $retval]} {
11 puts "PASSED"
12 incr ::passed
13 } else {
14 puts "!! ERROR expected\n'$okpattern'\nbut got\n'$retval'"
15 incr ::failed
16 }
17}
18
19proc main {server port} {
20 set fd [redis_connect $server $port]
21
22 test {DEL all keys to start with a clean DB} {
23 foreach key [redis_keys $fd *] {
24 redis_del $fd $key
25 }
26 redis_dbsize $fd
27 } {0}
28
29 test {SET and GET an item} {
30 redis_set $fd x foobar
31 redis_get $fd x
32 } {foobar}
33
34 test {DEL against a single item} {
35 redis_del $fd x
36 redis_get $fd x
37 } {}
38
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
42 }
43 lsort [redis_keys $fd foo*]
44 } {foo_a foo_b foo_c}
45
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}
49
50 test {DBSIZE} {
51 redis_dbsize $fd
52 } {6}
53
54 test {DEL all keys} {
55 foreach key [redis_keys $fd *] {
56 redis_del $fd $key
57 }
58 redis_dbsize $fd
59 } {0}
60
61 test {Very big payload in GET/SET} {
62 set buf [string repeat "abcd" 1000000]
63 redis_set $fd foo $buf
64 redis_get $fd foo
65 } [string repeat "abcd" 1000000]
66
67 test {SET 10000 numeric keys and access all them in reverse order} {
68 for {set x 0} {$x < 10000} {incr x} {
69 redis_set $fd $x $x
70 }
71 set sum 0
72 for {set x 9999} {$x >= 0} {incr x -1} {
73 incr sum [redis_get $fd $x]
74 }
75 format $sum
76 } {49995000}
77
78 test {DBSIZE should be 10001 now} {
79 redis_dbsize $fd
80 } {10001}
81
82 test {INCR against non existing key} {
83 set res {}
84 append res [redis_incr $fd novar]
85 append res [redis_get $fd novar]
86 } {11}
87
88 test {INCR against key created by incr itself} {
89 redis_incr $fd novar
90 } {2}
91
92 test {INCR against key originally set with SET} {
93 redis_set $fd novar 100
94 redis_incr $fd novar
95 } {101}
96
97 test {SETNX target key missing} {
98 redis_setnx $fd novar2 foobared
99 redis_get $fd novar2
100 } {foobared}
101
102 test {SETNX target key exists} {
103 redis_setnx $fd novar2 blabla
104 redis_get $fd novar2
105 } {foobared}
106
107 test {EXISTS} {
108 set res {}
109 redis_set $fd newkey test
110 append res [redis_exists $fd newkey]
111 redis_del $fd newkey
112 append res [redis_exists $fd newkey]
113 } {10}
114
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]
121 } {10}
122
123 test {Commands pipelining} {
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_read_retcode $fd]]
128 append res [redis_bulk_read $fd]
129 append res [string match +PONG* [redis_read_retcode $fd]]
130 format $res
131 } {1xyzk1}
132
133 test {Non existing command} {
134 puts -nonewline $fd "foo\r\n"
135 flush $fd
136 string match -ERR* [redis_read_retcode $fd]
137 } {1}
138
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]
147 } {3bac}
148
149 test {DEL a list} {
150 redis_del $fd mylist
151 redis_exists $fd mylist
152 } {0}
153
154 test {Create a long list and check every single element with LINDEX} {
155 set ok 0
156 for {set i 0} {$i < 1000} {incr i} {
157 redis_rpush $fd mylist $i
158 }
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]} {
162 incr ok
163 }
164 }
165 format $ok
166 } {2000}
167
168 test {Test elements with LINDEX in random access} {
169 set ok 0
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]} {
174 incr ok
175 }
176 }
177 format $ok
178 } {2000}
179
180 test {LLEN against non-list value error} {
181 redis_del $fd mylist
182 redis_set $fd mylist foobar
183 redis_llen $fd mylist
184 } {-2}
185
186 test {LINDEX against non-list value error} {
187 redis_lindex $fd mylist 0
188 } {*ERROR*}
189
190 test {LPUSH against non-list value error} {
191 redis_lpush $fd mylist 0
192 } {-ERR*}
193
194 test {RPUSH against non-list value error} {
195 redis_rpush $fd mylist 0
196 } {-ERR*}
197
198 test {RENAME basic usage} {
199 redis_set $fd mykey hello
200 redis_rename $fd mykey mykey1
201 redis_rename $fd mykey1 mykey2
202 redis_get $fd mykey2
203 } {hello}
204
205 test {RENAME source key should no longer exist} {
206 redis_exists $fd mykey
207 } {0}
208
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]
215 } {b0}
216
217 test {RENAMENX basic usage} {
218 redis_del $fd mykey
219 redis_del $fd mykey2
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]
224 } {foobar0}
225
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
230 } {0}
231
232 test {RENAMENX against already existing key (2)} {
233 set res [redis_get $fd mykey]
234 append res [redis_get $fd mykey2]
235 } {foobar}
236
237 test {RENAME against non existing source key} {
238 redis_rename $fd nokey foobar
239 } {-ERR*}
240
241 test {RENAME where source and dest key is the same} {
242 redis_rename $fd mykey mykey
243 } {-ERR*}
244
245 test {DEL all keys again (DB 0)} {
246 foreach key [redis_keys $fd *] {
247 redis_del $fd $key
248 }
249 redis_dbsize $fd
250 } {0}
251
252 test {DEL all keys again (DB 1)} {
253 redis_select $fd 1
254 foreach key [redis_keys $fd *] {
255 redis_del $fd $key
256 }
257 set res [redis_dbsize $fd]
258 redis_select $fd 0
259 format $res
260 } {0}
261
262 test {MOVE basic usage} {
263 redis_set $fd mykey foobar
264 redis_move $fd mykey 1
265 set res {}
266 lappend res [redis_exists $fd mykey]
267 lappend res [redis_dbsize $fd]
268 redis_select $fd 1
269 lappend res [redis_get $fd mykey]
270 lappend res [redis_dbsize $fd]
271 redis_select $fd 0
272 format $res
273 } [list 0 0 foobar 1]
274
275 test {MOVE against key existing in the target DB} {
276 redis_set $fd mykey hello
277 redis_move $fd mykey 1
278 } {0}
279
280 test {SET/GET keys in different DBs} {
281 redis_set $fd a hello
282 redis_set $fd b world
283 redis_select $fd 1
284 redis_set $fd a foo
285 redis_set $fd b bared
286 redis_select $fd 0
287 set res {}
288 lappend res [redis_get $fd a]
289 lappend res [redis_get $fd b]
290 redis_select $fd 1
291 lappend res [redis_get $fd a]
292 lappend res [redis_get $fd b]
293 redis_select $fd 0
294 format $res
295 } {hello world foo bared}
296
297 test {Basic LPOP/RPOP} {
298 redis_del $fd mylist
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]
303 } [list 0 2 1 0]
304
305 test {LPOP/RPOP against empty list} {
306 redis_lpop $fd mylist
307 } {}
308
309 test {LPOP against non list value} {
310 redis_set $fd notalist foo
311 redis_lpop $fd notalist
312 } {*ERROR*against*}
313
314 test {Mass LPUSH/LPOP} {
315 set sum 0
316 for {set i 0} {$i < 1000} {incr i} {
317 redis_lpush $fd mylist $i
318 incr sum $i
319 }
320 set sum2 0
321 for {set i 0} {$i < 500} {incr i} {
322 incr sum2 [redis_lpop $fd mylist]
323 incr sum2 [redis_rpop $fd mylist]
324 }
325 expr $sum == $sum2
326 } {1}
327
328 test {LRANGE basics} {
329 for {set i 0} {$i < 10} {incr i} {
330 redis_rpush $fd mylist $i
331 }
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}
336
337 test {LRANGE inverted indexes} {
338 redis_lrange $fd mylist 6 2
339 } {}
340
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}
344
345 test {LRANGE against non existing key} {
346 redis_lrange $fd nosuchkey 0 1
347 } {}
348
349 test {LTRIM basics} {
350 redis_del $fd mylist
351 for {set i 0} {$i < 100} {incr i} {
352 redis_lpush $fd mylist $i
353 redis_ltrim $fd mylist 0 4
354 }
355 redis_lrange $fd mylist 0 -1
356 } {99 98 97 96 95}
357
358 test {LSET} {
359 redis_lset $fd mylist 1 foo
360 redis_lset $fd mylist -1 bar
361 redis_lrange $fd mylist 0 -1
362 } {99 foo 97 96 bar}
363
364 test {LSET out of range index} {
365 redis_lset $fd mylist 10 foo
366 } {-ERR*range*}
367
368 test {LSET against non existing key} {
369 redis_lset $fd nosuchkey 10 foo
370 } {-ERR*key*}
371
372 test {LSET against non list value} {
373 redis_set $fd nolist foobar
374 redis_lset $fd nolist 0 foo
375 } {-ERR*value*}
376
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}}
384
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
390 } {2}
391
392 test {SADD against non set} {
393 redis_sadd $fd mylist foo
394 } {-2}
395
396 test {SREM basics} {
397 redis_sadd $fd myset ciao
398 redis_srem $fd myset foo
399 lsort [redis_smembers $fd myset]
400 } {bar ciao}
401
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]
406 }
407 lsort [redis_sinter $fd set1 set2]
408 } {995 996 997 998 999}
409
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}
414
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]
421 } {995 999}
422
423 test {SINTERSTORE with three sets} {
424 redis_sinterstore $fd setres set1 set2 set3
425 lsort [redis_smembers $fd setres]
426 } {995 999}
427
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}
433 redis_save $fd
434 } {+OK}
435
436 test {Create a random list} {
437 set tosort {}
438 array set seenrand {}
439 for {set i 0} {$i < 10000} {incr i} {
440 while 1 {
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
445 }
446 set seenrand($r) x
447 redis_lpush $fd tosort $i
448 redis_set $fd weight_$i $r
449 lappend tosort [list $i $r]
450 }
451 set sorted [lsort -index 1 -real $tosort]
452 set res {}
453 for {set i 0} {$i < 10000} {incr i} {
454 lappend res [lindex $sorted $i 0]
455 }
456 format {}
457 } {}
458
459 test {SORT with BY against the newly created list} {
460 redis_sort $fd tosort {BY weight_*}
461 } $res
462
463 test {SORT direct, numeric, against the newly created list} {
464 redis_sort $fd tosort
465 } [lsort -integer $res]
466
467 test {SORT decreasing sort} {
468 redis_sort $fd tosort {DESC}
469 } [lsort -decreasing -integer $res]
470
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}]
475 }
476 set elapsed [expr [clock clicks -milliseconds]-$start]
477 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
478 flush stdout
479 format {}
480 } {}
481
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}]
486 }
487 set elapsed [expr [clock clicks -milliseconds]-$start]
488 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
489 flush stdout
490 format {}
491 } {}
492
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}]
497 }
498 set elapsed [expr [clock clicks -milliseconds]-$start]
499 puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds "
500 flush stdout
501 format {}
502 } {}
503
504 test {SORT regression for issue #19, sorting floats} {
505 redis_flushdb $fd
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
508 }
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}]
511
512 test {LREM, remove all the occurrences} {
513 redis_flushall $fd
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}
525
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}
530
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}
535
536 test {LREM, starting from tail with negative count} {
537 redis_flushall $fd
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}
550
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}
555
5b19bd72 556 test {MGET} {
557 redis_flushall $fd
558 redis_set $fd foo BAR
559 redis_set $fd bar FOO
560 redis_mget $fd foo bar
561 } {BAR FOO}
562
563 test {MGET against non existing key} {
564 redis_mget $fd foo baazz bar
565 } {BAR {} FOO}
566
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
571 } {BAR {} FOO {}}
572
ed9b544e 573 # Leave the user with a clean DB before to exit
574 test {FLUSHALL} {
575 redis_flushall $fd
576 redis_dbsize $fd
577 } {0}
578
579 puts "\n[expr $::passed+$::failed] tests, $::passed passed, $::failed failed"
580 if {$::failed > 0} {
581 puts "\n*** WARNING!!! $::failed FAILED TESTS ***\n"
582 }
583 close $fd
584}
585
586proc redis_connect {server port} {
587 set fd [socket $server $port]
588 fconfigure $fd -translation binary
589 return $fd
590}
591
592proc redis_write {fd buf} {
593 puts -nonewline $fd $buf
594}
595
596proc redis_writenl {fd buf} {
597 # puts "C: $buf"
598 redis_write $fd $buf
599 redis_write $fd "\r\n"
600 flush $fd
601}
602
603proc redis_readnl {fd len} {
604 set buf [read $fd $len]
605 read $fd 2 ; # discard CR LF
606 return $buf
607}
608
5b19bd72 609proc redis_bulk_read {fd {multi 0}} {
ed9b544e 610 set count [redis_read_integer $fd]
611 if {$count eq {nil}} return {}
5b19bd72 612 if {$multi && $count == -1} return {}
ed9b544e 613 set len [expr {abs($count)}]
614 set buf [redis_readnl $fd $len]
615 if {$count < 0} {return "***ERROR*** $buf"}
616 return $buf
617}
618
619proc redis_multi_bulk_read fd {
620 set count [redis_read_integer $fd]
621 if {$count eq {nil}} return {}
622 if {$count < 0} {
623 set len [expr {abs($count)}]
624 set buf [redis_readnl $fd $len]
625 return "***ERROR*** $buf"
626 }
627 set l {}
628 for {set i 0} {$i < $count} {incr i} {
5b19bd72 629 lappend l [redis_bulk_read $fd 1]
ed9b544e 630 }
631 return $l
632}
633
634proc redis_read_retcode fd {
635 set retcode [string trim [gets $fd]]
636 # puts "S: $retcode"
637 return $retcode
638}
639
640proc redis_read_integer fd {
641 string trim [gets $fd]
642}
643
644### Actual API ###
645
646proc redis_set {fd key val} {
647 redis_writenl $fd "set $key [string length $val]\r\n$val"
648 redis_read_retcode $fd
649}
650
651proc redis_setnx {fd key val} {
652 redis_writenl $fd "setnx $key [string length $val]\r\n$val"
653 redis_read_integer $fd
654}
655
656proc redis_get {fd key} {
657 redis_writenl $fd "get $key"
658 redis_bulk_read $fd
659}
660
661proc redis_select {fd id} {
662 redis_writenl $fd "select $id"
663 redis_read_retcode $fd
664}
665
666proc redis_move {fd key id} {
667 redis_writenl $fd "move $key $id"
668 redis_read_integer $fd
669}
670
671proc redis_del {fd key} {
672 redis_writenl $fd "del $key"
673 redis_read_integer $fd
674}
675
676proc redis_keys {fd pattern} {
677 redis_writenl $fd "keys $pattern"
678 split [redis_bulk_read $fd]
679}
680
681proc redis_dbsize {fd} {
682 redis_writenl $fd "dbsize"
683 redis_read_integer $fd
684}
685
686proc redis_incr {fd key} {
687 redis_writenl $fd "incr $key"
688 redis_read_integer $fd
689}
690
691proc redis_decr {fd key} {
692 redis_writenl $fd "decr $key"
693 redis_read_integer $fd
694}
695
696proc redis_exists {fd key} {
697 redis_writenl $fd "exists $key"
698 redis_read_integer $fd
699}
700
701proc redis_lpush {fd key val} {
702 redis_writenl $fd "lpush $key [string length $val]\r\n$val"
703 redis_read_retcode $fd
704}
705
706proc redis_rpush {fd key val} {
707 redis_writenl $fd "rpush $key [string length $val]\r\n$val"
708 redis_read_retcode $fd
709}
710
711proc redis_llen {fd key} {
712 redis_writenl $fd "llen $key"
713 redis_read_integer $fd
714}
715
716proc redis_scard {fd key} {
717 redis_writenl $fd "scard $key"
718 redis_read_integer $fd
719}
720
721proc redis_lindex {fd key index} {
722 redis_writenl $fd "lindex $key $index"
723 redis_bulk_read $fd
724}
725
726proc redis_lrange {fd key first last} {
727 redis_writenl $fd "lrange $key $first $last"
728 redis_multi_bulk_read $fd
729}
730
5b19bd72 731proc redis_mget {fd args} {
732 redis_writenl $fd "mget [join $args]"
733 redis_multi_bulk_read $fd
734}
735
ed9b544e 736proc redis_sort {fd key {params {}}} {
737 redis_writenl $fd "sort $key $params"
738 redis_multi_bulk_read $fd
739}
740
741proc redis_ltrim {fd key first last} {
742 redis_writenl $fd "ltrim $key $first $last"
743 redis_read_retcode $fd
744}
745
746proc redis_rename {fd key1 key2} {
747 redis_writenl $fd "rename $key1 $key2"
748 redis_read_retcode $fd
749}
750
751proc redis_renamenx {fd key1 key2} {
752 redis_writenl $fd "renamenx $key1 $key2"
753 redis_read_integer $fd
754}
755
756proc redis_lpop {fd key} {
757 redis_writenl $fd "lpop $key"
758 redis_bulk_read $fd
759}
760
761proc redis_rpop {fd key} {
762 redis_writenl $fd "rpop $key"
763 redis_bulk_read $fd
764}
765
766proc redis_lset {fd key index val} {
767 redis_writenl $fd "lset $key $index [string length $val]\r\n$val"
768 redis_read_retcode $fd
769}
770
771proc redis_sadd {fd key val} {
772 redis_writenl $fd "sadd $key [string length $val]\r\n$val"
773 redis_read_integer $fd
774}
775
776proc redis_srem {fd key val} {
777 redis_writenl $fd "srem $key [string length $val]\r\n$val"
778 redis_read_integer $fd
779}
780
781proc redis_sismember {fd key val} {
782 redis_writenl $fd "sismember $key [string length $val]\r\n$val"
783 redis_read_integer $fd
784}
785
786proc redis_sinter {fd args} {
787 redis_writenl $fd "sinter [join $args]\r\n"
788 redis_multi_bulk_read $fd
789}
790
791proc redis_sinterstore {fd args} {
792 redis_writenl $fd "sinterstore [join $args]\r\n"
793 redis_read_retcode $fd
794}
795
796proc redis_smembers {fd key} {
797 redis_writenl $fd "smembers $key\r\n"
798 redis_multi_bulk_read $fd
799}
800
801proc redis_echo {fd str} {
802 redis_writenl $fd "echo [string length $str]\r\n$str\r\n"
803 redis_writenl $fd "smembers $key\r\n"
804}
805
806proc redis_save {fd} {
807 redis_writenl $fd "save\r\n"
808 redis_read_retcode $fd
809}
810
811proc redis_flushall {fd} {
812 redis_writenl $fd "flushall\r\n"
813 redis_read_retcode $fd
814}
815
816proc redis_flushdb {fd} {
817 redis_writenl $fd "flushdb\r\n"
818 redis_read_retcode $fd
819}
820
821proc redis_lrem {fd key count val} {
822 redis_writenl $fd "lrem $key $count [string length $val]\r\n$val"
823 redis_read_integer $fd
824}
825
826if {[llength $argv] == 0} {
827 main 127.0.0.1 6379
828} else {
829 main [lindex $argv 0] [lindex $argv 1]
830}