xref: /redis-3.2.3/tests/unit/type/string.tcl (revision 74354cee)
1start_server {tags {"string"}} {
2    test {SET and GET an item} {
3        r set x foobar
4        r get x
5    } {foobar}
6
7    test {SET and GET an empty item} {
8        r set x {}
9        r get x
10    } {}
11
12    test {Very big payload in GET/SET} {
13        set buf [string repeat "abcd" 1000000]
14        r set foo $buf
15        r get foo
16    } [string repeat "abcd" 1000000]
17
18    tags {"slow"} {
19        test {Very big payload random access} {
20            set err {}
21            array set payload {}
22            for {set j 0} {$j < 100} {incr j} {
23                set size [expr 1+[randomInt 100000]]
24                set buf [string repeat "pl-$j" $size]
25                set payload($j) $buf
26                r set bigpayload_$j $buf
27            }
28            for {set j 0} {$j < 1000} {incr j} {
29                set index [randomInt 100]
30                set buf [r get bigpayload_$index]
31                if {$buf != $payload($index)} {
32                    set err "Values differ: I set '$payload($index)' but I read back '$buf'"
33                    break
34                }
35            }
36            unset payload
37            set _ $err
38        } {}
39
40        test {SET 10000 numeric keys and access all them in reverse order} {
41            r flushdb
42            set err {}
43            for {set x 0} {$x < 10000} {incr x} {
44                r set $x $x
45            }
46            set sum 0
47            for {set x 9999} {$x >= 0} {incr x -1} {
48                set val [r get $x]
49                if {$val ne $x} {
50                    set err "Element at position $x is $val instead of $x"
51                    break
52                }
53            }
54            set _ $err
55        } {}
56
57        test {DBSIZE should be 10000 now} {
58            r dbsize
59        } {10000}
60    }
61
62    test "SETNX target key missing" {
63        r del novar
64        assert_equal 1 [r setnx novar foobared]
65        assert_equal "foobared" [r get novar]
66    }
67
68    test "SETNX target key exists" {
69        r set novar foobared
70        assert_equal 0 [r setnx novar blabla]
71        assert_equal "foobared" [r get novar]
72    }
73
74    test "SETNX against not-expired volatile key" {
75        r set x 10
76        r expire x 10000
77        assert_equal 0 [r setnx x 20]
78        assert_equal 10 [r get x]
79    }
80
81    test "SETNX against expired volatile key" {
82        # Make it very unlikely for the key this test uses to be expired by the
83        # active expiry cycle. This is tightly coupled to the implementation of
84        # active expiry and dbAdd() but currently the only way to test that
85        # SETNX expires a key when it should have been.
86        for {set x 0} {$x < 9999} {incr x} {
87            r setex key-$x 3600 value
88        }
89
90        # This will be one of 10000 expiring keys. A cycle is executed every
91        # 100ms, sampling 10 keys for being expired or not.  This key will be
92        # expired for at most 1s when we wait 2s, resulting in a total sample
93        # of 100 keys. The probability of the success of this test being a
94        # false positive is therefore approx. 1%.
95        r set x 10
96        r expire x 1
97
98        # Wait for the key to expire
99        after 2000
100
101        assert_equal 1 [r setnx x 20]
102        assert_equal 20 [r get x]
103    }
104
105    test {MGET} {
106        r flushdb
107        r set foo BAR
108        r set bar FOO
109        r mget foo bar
110    } {BAR FOO}
111
112    test {MGET against non existing key} {
113        r mget foo baazz bar
114    } {BAR {} FOO}
115
116    test {MGET against non-string key} {
117        r sadd myset ciao
118        r sadd myset bau
119        r mget foo baazz bar myset
120    } {BAR {} FOO {}}
121
122    test {GETSET (set new value)} {
123        r del foo
124        list [r getset foo xyz] [r get foo]
125    } {{} xyz}
126
127    test {GETSET (replace old value)} {
128        r set foo bar
129        list [r getset foo xyz] [r get foo]
130    } {bar xyz}
131
132    test {MSET base case} {
133        r mset x 10 y "foo bar" z "x x x x x x x\n\n\r\n"
134        r mget x y z
135    } [list 10 {foo bar} "x x x x x x x\n\n\r\n"]
136
137    test {MSET wrong number of args} {
138        catch {r mset x 10 y "foo bar" z} err
139        format $err
140    } {*wrong number*}
141
142    test {MSETNX with already existent key} {
143        list [r msetnx x1 xxx y2 yyy x 20] [r exists x1] [r exists y2]
144    } {0 0 0}
145
146    test {MSETNX with not existing keys} {
147        list [r msetnx x1 xxx y2 yyy] [r get x1] [r get y2]
148    } {1 xxx yyy}
149
150    test "STRLEN against non-existing key" {
151        assert_equal 0 [r strlen notakey]
152    }
153
154    test "STRLEN against integer-encoded value" {
155        r set myinteger -555
156        assert_equal 4 [r strlen myinteger]
157    }
158
159    test "STRLEN against plain string" {
160        r set mystring "foozzz0123456789 baz"
161        assert_equal 20 [r strlen mystring]
162    }
163
164    test "SETBIT against non-existing key" {
165        r del mykey
166        assert_equal 0 [r setbit mykey 1 1]
167        assert_equal [binary format B* 01000000] [r get mykey]
168    }
169
170    test "SETBIT against string-encoded key" {
171        # Ascii "@" is integer 64 = 01 00 00 00
172        r set mykey "@"
173
174        assert_equal 0 [r setbit mykey 2 1]
175        assert_equal [binary format B* 01100000] [r get mykey]
176        assert_equal 1 [r setbit mykey 1 0]
177        assert_equal [binary format B* 00100000] [r get mykey]
178    }
179
180    test "SETBIT against integer-encoded key" {
181        # Ascii "1" is integer 49 = 00 11 00 01
182        r set mykey 1
183        assert_encoding int mykey
184
185        assert_equal 0 [r setbit mykey 6 1]
186        assert_equal [binary format B* 00110011] [r get mykey]
187        assert_equal 1 [r setbit mykey 2 0]
188        assert_equal [binary format B* 00010011] [r get mykey]
189    }
190
191    test "SETBIT against key with wrong type" {
192        r del mykey
193        r lpush mykey "foo"
194        assert_error "WRONGTYPE*" {r setbit mykey 0 1}
195    }
196
197    test "SETBIT with out of range bit offset" {
198        r del mykey
199        assert_error "*out of range*" {r setbit mykey [expr 4*1024*1024*1024] 1}
200        assert_error "*out of range*" {r setbit mykey -1 1}
201    }
202
203    test "SETBIT with non-bit argument" {
204        r del mykey
205        assert_error "*out of range*" {r setbit mykey 0 -1}
206        assert_error "*out of range*" {r setbit mykey 0  2}
207        assert_error "*out of range*" {r setbit mykey 0 10}
208        assert_error "*out of range*" {r setbit mykey 0 20}
209    }
210
211    test "SETBIT fuzzing" {
212        set str ""
213        set len [expr 256*8]
214        r del mykey
215
216        for {set i 0} {$i < 2000} {incr i} {
217            set bitnum [randomInt $len]
218            set bitval [randomInt 2]
219            set fmt [format "%%-%ds%%d%%-s" $bitnum]
220            set head [string range $str 0 $bitnum-1]
221            set tail [string range $str $bitnum+1 end]
222            set str [string map {" " 0} [format $fmt $head $bitval $tail]]
223
224            r setbit mykey $bitnum $bitval
225            assert_equal [binary format B* $str] [r get mykey]
226        }
227    }
228
229    test "GETBIT against non-existing key" {
230        r del mykey
231        assert_equal 0 [r getbit mykey 0]
232    }
233
234    test "GETBIT against string-encoded key" {
235        # Single byte with 2nd and 3rd bit set
236        r set mykey "`"
237
238        # In-range
239        assert_equal 0 [r getbit mykey 0]
240        assert_equal 1 [r getbit mykey 1]
241        assert_equal 1 [r getbit mykey 2]
242        assert_equal 0 [r getbit mykey 3]
243
244        # Out-range
245        assert_equal 0 [r getbit mykey 8]
246        assert_equal 0 [r getbit mykey 100]
247        assert_equal 0 [r getbit mykey 10000]
248    }
249
250    test "GETBIT against integer-encoded key" {
251        r set mykey 1
252        assert_encoding int mykey
253
254        # Ascii "1" is integer 49 = 00 11 00 01
255        assert_equal 0 [r getbit mykey 0]
256        assert_equal 0 [r getbit mykey 1]
257        assert_equal 1 [r getbit mykey 2]
258        assert_equal 1 [r getbit mykey 3]
259
260        # Out-range
261        assert_equal 0 [r getbit mykey 8]
262        assert_equal 0 [r getbit mykey 100]
263        assert_equal 0 [r getbit mykey 10000]
264    }
265
266    test "SETRANGE against non-existing key" {
267        r del mykey
268        assert_equal 3 [r setrange mykey 0 foo]
269        assert_equal "foo" [r get mykey]
270
271        r del mykey
272        assert_equal 0 [r setrange mykey 0 ""]
273        assert_equal 0 [r exists mykey]
274
275        r del mykey
276        assert_equal 4 [r setrange mykey 1 foo]
277        assert_equal "\000foo" [r get mykey]
278    }
279
280    test "SETRANGE against string-encoded key" {
281        r set mykey "foo"
282        assert_equal 3 [r setrange mykey 0 b]
283        assert_equal "boo" [r get mykey]
284
285        r set mykey "foo"
286        assert_equal 3 [r setrange mykey 0 ""]
287        assert_equal "foo" [r get mykey]
288
289        r set mykey "foo"
290        assert_equal 3 [r setrange mykey 1 b]
291        assert_equal "fbo" [r get mykey]
292
293        r set mykey "foo"
294        assert_equal 7 [r setrange mykey 4 bar]
295        assert_equal "foo\000bar" [r get mykey]
296    }
297
298    test "SETRANGE against integer-encoded key" {
299        r set mykey 1234
300        assert_encoding int mykey
301        assert_equal 4 [r setrange mykey 0 2]
302        assert_encoding raw mykey
303        assert_equal 2234 [r get mykey]
304
305        # Shouldn't change encoding when nothing is set
306        r set mykey 1234
307        assert_encoding int mykey
308        assert_equal 4 [r setrange mykey 0 ""]
309        assert_encoding int mykey
310        assert_equal 1234 [r get mykey]
311
312        r set mykey 1234
313        assert_encoding int mykey
314        assert_equal 4 [r setrange mykey 1 3]
315        assert_encoding raw mykey
316        assert_equal 1334 [r get mykey]
317
318        r set mykey 1234
319        assert_encoding int mykey
320        assert_equal 6 [r setrange mykey 5 2]
321        assert_encoding raw mykey
322        assert_equal "1234\0002" [r get mykey]
323    }
324
325    test "SETRANGE against key with wrong type" {
326        r del mykey
327        r lpush mykey "foo"
328        assert_error "WRONGTYPE*" {r setrange mykey 0 bar}
329    }
330
331    test "SETRANGE with out of range offset" {
332        r del mykey
333        assert_error "*maximum allowed size*" {r setrange mykey [expr 512*1024*1024-4] world}
334
335        r set mykey "hello"
336        assert_error "*out of range*" {r setrange mykey -1 world}
337        assert_error "*maximum allowed size*" {r setrange mykey [expr 512*1024*1024-4] world}
338    }
339
340    test "GETRANGE against non-existing key" {
341        r del mykey
342        assert_equal "" [r getrange mykey 0 -1]
343    }
344
345    test "GETRANGE against string value" {
346        r set mykey "Hello World"
347        assert_equal "Hell" [r getrange mykey 0 3]
348        assert_equal "Hello World" [r getrange mykey 0 -1]
349        assert_equal "orld" [r getrange mykey -4 -1]
350        assert_equal "" [r getrange mykey 5 3]
351        assert_equal " World" [r getrange mykey 5 5000]
352        assert_equal "Hello World" [r getrange mykey -5000 10000]
353    }
354
355    test "GETRANGE against integer-encoded value" {
356        r set mykey 1234
357        assert_equal "123" [r getrange mykey 0 2]
358        assert_equal "1234" [r getrange mykey 0 -1]
359        assert_equal "234" [r getrange mykey -3 -1]
360        assert_equal "" [r getrange mykey 5 3]
361        assert_equal "4" [r getrange mykey 3 5000]
362        assert_equal "1234" [r getrange mykey -5000 10000]
363    }
364
365    test "GETRANGE fuzzing" {
366        for {set i 0} {$i < 1000} {incr i} {
367            r set bin [set bin [randstring 0 1024 binary]]
368            set _start [set start [randomInt 1500]]
369            set _end [set end [randomInt 1500]]
370            if {$_start < 0} {set _start "end-[abs($_start)-1]"}
371            if {$_end < 0} {set _end "end-[abs($_end)-1]"}
372            assert_equal [string range $bin $_start $_end] [r getrange bin $start $end]
373        }
374    }
375
376    test {Extended SET can detect syntax errors} {
377        set e {}
378        catch {r set foo bar non-existing-option} e
379        set e
380    } {*syntax*}
381
382    test {Extended SET NX option} {
383        r del foo
384        set v1 [r set foo 1 nx]
385        set v2 [r set foo 2 nx]
386        list $v1 $v2 [r get foo]
387    } {OK {} 1}
388
389    test {Extended SET XX option} {
390        r del foo
391        set v1 [r set foo 1 xx]
392        r set foo bar
393        set v2 [r set foo 2 xx]
394        list $v1 $v2 [r get foo]
395    } {{} OK 2}
396
397    test {Extended SET EX option} {
398        r del foo
399        r set foo bar ex 10
400        set ttl [r ttl foo]
401        assert {$ttl <= 10 && $ttl > 5}
402    }
403
404    test {Extended SET PX option} {
405        r del foo
406        r set foo bar px 10000
407        set ttl [r ttl foo]
408        assert {$ttl <= 10 && $ttl > 5}
409    }
410
411    test {Extended SET using multiple options at once} {
412        r set foo val
413        assert {[r set foo bar xx px 10000] eq {OK}}
414        set ttl [r ttl foo]
415        assert {$ttl <= 10 && $ttl > 5}
416    }
417
418    test {GETRANGE with huge ranges, Github issue #1844} {
419        r set foo bar
420        r getrange foo 0 4294967297
421    } {bar}
422}
423