xref: /redis-3.2.3/tests/unit/type/set.tcl (revision 414c3dea)
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 "SINTER against non-set should throw error" {
210        r set key1 x
211        assert_error "ERR*wrong kind*" {r sinter key1 noset}
212    }
213
214    test "SUNION against non-set should throw error" {
215        r set key1 x
216        assert_error "ERR*wrong kind*" {r sunion key1 noset}
217    }
218
219    test "SINTERSTORE against non existing keys should delete dstkey" {
220        r set setres xxx
221        assert_equal 0 [r sinterstore setres foo111 bar222]
222        assert_equal 0 [r exists setres]
223    }
224
225    test "SUNIONSTORE against non existing keys should delete dstkey" {
226        r set setres xxx
227        assert_equal 0 [r sunionstore setres foo111 bar222]
228        assert_equal 0 [r exists setres]
229    }
230
231    foreach {type contents} {hashtable {a b c} intset {1 2 3}} {
232        test "SPOP basics - $type" {
233            create_set myset $contents
234            assert_encoding $type myset
235            assert_equal $contents [lsort [list [r spop myset] [r spop myset] [r spop myset]]]
236            assert_equal 0 [r scard myset]
237        }
238
239        test "SRANDMEMBER - $type" {
240            create_set myset $contents
241            unset -nocomplain myset
242            array set myset {}
243            for {set i 0} {$i < 100} {incr i} {
244                set myset([r srandmember myset]) 1
245            }
246            assert_equal $contents [lsort [array names myset]]
247        }
248    }
249
250    proc setup_move {} {
251        r del myset3 myset4
252        create_set myset1 {1 a b}
253        create_set myset2 {2 3 4}
254        assert_encoding hashtable myset1
255        assert_encoding intset myset2
256    }
257
258    test "SMOVE basics - from regular set to intset" {
259        # move a non-integer element to an intset should convert encoding
260        setup_move
261        assert_equal 1 [r smove myset1 myset2 a]
262        assert_equal {1 b} [lsort [r smembers myset1]]
263        assert_equal {2 3 4 a} [lsort [r smembers myset2]]
264        assert_encoding hashtable myset2
265
266        # move an integer element should not convert the encoding
267        setup_move
268        assert_equal 1 [r smove myset1 myset2 1]
269        assert_equal {a b} [lsort [r smembers myset1]]
270        assert_equal {1 2 3 4} [lsort [r smembers myset2]]
271        assert_encoding intset myset2
272    }
273
274    test "SMOVE basics - from intset to regular set" {
275        setup_move
276        assert_equal 1 [r smove myset2 myset1 2]
277        assert_equal {1 2 a b} [lsort [r smembers myset1]]
278        assert_equal {3 4} [lsort [r smembers myset2]]
279    }
280
281    test "SMOVE non existing key" {
282        setup_move
283        assert_equal 0 [r smove myset1 myset2 foo]
284        assert_equal {1 a b} [lsort [r smembers myset1]]
285        assert_equal {2 3 4} [lsort [r smembers myset2]]
286    }
287
288    test "SMOVE non existing src set" {
289        setup_move
290        assert_equal 0 [r smove noset myset2 foo]
291        assert_equal {2 3 4} [lsort [r smembers myset2]]
292    }
293
294    test "SMOVE from regular set to non existing destination set" {
295        setup_move
296        assert_equal 1 [r smove myset1 myset3 a]
297        assert_equal {1 b} [lsort [r smembers myset1]]
298        assert_equal {a} [lsort [r smembers myset3]]
299        assert_encoding hashtable myset3
300    }
301
302    test "SMOVE from intset to non existing destination set" {
303        setup_move
304        assert_equal 1 [r smove myset2 myset3 2]
305        assert_equal {3 4} [lsort [r smembers myset2]]
306        assert_equal {2} [lsort [r smembers myset3]]
307        assert_encoding intset myset3
308    }
309
310    test "SMOVE wrong src key type" {
311        r set x 10
312        assert_error "ERR*wrong kind*" {r smove x myset2 foo}
313    }
314
315    test "SMOVE wrong dst key type" {
316        r set x 10
317        assert_error "ERR*wrong kind*" {r smove myset2 x foo}
318    }
319
320    tags {slow} {
321        test {intsets implementation stress testing} {
322            for {set j 0} {$j < 20} {incr j} {
323                unset -nocomplain s
324                array set s {}
325                r del s
326                set len [randomInt 1024]
327                for {set i 0} {$i < $len} {incr i} {
328                    randpath {
329                        set data [randomInt 65536]
330                    } {
331                        set data [randomInt 4294967296]
332                    } {
333                        set data [randomInt 18446744073709551616]
334                    }
335                    set s($data) {}
336                    r sadd s $data
337                }
338                assert_equal [lsort [r smembers s]] [lsort [array names s]]
339                set len [array size s]
340                for {set i 0} {$i < $len} {incr i} {
341                    set e [r spop s]
342                    if {![info exists s($e)]} {
343                        puts "Can't find '$e' on local array"
344                        puts "Local array: [lsort [r smembers s]]"
345                        puts "Remote array: [lsort [array names s]]"
346                        error "exception"
347                    }
348                    array unset s $e
349                }
350                assert_equal [r scard s] 0
351                assert_equal [array size s] 0
352            }
353        }
354    }
355}
356