]> git.saurik.com Git - redis.git/blob - tests/unit/type/set.tcl
SDIFF fuzz test added.
[redis.git] / tests / unit / type / set.tcl
1 start_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 WRONGTYPE* {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 "SDIFF fuzzing" {
217 for {set j 0} {$j < 100} {incr j} {
218 unset -nocomplain s
219 array set s {}
220 set args {}
221 set num_sets [expr {[randomInt 10]+1}]
222 for {set i 0} {$i < $num_sets} {incr i} {
223 set num_elements [randomInt 100]
224 r del set_$i
225 lappend args set_$i
226 while {$num_elements} {
227 set ele [randomValue]
228 r sadd set_$i $ele
229 if {$i == 0} {
230 set s($ele) x
231 } else {
232 unset -nocomplain s($ele)
233 }
234 incr num_elements -1
235 }
236 }
237 set result [lsort [r sdiff {*}$args]]
238 assert_equal $result [lsort [array names s]]
239 }
240 }
241
242 test "SINTER against non-set should throw error" {
243 r set key1 x
244 assert_error "WRONGTYPE*" {r sinter key1 noset}
245 }
246
247 test "SUNION against non-set should throw error" {
248 r set key1 x
249 assert_error "WRONGTYPE*" {r sunion key1 noset}
250 }
251
252 test "SINTER should handle non existing key as empty" {
253 r del set1 set2 set3
254 r sadd set1 a b c
255 r sadd set2 b c d
256 r sinter set1 set2 set3
257 } {}
258
259 test "SINTER with same integer elements but different encoding" {
260 r del set1 set2
261 r sadd set1 1 2 3
262 r sadd set2 1 2 3 a
263 r srem set2 a
264 assert_encoding intset set1
265 assert_encoding hashtable set2
266 lsort [r sinter set1 set2]
267 } {1 2 3}
268
269 test "SINTERSTORE against non existing keys should delete dstkey" {
270 r set setres xxx
271 assert_equal 0 [r sinterstore setres foo111 bar222]
272 assert_equal 0 [r exists setres]
273 }
274
275 test "SUNIONSTORE against non existing keys should delete dstkey" {
276 r set setres xxx
277 assert_equal 0 [r sunionstore setres foo111 bar222]
278 assert_equal 0 [r exists setres]
279 }
280
281 foreach {type contents} {hashtable {a b c} intset {1 2 3}} {
282 test "SPOP basics - $type" {
283 create_set myset $contents
284 assert_encoding $type myset
285 assert_equal $contents [lsort [list [r spop myset] [r spop myset] [r spop myset]]]
286 assert_equal 0 [r scard myset]
287 }
288
289 test "SRANDMEMBER - $type" {
290 create_set myset $contents
291 unset -nocomplain myset
292 array set myset {}
293 for {set i 0} {$i < 100} {incr i} {
294 set myset([r srandmember myset]) 1
295 }
296 assert_equal $contents [lsort [array names myset]]
297 }
298 }
299
300 test "SRANDMEMBER with <count> against non existing key" {
301 r srandmember nonexisting_key 100
302 } {}
303
304 foreach {type contents} {
305 hashtable {
306 1 5 10 50 125 50000 33959417 4775547 65434162
307 12098459 427716 483706 2726473884 72615637475
308 MARY PATRICIA LINDA BARBARA ELIZABETH JENNIFER MARIA
309 SUSAN MARGARET DOROTHY LISA NANCY KAREN BETTY HELEN
310 SANDRA DONNA CAROL RUTH SHARON MICHELLE LAURA SARAH
311 KIMBERLY DEBORAH JESSICA SHIRLEY CYNTHIA ANGELA MELISSA
312 BRENDA AMY ANNA REBECCA VIRGINIA KATHLEEN
313 }
314 intset {
315 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
316 20 21 22 23 24 25 26 27 28 29
317 30 31 32 33 34 35 36 37 38 39
318 40 41 42 43 44 45 46 47 48 49
319 }
320 } {
321 test "SRANDMEMBER with <count> - $type" {
322 create_set myset $contents
323 unset -nocomplain myset
324 array set myset {}
325 foreach ele [r smembers myset] {
326 set myset($ele) 1
327 }
328 assert_equal [lsort $contents] [lsort [array names myset]]
329
330 # Make sure that a count of 0 is handled correctly.
331 assert_equal [r srandmember myset 0] {}
332
333 # We'll stress different parts of the code, see the implementation
334 # of SRANDMEMBER for more information, but basically there are
335 # four different code paths.
336 #
337 # PATH 1: Use negative count.
338 #
339 # 1) Check that it returns repeated elements.
340 set res [r srandmember myset -100]
341 assert_equal [llength $res] 100
342
343 # 2) Check that all the elements actually belong to the
344 # original set.
345 foreach ele $res {
346 assert {[info exists myset($ele)]}
347 }
348
349 # 3) Check that eventually all the elements are returned.
350 unset -nocomplain auxset
351 set iterations 1000
352 while {$iterations != 0} {
353 incr iterations -1
354 set res [r srandmember myset -10]
355 foreach ele $res {
356 set auxset($ele) 1
357 }
358 if {[lsort [array names myset]] eq
359 [lsort [array names auxset]]} {
360 break;
361 }
362 }
363 assert {$iterations != 0}
364
365 # PATH 2: positive count (unique behavior) with requested size
366 # equal or greater than set size.
367 foreach size {50 100} {
368 set res [r srandmember myset $size]
369 assert_equal [llength $res] 50
370 assert_equal [lsort $res] [lsort [array names myset]]
371 }
372
373 # PATH 3: Ask almost as elements as there are in the set.
374 # In this case the implementation will duplicate the original
375 # set and will remove random elements up to the requested size.
376 #
377 # PATH 4: Ask a number of elements definitely smaller than
378 # the set size.
379 #
380 # We can test both the code paths just changing the size but
381 # using the same code.
382
383 foreach size {45 5} {
384 set res [r srandmember myset $size]
385 assert_equal [llength $res] $size
386
387 # 1) Check that all the elements actually belong to the
388 # original set.
389 foreach ele $res {
390 assert {[info exists myset($ele)]}
391 }
392
393 # 2) Check that eventually all the elements are returned.
394 unset -nocomplain auxset
395 set iterations 1000
396 while {$iterations != 0} {
397 incr iterations -1
398 set res [r srandmember myset -10]
399 foreach ele $res {
400 set auxset($ele) 1
401 }
402 if {[lsort [array names myset]] eq
403 [lsort [array names auxset]]} {
404 break;
405 }
406 }
407 assert {$iterations != 0}
408 }
409 }
410 }
411
412 proc setup_move {} {
413 r del myset3 myset4
414 create_set myset1 {1 a b}
415 create_set myset2 {2 3 4}
416 assert_encoding hashtable myset1
417 assert_encoding intset myset2
418 }
419
420 test "SMOVE basics - from regular set to intset" {
421 # move a non-integer element to an intset should convert encoding
422 setup_move
423 assert_equal 1 [r smove myset1 myset2 a]
424 assert_equal {1 b} [lsort [r smembers myset1]]
425 assert_equal {2 3 4 a} [lsort [r smembers myset2]]
426 assert_encoding hashtable myset2
427
428 # move an integer element should not convert the encoding
429 setup_move
430 assert_equal 1 [r smove myset1 myset2 1]
431 assert_equal {a b} [lsort [r smembers myset1]]
432 assert_equal {1 2 3 4} [lsort [r smembers myset2]]
433 assert_encoding intset myset2
434 }
435
436 test "SMOVE basics - from intset to regular set" {
437 setup_move
438 assert_equal 1 [r smove myset2 myset1 2]
439 assert_equal {1 2 a b} [lsort [r smembers myset1]]
440 assert_equal {3 4} [lsort [r smembers myset2]]
441 }
442
443 test "SMOVE non existing key" {
444 setup_move
445 assert_equal 0 [r smove myset1 myset2 foo]
446 assert_equal {1 a b} [lsort [r smembers myset1]]
447 assert_equal {2 3 4} [lsort [r smembers myset2]]
448 }
449
450 test "SMOVE non existing src set" {
451 setup_move
452 assert_equal 0 [r smove noset myset2 foo]
453 assert_equal {2 3 4} [lsort [r smembers myset2]]
454 }
455
456 test "SMOVE from regular set to non existing destination set" {
457 setup_move
458 assert_equal 1 [r smove myset1 myset3 a]
459 assert_equal {1 b} [lsort [r smembers myset1]]
460 assert_equal {a} [lsort [r smembers myset3]]
461 assert_encoding hashtable myset3
462 }
463
464 test "SMOVE from intset to non existing destination set" {
465 setup_move
466 assert_equal 1 [r smove myset2 myset3 2]
467 assert_equal {3 4} [lsort [r smembers myset2]]
468 assert_equal {2} [lsort [r smembers myset3]]
469 assert_encoding intset myset3
470 }
471
472 test "SMOVE wrong src key type" {
473 r set x 10
474 assert_error "WRONGTYPE*" {r smove x myset2 foo}
475 }
476
477 test "SMOVE wrong dst key type" {
478 r set x 10
479 assert_error "WRONGTYPE*" {r smove myset2 x foo}
480 }
481
482 test "SMOVE with identical source and destination" {
483 r del set
484 r sadd set a b c
485 r smove set set b
486 lsort [r smembers set]
487 } {a b c}
488
489 tags {slow} {
490 test {intsets implementation stress testing} {
491 for {set j 0} {$j < 20} {incr j} {
492 unset -nocomplain s
493 array set s {}
494 r del s
495 set len [randomInt 1024]
496 for {set i 0} {$i < $len} {incr i} {
497 randpath {
498 set data [randomInt 65536]
499 } {
500 set data [randomInt 4294967296]
501 } {
502 set data [randomInt 18446744073709551616]
503 }
504 set s($data) {}
505 r sadd s $data
506 }
507 assert_equal [lsort [r smembers s]] [lsort [array names s]]
508 set len [array size s]
509 for {set i 0} {$i < $len} {incr i} {
510 set e [r spop s]
511 if {![info exists s($e)]} {
512 puts "Can't find '$e' on local array"
513 puts "Local array: [lsort [r smembers s]]"
514 puts "Remote array: [lsort [array names s]]"
515 error "exception"
516 }
517 array unset s $e
518 }
519 assert_equal [r scard s] 0
520 assert_equal [array size s] 0
521 }
522 }
523 }
524 }