]> git.saurik.com Git - redis.git/blame - test-redis.tcl
redis-cli now checks the arity of vararg commnads
[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
556 # Leave the user with a clean DB before to exit
557 test {FLUSHALL} {
558 redis_flushall $fd
559 redis_dbsize $fd
560 } {0}
561
562 puts "\n[expr $::passed+$::failed] tests, $::passed passed, $::failed failed"
563 if {$::failed > 0} {
564 puts "\n*** WARNING!!! $::failed FAILED TESTS ***\n"
565 }
566 close $fd
567}
568
569proc redis_connect {server port} {
570 set fd [socket $server $port]
571 fconfigure $fd -translation binary
572 return $fd
573}
574
575proc redis_write {fd buf} {
576 puts -nonewline $fd $buf
577}
578
579proc redis_writenl {fd buf} {
580 # puts "C: $buf"
581 redis_write $fd $buf
582 redis_write $fd "\r\n"
583 flush $fd
584}
585
586proc redis_readnl {fd len} {
587 set buf [read $fd $len]
588 read $fd 2 ; # discard CR LF
589 return $buf
590}
591
592proc redis_bulk_read fd {
593 set count [redis_read_integer $fd]
594 if {$count eq {nil}} return {}
595 set len [expr {abs($count)}]
596 set buf [redis_readnl $fd $len]
597 if {$count < 0} {return "***ERROR*** $buf"}
598 return $buf
599}
600
601proc redis_multi_bulk_read fd {
602 set count [redis_read_integer $fd]
603 if {$count eq {nil}} return {}
604 if {$count < 0} {
605 set len [expr {abs($count)}]
606 set buf [redis_readnl $fd $len]
607 return "***ERROR*** $buf"
608 }
609 set l {}
610 for {set i 0} {$i < $count} {incr i} {
611 lappend l [redis_bulk_read $fd]
612 }
613 return $l
614}
615
616proc redis_read_retcode fd {
617 set retcode [string trim [gets $fd]]
618 # puts "S: $retcode"
619 return $retcode
620}
621
622proc redis_read_integer fd {
623 string trim [gets $fd]
624}
625
626### Actual API ###
627
628proc redis_set {fd key val} {
629 redis_writenl $fd "set $key [string length $val]\r\n$val"
630 redis_read_retcode $fd
631}
632
633proc redis_setnx {fd key val} {
634 redis_writenl $fd "setnx $key [string length $val]\r\n$val"
635 redis_read_integer $fd
636}
637
638proc redis_get {fd key} {
639 redis_writenl $fd "get $key"
640 redis_bulk_read $fd
641}
642
643proc redis_select {fd id} {
644 redis_writenl $fd "select $id"
645 redis_read_retcode $fd
646}
647
648proc redis_move {fd key id} {
649 redis_writenl $fd "move $key $id"
650 redis_read_integer $fd
651}
652
653proc redis_del {fd key} {
654 redis_writenl $fd "del $key"
655 redis_read_integer $fd
656}
657
658proc redis_keys {fd pattern} {
659 redis_writenl $fd "keys $pattern"
660 split [redis_bulk_read $fd]
661}
662
663proc redis_dbsize {fd} {
664 redis_writenl $fd "dbsize"
665 redis_read_integer $fd
666}
667
668proc redis_incr {fd key} {
669 redis_writenl $fd "incr $key"
670 redis_read_integer $fd
671}
672
673proc redis_decr {fd key} {
674 redis_writenl $fd "decr $key"
675 redis_read_integer $fd
676}
677
678proc redis_exists {fd key} {
679 redis_writenl $fd "exists $key"
680 redis_read_integer $fd
681}
682
683proc redis_lpush {fd key val} {
684 redis_writenl $fd "lpush $key [string length $val]\r\n$val"
685 redis_read_retcode $fd
686}
687
688proc redis_rpush {fd key val} {
689 redis_writenl $fd "rpush $key [string length $val]\r\n$val"
690 redis_read_retcode $fd
691}
692
693proc redis_llen {fd key} {
694 redis_writenl $fd "llen $key"
695 redis_read_integer $fd
696}
697
698proc redis_scard {fd key} {
699 redis_writenl $fd "scard $key"
700 redis_read_integer $fd
701}
702
703proc redis_lindex {fd key index} {
704 redis_writenl $fd "lindex $key $index"
705 redis_bulk_read $fd
706}
707
708proc redis_lrange {fd key first last} {
709 redis_writenl $fd "lrange $key $first $last"
710 redis_multi_bulk_read $fd
711}
712
713proc redis_sort {fd key {params {}}} {
714 redis_writenl $fd "sort $key $params"
715 redis_multi_bulk_read $fd
716}
717
718proc redis_ltrim {fd key first last} {
719 redis_writenl $fd "ltrim $key $first $last"
720 redis_read_retcode $fd
721}
722
723proc redis_rename {fd key1 key2} {
724 redis_writenl $fd "rename $key1 $key2"
725 redis_read_retcode $fd
726}
727
728proc redis_renamenx {fd key1 key2} {
729 redis_writenl $fd "renamenx $key1 $key2"
730 redis_read_integer $fd
731}
732
733proc redis_lpop {fd key} {
734 redis_writenl $fd "lpop $key"
735 redis_bulk_read $fd
736}
737
738proc redis_rpop {fd key} {
739 redis_writenl $fd "rpop $key"
740 redis_bulk_read $fd
741}
742
743proc redis_lset {fd key index val} {
744 redis_writenl $fd "lset $key $index [string length $val]\r\n$val"
745 redis_read_retcode $fd
746}
747
748proc redis_sadd {fd key val} {
749 redis_writenl $fd "sadd $key [string length $val]\r\n$val"
750 redis_read_integer $fd
751}
752
753proc redis_srem {fd key val} {
754 redis_writenl $fd "srem $key [string length $val]\r\n$val"
755 redis_read_integer $fd
756}
757
758proc redis_sismember {fd key val} {
759 redis_writenl $fd "sismember $key [string length $val]\r\n$val"
760 redis_read_integer $fd
761}
762
763proc redis_sinter {fd args} {
764 redis_writenl $fd "sinter [join $args]\r\n"
765 redis_multi_bulk_read $fd
766}
767
768proc redis_sinterstore {fd args} {
769 redis_writenl $fd "sinterstore [join $args]\r\n"
770 redis_read_retcode $fd
771}
772
773proc redis_smembers {fd key} {
774 redis_writenl $fd "smembers $key\r\n"
775 redis_multi_bulk_read $fd
776}
777
778proc redis_echo {fd str} {
779 redis_writenl $fd "echo [string length $str]\r\n$str\r\n"
780 redis_writenl $fd "smembers $key\r\n"
781}
782
783proc redis_save {fd} {
784 redis_writenl $fd "save\r\n"
785 redis_read_retcode $fd
786}
787
788proc redis_flushall {fd} {
789 redis_writenl $fd "flushall\r\n"
790 redis_read_retcode $fd
791}
792
793proc redis_flushdb {fd} {
794 redis_writenl $fd "flushdb\r\n"
795 redis_read_retcode $fd
796}
797
798proc redis_lrem {fd key count val} {
799 redis_writenl $fd "lrem $key $count [string length $val]\r\n$val"
800 redis_read_integer $fd
801}
802
803if {[llength $argv] == 0} {
804 main 127.0.0.1 6379
805} else {
806 main [lindex $argv 0] [lindex $argv 1]
807}