]> git.saurik.com Git - redis.git/blame_incremental - tests/unit/type/set.tcl
New test: hash ziplist -> hashtable encoding conversion.
[redis.git] / tests / unit / type / set.tcl
... / ...
CommitLineData
1start_server {
2 tags {"set"}
3 overrides {
4 "set-max-intset-entries" 512
5 }
6} {
7 proc create_set {key entries} {
8 r del $key
9 foreach entry $entries { r sadd $key $entry }
10 }
11
12 test {SADD, SCARD, SISMEMBER, SMEMBERS basics - regular set} {
13 create_set myset {foo}
14 assert_encoding hashtable myset
15 assert_equal 1 [r sadd myset bar]
16 assert_equal 0 [r sadd myset bar]
17 assert_equal 2 [r scard myset]
18 assert_equal 1 [r sismember myset foo]
19 assert_equal 1 [r sismember myset bar]
20 assert_equal 0 [r sismember myset bla]
21 assert_equal {bar foo} [lsort [r smembers myset]]
22 }
23
24 test {SADD, SCARD, SISMEMBER, SMEMBERS basics - intset} {
25 create_set myset {17}
26 assert_encoding intset myset
27 assert_equal 1 [r sadd myset 16]
28 assert_equal 0 [r sadd myset 16]
29 assert_equal 2 [r scard myset]
30 assert_equal 1 [r sismember myset 16]
31 assert_equal 1 [r sismember myset 17]
32 assert_equal 0 [r sismember myset 18]
33 assert_equal {16 17} [lsort [r smembers myset]]
34 }
35
36 test {SADD against non set} {
37 r lpush mylist foo
38 assert_error ERR*kind* {r sadd mylist bar}
39 }
40
41 test "SADD a non-integer against an intset" {
42 create_set myset {1 2 3}
43 assert_encoding intset myset
44 assert_equal 1 [r sadd myset a]
45 assert_encoding hashtable myset
46 }
47
48 test "SADD an integer larger than 64 bits" {
49 create_set myset {213244124402402314402033402}
50 assert_encoding hashtable myset
51 assert_equal 1 [r sismember myset 213244124402402314402033402]
52 }
53
54 test "SADD overflows the maximum allowed integers in an intset" {
55 r del myset
56 for {set i 0} {$i < 512} {incr i} { r sadd myset $i }
57 assert_encoding intset myset
58 assert_equal 1 [r sadd myset 512]
59 assert_encoding hashtable myset
60 }
61
62 test {Variadic SADD} {
63 r del myset
64 assert_equal 3 [r sadd myset a b c]
65 assert_equal 2 [r sadd myset A a b c B]
66 assert_equal [lsort {A a b c B}] [lsort [r smembers myset]]
67 }
68
69 test "Set encoding after DEBUG RELOAD" {
70 r del myintset myhashset mylargeintset
71 for {set i 0} {$i < 100} {incr i} { r sadd myintset $i }
72 for {set i 0} {$i < 1280} {incr i} { r sadd mylargeintset $i }
73 for {set i 0} {$i < 256} {incr i} { r sadd myhashset [format "i%03d" $i] }
74 assert_encoding intset myintset
75 assert_encoding hashtable mylargeintset
76 assert_encoding hashtable myhashset
77
78 r debug reload
79 assert_encoding intset myintset
80 assert_encoding hashtable mylargeintset
81 assert_encoding hashtable myhashset
82 }
83
84 test {SREM basics - regular set} {
85 create_set myset {foo bar ciao}
86 assert_encoding hashtable myset
87 assert_equal 0 [r srem myset qux]
88 assert_equal 1 [r srem myset foo]
89 assert_equal {bar ciao} [lsort [r smembers myset]]
90 }
91
92 test {SREM basics - intset} {
93 create_set myset {3 4 5}
94 assert_encoding intset myset
95 assert_equal 0 [r srem myset 6]
96 assert_equal 1 [r srem myset 4]
97 assert_equal {3 5} [lsort [r smembers myset]]
98 }
99
100 test {SREM with multiple arguments} {
101 r del myset
102 r sadd myset a b c d
103 assert_equal 0 [r srem myset k k k]
104 assert_equal 2 [r srem myset b d x y]
105 lsort [r smembers myset]
106 } {a c}
107
108 test {SREM variadic version with more args needed to destroy the key} {
109 r del myset
110 r sadd myset 1 2 3
111 r srem myset 1 2 3 4 5 6 7 8
112 } {3}
113
114 foreach {type} {hashtable intset} {
115 for {set i 1} {$i <= 5} {incr i} {
116 r del [format "set%d" $i]
117 }
118 for {set i 0} {$i < 200} {incr i} {
119 r sadd set1 $i
120 r sadd set2 [expr $i+195]
121 }
122 foreach i {199 195 1000 2000} {
123 r sadd set3 $i
124 }
125 for {set i 5} {$i < 200} {incr i} {
126 r sadd set4 $i
127 }
128 r sadd set5 0
129
130 # To make sure the sets are encoded as the type we are testing -- also
131 # when the VM is enabled and the values may be swapped in and out
132 # while the tests are running -- an extra element is added to every
133 # set that determines its encoding.
134 set large 200
135 if {$type eq "hashtable"} {
136 set large foo
137 }
138
139 for {set i 1} {$i <= 5} {incr i} {
140 r sadd [format "set%d" $i] $large
141 }
142
143 test "Generated sets must be encoded as $type" {
144 for {set i 1} {$i <= 5} {incr i} {
145 assert_encoding $type [format "set%d" $i]
146 }
147 }
148
149 test "SINTER with two sets - $type" {
150 assert_equal [list 195 196 197 198 199 $large] [lsort [r sinter set1 set2]]
151 }
152
153 test "SINTERSTORE with two sets - $type" {
154 r sinterstore setres set1 set2
155 assert_encoding $type setres
156 assert_equal [list 195 196 197 198 199 $large] [lsort [r smembers setres]]
157 }
158
159 test "SINTERSTORE with two sets, after a DEBUG RELOAD - $type" {
160 r debug reload
161 r sinterstore setres set1 set2
162 assert_encoding $type setres
163 assert_equal [list 195 196 197 198 199 $large] [lsort [r smembers setres]]
164 }
165
166 test "SUNION with two sets - $type" {
167 set expected [lsort -uniq "[r smembers set1] [r smembers set2]"]
168 assert_equal $expected [lsort [r sunion set1 set2]]
169 }
170
171 test "SUNIONSTORE with two sets - $type" {
172 r sunionstore setres set1 set2
173 assert_encoding $type setres
174 set expected [lsort -uniq "[r smembers set1] [r smembers set2]"]
175 assert_equal $expected [lsort [r smembers setres]]
176 }
177
178 test "SINTER against three sets - $type" {
179 assert_equal [list 195 199 $large] [lsort [r sinter set1 set2 set3]]
180 }
181
182 test "SINTERSTORE with three sets - $type" {
183 r sinterstore setres set1 set2 set3
184 assert_equal [list 195 199 $large] [lsort [r smembers setres]]
185 }
186
187 test "SUNION with non existing keys - $type" {
188 set expected [lsort -uniq "[r smembers set1] [r smembers set2]"]
189 assert_equal $expected [lsort [r sunion nokey1 set1 set2 nokey2]]
190 }
191
192 test "SDIFF with two sets - $type" {
193 assert_equal {0 1 2 3 4} [lsort [r sdiff set1 set4]]
194 }
195
196 test "SDIFF with three sets - $type" {
197 assert_equal {1 2 3 4} [lsort [r sdiff set1 set4 set5]]
198 }
199
200 test "SDIFFSTORE with three sets - $type" {
201 r sdiffstore setres set1 set4 set5
202 # The type is determined by type of the first key to diff against.
203 # See the implementation for more information.
204 assert_encoding $type setres
205 assert_equal {1 2 3 4} [lsort [r smembers setres]]
206 }
207 }
208
209 test "SDIFF with first set empty" {
210 r del set1 set2 set3
211 r sadd set2 1 2 3 4
212 r sadd set3 a b c d
213 r sdiff set1 set2 set3
214 } {}
215
216 test "SINTER against non-set should throw error" {
217 r set key1 x
218 assert_error "ERR*wrong kind*" {r sinter key1 noset}
219 }
220
221 test "SUNION against non-set should throw error" {
222 r set key1 x
223 assert_error "ERR*wrong kind*" {r sunion key1 noset}
224 }
225
226 test "SINTER should handle non existing key as empty" {
227 r del set1 set2 set3
228 r sadd set1 a b c
229 r sadd set2 b c d
230 r sinter set1 set2 set3
231 } {}
232
233 test "SINTER with same integer elements but different encoding" {
234 r del set1 set2
235 r sadd set1 1 2 3
236 r sadd set2 1 2 3 a
237 r srem set2 a
238 assert_encoding intset set1
239 assert_encoding hashtable set2
240 lsort [r sinter set1 set2]
241 } {1 2 3}
242
243 test "SINTERSTORE against non existing keys should delete dstkey" {
244 r set setres xxx
245 assert_equal 0 [r sinterstore setres foo111 bar222]
246 assert_equal 0 [r exists setres]
247 }
248
249 test "SUNIONSTORE against non existing keys should delete dstkey" {
250 r set setres xxx
251 assert_equal 0 [r sunionstore setres foo111 bar222]
252 assert_equal 0 [r exists setres]
253 }
254
255 foreach {type contents} {hashtable {a b c} intset {1 2 3}} {
256 test "SPOP basics - $type" {
257 create_set myset $contents
258 assert_encoding $type myset
259 assert_equal $contents [lsort [list [r spop myset] [r spop myset] [r spop myset]]]
260 assert_equal 0 [r scard myset]
261 }
262
263 test "SRANDMEMBER - $type" {
264 create_set myset $contents
265 unset -nocomplain myset
266 array set myset {}
267 for {set i 0} {$i < 100} {incr i} {
268 set myset([r srandmember myset]) 1
269 }
270 assert_equal $contents [lsort [array names myset]]
271 }
272 }
273
274 proc setup_move {} {
275 r del myset3 myset4
276 create_set myset1 {1 a b}
277 create_set myset2 {2 3 4}
278 assert_encoding hashtable myset1
279 assert_encoding intset myset2
280 }
281
282 test "SMOVE basics - from regular set to intset" {
283 # move a non-integer element to an intset should convert encoding
284 setup_move
285 assert_equal 1 [r smove myset1 myset2 a]
286 assert_equal {1 b} [lsort [r smembers myset1]]
287 assert_equal {2 3 4 a} [lsort [r smembers myset2]]
288 assert_encoding hashtable myset2
289
290 # move an integer element should not convert the encoding
291 setup_move
292 assert_equal 1 [r smove myset1 myset2 1]
293 assert_equal {a b} [lsort [r smembers myset1]]
294 assert_equal {1 2 3 4} [lsort [r smembers myset2]]
295 assert_encoding intset myset2
296 }
297
298 test "SMOVE basics - from intset to regular set" {
299 setup_move
300 assert_equal 1 [r smove myset2 myset1 2]
301 assert_equal {1 2 a b} [lsort [r smembers myset1]]
302 assert_equal {3 4} [lsort [r smembers myset2]]
303 }
304
305 test "SMOVE non existing key" {
306 setup_move
307 assert_equal 0 [r smove myset1 myset2 foo]
308 assert_equal {1 a b} [lsort [r smembers myset1]]
309 assert_equal {2 3 4} [lsort [r smembers myset2]]
310 }
311
312 test "SMOVE non existing src set" {
313 setup_move
314 assert_equal 0 [r smove noset myset2 foo]
315 assert_equal {2 3 4} [lsort [r smembers myset2]]
316 }
317
318 test "SMOVE from regular set to non existing destination set" {
319 setup_move
320 assert_equal 1 [r smove myset1 myset3 a]
321 assert_equal {1 b} [lsort [r smembers myset1]]
322 assert_equal {a} [lsort [r smembers myset3]]
323 assert_encoding hashtable myset3
324 }
325
326 test "SMOVE from intset to non existing destination set" {
327 setup_move
328 assert_equal 1 [r smove myset2 myset3 2]
329 assert_equal {3 4} [lsort [r smembers myset2]]
330 assert_equal {2} [lsort [r smembers myset3]]
331 assert_encoding intset myset3
332 }
333
334 test "SMOVE wrong src key type" {
335 r set x 10
336 assert_error "ERR*wrong kind*" {r smove x myset2 foo}
337 }
338
339 test "SMOVE wrong dst key type" {
340 r set x 10
341 assert_error "ERR*wrong kind*" {r smove myset2 x foo}
342 }
343
344 test "SMOVE with identical source and destination" {
345 r del set
346 r sadd set a b c
347 r smove set set b
348 lsort [r smembers set]
349 } {a b c}
350
351 tags {slow} {
352 test {intsets implementation stress testing} {
353 for {set j 0} {$j < 20} {incr j} {
354 unset -nocomplain s
355 array set s {}
356 r del s
357 set len [randomInt 1024]
358 for {set i 0} {$i < $len} {incr i} {
359 randpath {
360 set data [randomInt 65536]
361 } {
362 set data [randomInt 4294967296]
363 } {
364 set data [randomInt 18446744073709551616]
365 }
366 set s($data) {}
367 r sadd s $data
368 }
369 assert_equal [lsort [r smembers s]] [lsort [array names s]]
370 set len [array size s]
371 for {set i 0} {$i < $len} {incr i} {
372 set e [r spop s]
373 if {![info exists s($e)]} {
374 puts "Can't find '$e' on local array"
375 puts "Local array: [lsort [r smembers s]]"
376 puts "Remote array: [lsort [array names s]]"
377 error "exception"
378 }
379 array unset s $e
380 }
381 assert_equal [r scard s] 0
382 assert_equal [array size s] 0
383 }
384 }
385 }
386}