1start_server {tags {"zset"}} { 2 proc create_zset {key items} { 3 r del $key 4 foreach {score entry} $items { 5 r zadd $key $score $entry 6 } 7 } 8 9 proc basics {encoding} { 10 if {$encoding == "ziplist"} { 11 r config set zset-max-ziplist-entries 128 12 r config set zset-max-ziplist-value 64 13 } elseif {$encoding == "skiplist"} { 14 r config set zset-max-ziplist-entries 0 15 r config set zset-max-ziplist-value 0 16 } else { 17 puts "Unknown sorted set encoding" 18 exit 19 } 20 21 test "Check encoding - $encoding" { 22 r del ztmp 23 r zadd ztmp 10 x 24 assert_encoding $encoding ztmp 25 } 26 27 test "ZSET basic ZADD and score update - $encoding" { 28 r del ztmp 29 r zadd ztmp 10 x 30 r zadd ztmp 20 y 31 r zadd ztmp 30 z 32 assert_equal {x y z} [r zrange ztmp 0 -1] 33 34 r zadd ztmp 1 y 35 assert_equal {y x z} [r zrange ztmp 0 -1] 36 } 37 38 test "ZSET element can't be set to NaN with ZADD - $encoding" { 39 assert_error "*not*float*" {r zadd myzset nan abc} 40 } 41 42 test "ZSET element can't be set to NaN with ZINCRBY" { 43 assert_error "*not*float*" {r zadd myzset nan abc} 44 } 45 46 test "ZADD with options syntax error with incomplete pair" { 47 r del ztmp 48 catch {r zadd ztmp xx 10 x 20} err 49 set err 50 } {ERR*} 51 52 test "ZADD XX option without key - $encoding" { 53 r del ztmp 54 assert {[r zadd ztmp xx 10 x] == 0} 55 assert {[r type ztmp] eq {none}} 56 } 57 58 test "ZADD XX existing key - $encoding" { 59 r del ztmp 60 r zadd ztmp 10 x 61 assert {[r zadd ztmp xx 20 y] == 0} 62 assert {[r zcard ztmp] == 1} 63 } 64 65 test "ZADD XX returns the number of elements actually added" { 66 r del ztmp 67 r zadd ztmp 10 x 68 set retval [r zadd ztmp 10 x 20 y 30 z] 69 assert {$retval == 2} 70 } 71 72 test "ZADD XX updates existing elements score" { 73 r del ztmp 74 r zadd ztmp 10 x 20 y 30 z 75 r zadd ztmp xx 5 foo 11 x 21 y 40 zap 76 assert {[r zcard ztmp] == 3} 77 assert {[r zscore ztmp x] == 11} 78 assert {[r zscore ztmp y] == 21} 79 } 80 81 test "ZADD XX and NX are not compatible" { 82 r del ztmp 83 catch {r zadd ztmp xx nx 10 x} err 84 set err 85 } {ERR*} 86 87 test "ZADD NX with non existing key" { 88 r del ztmp 89 r zadd ztmp nx 10 x 20 y 30 z 90 assert {[r zcard ztmp] == 3} 91 } 92 93 test "ZADD NX only add new elements without updating old ones" { 94 r del ztmp 95 r zadd ztmp 10 x 20 y 30 z 96 assert {[r zadd ztmp nx 11 x 21 y 100 a 200 b] == 2} 97 assert {[r zscore ztmp x] == 10} 98 assert {[r zscore ztmp y] == 20} 99 assert {[r zscore ztmp a] == 100} 100 assert {[r zscore ztmp b] == 200} 101 } 102 103 test "ZADD INCR works like ZINCRBY" { 104 r del ztmp 105 r zadd ztmp 10 x 20 y 30 z 106 r zadd ztmp INCR 15 x 107 assert {[r zscore ztmp x] == 25} 108 } 109 110 test "ZADD INCR works with a single score-elemenet pair" { 111 r del ztmp 112 r zadd ztmp 10 x 20 y 30 z 113 catch {r zadd ztmp INCR 15 x 10 y} err 114 set err 115 } {ERR*} 116 117 test "ZADD CH option changes return value to all changed elements" { 118 r del ztmp 119 r zadd ztmp 10 x 20 y 30 z 120 assert {[r zadd ztmp 11 x 21 y 30 z] == 0} 121 assert {[r zadd ztmp ch 12 x 22 y 30 z] == 2} 122 } 123 124 test "ZINCRBY calls leading to NaN result in error" { 125 r zincrby myzset +inf abc 126 assert_error "*NaN*" {r zincrby myzset -inf abc} 127 } 128 129 test {ZADD - Variadic version base case} { 130 r del myzset 131 list [r zadd myzset 10 a 20 b 30 c] [r zrange myzset 0 -1 withscores] 132 } {3 {a 10 b 20 c 30}} 133 134 test {ZADD - Return value is the number of actually added items} { 135 list [r zadd myzset 5 x 20 b 30 c] [r zrange myzset 0 -1 withscores] 136 } {1 {x 5 a 10 b 20 c 30}} 137 138 test {ZADD - Variadic version does not add nothing on single parsing err} { 139 r del myzset 140 catch {r zadd myzset 10 a 20 b 30.badscore c} e 141 assert_match {*ERR*not*float*} $e 142 r exists myzset 143 } {0} 144 145 test {ZADD - Variadic version will raise error on missing arg} { 146 r del myzset 147 catch {r zadd myzset 10 a 20 b 30 c 40} e 148 assert_match {*ERR*syntax*} $e 149 } 150 151 test {ZINCRBY does not work variadic even if shares ZADD implementation} { 152 r del myzset 153 catch {r zincrby myzset 10 a 20 b 30 c} e 154 assert_match {*ERR*wrong*number*arg*} $e 155 } 156 157 test "ZCARD basics - $encoding" { 158 r del ztmp 159 r zadd ztmp 10 a 20 b 30 c 160 assert_equal 3 [r zcard ztmp] 161 assert_equal 0 [r zcard zdoesntexist] 162 } 163 164 test "ZREM removes key after last element is removed" { 165 r del ztmp 166 r zadd ztmp 10 x 167 r zadd ztmp 20 y 168 169 assert_equal 1 [r exists ztmp] 170 assert_equal 0 [r zrem ztmp z] 171 assert_equal 1 [r zrem ztmp y] 172 assert_equal 1 [r zrem ztmp x] 173 assert_equal 0 [r exists ztmp] 174 } 175 176 test "ZREM variadic version" { 177 r del ztmp 178 r zadd ztmp 10 a 20 b 30 c 179 assert_equal 2 [r zrem ztmp x y a b k] 180 assert_equal 0 [r zrem ztmp foo bar] 181 assert_equal 1 [r zrem ztmp c] 182 r exists ztmp 183 } {0} 184 185 test "ZREM variadic version -- remove elements after key deletion" { 186 r del ztmp 187 r zadd ztmp 10 a 20 b 30 c 188 r zrem ztmp a b c d e f g 189 } {3} 190 191 test "ZRANGE basics - $encoding" { 192 r del ztmp 193 r zadd ztmp 1 a 194 r zadd ztmp 2 b 195 r zadd ztmp 3 c 196 r zadd ztmp 4 d 197 198 assert_equal {a b c d} [r zrange ztmp 0 -1] 199 assert_equal {a b c} [r zrange ztmp 0 -2] 200 assert_equal {b c d} [r zrange ztmp 1 -1] 201 assert_equal {b c} [r zrange ztmp 1 -2] 202 assert_equal {c d} [r zrange ztmp -2 -1] 203 assert_equal {c} [r zrange ztmp -2 -2] 204 205 # out of range start index 206 assert_equal {a b c} [r zrange ztmp -5 2] 207 assert_equal {a b} [r zrange ztmp -5 1] 208 assert_equal {} [r zrange ztmp 5 -1] 209 assert_equal {} [r zrange ztmp 5 -2] 210 211 # out of range end index 212 assert_equal {a b c d} [r zrange ztmp 0 5] 213 assert_equal {b c d} [r zrange ztmp 1 5] 214 assert_equal {} [r zrange ztmp 0 -5] 215 assert_equal {} [r zrange ztmp 1 -5] 216 217 # withscores 218 assert_equal {a 1 b 2 c 3 d 4} [r zrange ztmp 0 -1 withscores] 219 } 220 221 test "ZREVRANGE basics - $encoding" { 222 r del ztmp 223 r zadd ztmp 1 a 224 r zadd ztmp 2 b 225 r zadd ztmp 3 c 226 r zadd ztmp 4 d 227 228 assert_equal {d c b a} [r zrevrange ztmp 0 -1] 229 assert_equal {d c b} [r zrevrange ztmp 0 -2] 230 assert_equal {c b a} [r zrevrange ztmp 1 -1] 231 assert_equal {c b} [r zrevrange ztmp 1 -2] 232 assert_equal {b a} [r zrevrange ztmp -2 -1] 233 assert_equal {b} [r zrevrange ztmp -2 -2] 234 235 # out of range start index 236 assert_equal {d c b} [r zrevrange ztmp -5 2] 237 assert_equal {d c} [r zrevrange ztmp -5 1] 238 assert_equal {} [r zrevrange ztmp 5 -1] 239 assert_equal {} [r zrevrange ztmp 5 -2] 240 241 # out of range end index 242 assert_equal {d c b a} [r zrevrange ztmp 0 5] 243 assert_equal {c b a} [r zrevrange ztmp 1 5] 244 assert_equal {} [r zrevrange ztmp 0 -5] 245 assert_equal {} [r zrevrange ztmp 1 -5] 246 247 # withscores 248 assert_equal {d 4 c 3 b 2 a 1} [r zrevrange ztmp 0 -1 withscores] 249 } 250 251 test "ZRANK/ZREVRANK basics - $encoding" { 252 r del zranktmp 253 r zadd zranktmp 10 x 254 r zadd zranktmp 20 y 255 r zadd zranktmp 30 z 256 assert_equal 0 [r zrank zranktmp x] 257 assert_equal 1 [r zrank zranktmp y] 258 assert_equal 2 [r zrank zranktmp z] 259 assert_equal "" [r zrank zranktmp foo] 260 assert_equal 2 [r zrevrank zranktmp x] 261 assert_equal 1 [r zrevrank zranktmp y] 262 assert_equal 0 [r zrevrank zranktmp z] 263 assert_equal "" [r zrevrank zranktmp foo] 264 } 265 266 test "ZRANK - after deletion - $encoding" { 267 r zrem zranktmp y 268 assert_equal 0 [r zrank zranktmp x] 269 assert_equal 1 [r zrank zranktmp z] 270 } 271 272 test "ZINCRBY - can create a new sorted set - $encoding" { 273 r del zset 274 r zincrby zset 1 foo 275 assert_equal {foo} [r zrange zset 0 -1] 276 assert_equal 1 [r zscore zset foo] 277 } 278 279 test "ZINCRBY - increment and decrement - $encoding" { 280 r zincrby zset 2 foo 281 r zincrby zset 1 bar 282 assert_equal {bar foo} [r zrange zset 0 -1] 283 284 r zincrby zset 10 bar 285 r zincrby zset -5 foo 286 r zincrby zset -5 bar 287 assert_equal {foo bar} [r zrange zset 0 -1] 288 289 assert_equal -2 [r zscore zset foo] 290 assert_equal 6 [r zscore zset bar] 291 } 292 293 test "ZINCRBY return value" { 294 r del ztmp 295 set retval [r zincrby ztmp 1.0 x] 296 assert {$retval == 1.0} 297 } 298 299 proc create_default_zset {} { 300 create_zset zset {-inf a 1 b 2 c 3 d 4 e 5 f +inf g} 301 } 302 303 test "ZRANGEBYSCORE/ZREVRANGEBYSCORE/ZCOUNT basics" { 304 create_default_zset 305 306 # inclusive range 307 assert_equal {a b c} [r zrangebyscore zset -inf 2] 308 assert_equal {b c d} [r zrangebyscore zset 0 3] 309 assert_equal {d e f} [r zrangebyscore zset 3 6] 310 assert_equal {e f g} [r zrangebyscore zset 4 +inf] 311 assert_equal {c b a} [r zrevrangebyscore zset 2 -inf] 312 assert_equal {d c b} [r zrevrangebyscore zset 3 0] 313 assert_equal {f e d} [r zrevrangebyscore zset 6 3] 314 assert_equal {g f e} [r zrevrangebyscore zset +inf 4] 315 assert_equal 3 [r zcount zset 0 3] 316 317 # exclusive range 318 assert_equal {b} [r zrangebyscore zset (-inf (2] 319 assert_equal {b c} [r zrangebyscore zset (0 (3] 320 assert_equal {e f} [r zrangebyscore zset (3 (6] 321 assert_equal {f} [r zrangebyscore zset (4 (+inf] 322 assert_equal {b} [r zrevrangebyscore zset (2 (-inf] 323 assert_equal {c b} [r zrevrangebyscore zset (3 (0] 324 assert_equal {f e} [r zrevrangebyscore zset (6 (3] 325 assert_equal {f} [r zrevrangebyscore zset (+inf (4] 326 assert_equal 2 [r zcount zset (0 (3] 327 328 # test empty ranges 329 r zrem zset a 330 r zrem zset g 331 332 # inclusive 333 assert_equal {} [r zrangebyscore zset 4 2] 334 assert_equal {} [r zrangebyscore zset 6 +inf] 335 assert_equal {} [r zrangebyscore zset -inf -6] 336 assert_equal {} [r zrevrangebyscore zset +inf 6] 337 assert_equal {} [r zrevrangebyscore zset -6 -inf] 338 339 # exclusive 340 assert_equal {} [r zrangebyscore zset (4 (2] 341 assert_equal {} [r zrangebyscore zset 2 (2] 342 assert_equal {} [r zrangebyscore zset (2 2] 343 assert_equal {} [r zrangebyscore zset (6 (+inf] 344 assert_equal {} [r zrangebyscore zset (-inf (-6] 345 assert_equal {} [r zrevrangebyscore zset (+inf (6] 346 assert_equal {} [r zrevrangebyscore zset (-6 (-inf] 347 348 # empty inner range 349 assert_equal {} [r zrangebyscore zset 2.4 2.6] 350 assert_equal {} [r zrangebyscore zset (2.4 2.6] 351 assert_equal {} [r zrangebyscore zset 2.4 (2.6] 352 assert_equal {} [r zrangebyscore zset (2.4 (2.6] 353 } 354 355 test "ZRANGEBYSCORE with WITHSCORES" { 356 create_default_zset 357 assert_equal {b 1 c 2 d 3} [r zrangebyscore zset 0 3 withscores] 358 assert_equal {d 3 c 2 b 1} [r zrevrangebyscore zset 3 0 withscores] 359 } 360 361 test "ZRANGEBYSCORE with LIMIT" { 362 create_default_zset 363 assert_equal {b c} [r zrangebyscore zset 0 10 LIMIT 0 2] 364 assert_equal {d e f} [r zrangebyscore zset 0 10 LIMIT 2 3] 365 assert_equal {d e f} [r zrangebyscore zset 0 10 LIMIT 2 10] 366 assert_equal {} [r zrangebyscore zset 0 10 LIMIT 20 10] 367 assert_equal {f e} [r zrevrangebyscore zset 10 0 LIMIT 0 2] 368 assert_equal {d c b} [r zrevrangebyscore zset 10 0 LIMIT 2 3] 369 assert_equal {d c b} [r zrevrangebyscore zset 10 0 LIMIT 2 10] 370 assert_equal {} [r zrevrangebyscore zset 10 0 LIMIT 20 10] 371 } 372 373 test "ZRANGEBYSCORE with LIMIT and WITHSCORES" { 374 create_default_zset 375 assert_equal {e 4 f 5} [r zrangebyscore zset 2 5 LIMIT 2 3 WITHSCORES] 376 assert_equal {d 3 c 2} [r zrevrangebyscore zset 5 2 LIMIT 2 3 WITHSCORES] 377 } 378 379 test "ZRANGEBYSCORE with non-value min or max" { 380 assert_error "*not*float*" {r zrangebyscore fooz str 1} 381 assert_error "*not*float*" {r zrangebyscore fooz 1 str} 382 assert_error "*not*float*" {r zrangebyscore fooz 1 NaN} 383 } 384 385 proc create_default_lex_zset {} { 386 create_zset zset {0 alpha 0 bar 0 cool 0 down 387 0 elephant 0 foo 0 great 0 hill 388 0 omega} 389 } 390 391 test "ZRANGEBYLEX/ZREVRANGEBYLEX/ZLEXCOUNT basics" { 392 create_default_lex_zset 393 394 # inclusive range 395 assert_equal {alpha bar cool} [r zrangebylex zset - \[cool] 396 assert_equal {bar cool down} [r zrangebylex zset \[bar \[down] 397 assert_equal {great hill omega} [r zrangebylex zset \[g +] 398 assert_equal {cool bar alpha} [r zrevrangebylex zset \[cool -] 399 assert_equal {down cool bar} [r zrevrangebylex zset \[down \[bar] 400 assert_equal {omega hill great foo elephant down} [r zrevrangebylex zset + \[d] 401 assert_equal 3 [r zlexcount zset \[ele \[h] 402 403 # exclusive range 404 assert_equal {alpha bar} [r zrangebylex zset - (cool] 405 assert_equal {cool} [r zrangebylex zset (bar (down] 406 assert_equal {hill omega} [r zrangebylex zset (great +] 407 assert_equal {bar alpha} [r zrevrangebylex zset (cool -] 408 assert_equal {cool} [r zrevrangebylex zset (down (bar] 409 assert_equal {omega hill} [r zrevrangebylex zset + (great] 410 assert_equal 2 [r zlexcount zset (ele (great] 411 412 # inclusive and exclusive 413 assert_equal {} [r zrangebylex zset (az (b] 414 assert_equal {} [r zrangebylex zset (z +] 415 assert_equal {} [r zrangebylex zset - \[aaaa] 416 assert_equal {} [r zrevrangebylex zset \[elez \[elex] 417 assert_equal {} [r zrevrangebylex zset (hill (omega] 418 } 419 420 test "ZLEXCOUNT advanced" { 421 create_default_lex_zset 422 423 assert_equal 9 [r zlexcount zset - +] 424 assert_equal 0 [r zlexcount zset + -] 425 assert_equal 0 [r zlexcount zset + \[c] 426 assert_equal 0 [r zlexcount zset \[c -] 427 assert_equal 8 [r zlexcount zset \[bar +] 428 assert_equal 5 [r zlexcount zset \[bar \[foo] 429 assert_equal 4 [r zlexcount zset \[bar (foo] 430 assert_equal 4 [r zlexcount zset (bar \[foo] 431 assert_equal 3 [r zlexcount zset (bar (foo] 432 assert_equal 5 [r zlexcount zset - (foo] 433 assert_equal 1 [r zlexcount zset (maxstring +] 434 } 435 436 test "ZRANGEBYSLEX with LIMIT" { 437 create_default_lex_zset 438 assert_equal {alpha bar} [r zrangebylex zset - \[cool LIMIT 0 2] 439 assert_equal {bar cool} [r zrangebylex zset - \[cool LIMIT 1 2] 440 assert_equal {} [r zrangebylex zset \[bar \[down LIMIT 0 0] 441 assert_equal {} [r zrangebylex zset \[bar \[down LIMIT 2 0] 442 assert_equal {bar} [r zrangebylex zset \[bar \[down LIMIT 0 1] 443 assert_equal {cool} [r zrangebylex zset \[bar \[down LIMIT 1 1] 444 assert_equal {bar cool down} [r zrangebylex zset \[bar \[down LIMIT 0 100] 445 assert_equal {omega hill great foo elephant} [r zrevrangebylex zset + \[d LIMIT 0 5] 446 assert_equal {omega hill great foo} [r zrevrangebylex zset + \[d LIMIT 0 4] 447 } 448 449 test "ZRANGEBYLEX with invalid lex range specifiers" { 450 assert_error "*not*string*" {r zrangebylex fooz foo bar} 451 assert_error "*not*string*" {r zrangebylex fooz \[foo bar} 452 assert_error "*not*string*" {r zrangebylex fooz foo \[bar} 453 assert_error "*not*string*" {r zrangebylex fooz +x \[bar} 454 assert_error "*not*string*" {r zrangebylex fooz -x \[bar} 455 } 456 457 test "ZREMRANGEBYSCORE basics" { 458 proc remrangebyscore {min max} { 459 create_zset zset {1 a 2 b 3 c 4 d 5 e} 460 assert_equal 1 [r exists zset] 461 r zremrangebyscore zset $min $max 462 } 463 464 # inner range 465 assert_equal 3 [remrangebyscore 2 4] 466 assert_equal {a e} [r zrange zset 0 -1] 467 468 # start underflow 469 assert_equal 1 [remrangebyscore -10 1] 470 assert_equal {b c d e} [r zrange zset 0 -1] 471 472 # end overflow 473 assert_equal 1 [remrangebyscore 5 10] 474 assert_equal {a b c d} [r zrange zset 0 -1] 475 476 # switch min and max 477 assert_equal 0 [remrangebyscore 4 2] 478 assert_equal {a b c d e} [r zrange zset 0 -1] 479 480 # -inf to mid 481 assert_equal 3 [remrangebyscore -inf 3] 482 assert_equal {d e} [r zrange zset 0 -1] 483 484 # mid to +inf 485 assert_equal 3 [remrangebyscore 3 +inf] 486 assert_equal {a b} [r zrange zset 0 -1] 487 488 # -inf to +inf 489 assert_equal 5 [remrangebyscore -inf +inf] 490 assert_equal {} [r zrange zset 0 -1] 491 492 # exclusive min 493 assert_equal 4 [remrangebyscore (1 5] 494 assert_equal {a} [r zrange zset 0 -1] 495 assert_equal 3 [remrangebyscore (2 5] 496 assert_equal {a b} [r zrange zset 0 -1] 497 498 # exclusive max 499 assert_equal 4 [remrangebyscore 1 (5] 500 assert_equal {e} [r zrange zset 0 -1] 501 assert_equal 3 [remrangebyscore 1 (4] 502 assert_equal {d e} [r zrange zset 0 -1] 503 504 # exclusive min and max 505 assert_equal 3 [remrangebyscore (1 (5] 506 assert_equal {a e} [r zrange zset 0 -1] 507 508 # destroy when empty 509 assert_equal 5 [remrangebyscore 1 5] 510 assert_equal 0 [r exists zset] 511 } 512 513 test "ZREMRANGEBYSCORE with non-value min or max" { 514 assert_error "*not*float*" {r zremrangebyscore fooz str 1} 515 assert_error "*not*float*" {r zremrangebyscore fooz 1 str} 516 assert_error "*not*float*" {r zremrangebyscore fooz 1 NaN} 517 } 518 519 test "ZREMRANGEBYRANK basics" { 520 proc remrangebyrank {min max} { 521 create_zset zset {1 a 2 b 3 c 4 d 5 e} 522 assert_equal 1 [r exists zset] 523 r zremrangebyrank zset $min $max 524 } 525 526 # inner range 527 assert_equal 3 [remrangebyrank 1 3] 528 assert_equal {a e} [r zrange zset 0 -1] 529 530 # start underflow 531 assert_equal 1 [remrangebyrank -10 0] 532 assert_equal {b c d e} [r zrange zset 0 -1] 533 534 # start overflow 535 assert_equal 0 [remrangebyrank 10 -1] 536 assert_equal {a b c d e} [r zrange zset 0 -1] 537 538 # end underflow 539 assert_equal 0 [remrangebyrank 0 -10] 540 assert_equal {a b c d e} [r zrange zset 0 -1] 541 542 # end overflow 543 assert_equal 5 [remrangebyrank 0 10] 544 assert_equal {} [r zrange zset 0 -1] 545 546 # destroy when empty 547 assert_equal 5 [remrangebyrank 0 4] 548 assert_equal 0 [r exists zset] 549 } 550 551 test "ZUNIONSTORE against non-existing key doesn't set destination - $encoding" { 552 r del zseta 553 assert_equal 0 [r zunionstore dst_key 1 zseta] 554 assert_equal 0 [r exists dst_key] 555 } 556 557 test "ZUNIONSTORE with empty set - $encoding" { 558 r del zseta zsetb 559 r zadd zseta 1 a 560 r zadd zseta 2 b 561 r zunionstore zsetc 2 zseta zsetb 562 r zrange zsetc 0 -1 withscores 563 } {a 1 b 2} 564 565 test "ZUNIONSTORE basics - $encoding" { 566 r del zseta zsetb zsetc 567 r zadd zseta 1 a 568 r zadd zseta 2 b 569 r zadd zseta 3 c 570 r zadd zsetb 1 b 571 r zadd zsetb 2 c 572 r zadd zsetb 3 d 573 574 assert_equal 4 [r zunionstore zsetc 2 zseta zsetb] 575 assert_equal {a 1 b 3 d 3 c 5} [r zrange zsetc 0 -1 withscores] 576 } 577 578 test "ZUNIONSTORE with weights - $encoding" { 579 assert_equal 4 [r zunionstore zsetc 2 zseta zsetb weights 2 3] 580 assert_equal {a 2 b 7 d 9 c 12} [r zrange zsetc 0 -1 withscores] 581 } 582 583 test "ZUNIONSTORE with a regular set and weights - $encoding" { 584 r del seta 585 r sadd seta a 586 r sadd seta b 587 r sadd seta c 588 589 assert_equal 4 [r zunionstore zsetc 2 seta zsetb weights 2 3] 590 assert_equal {a 2 b 5 c 8 d 9} [r zrange zsetc 0 -1 withscores] 591 } 592 593 test "ZUNIONSTORE with AGGREGATE MIN - $encoding" { 594 assert_equal 4 [r zunionstore zsetc 2 zseta zsetb aggregate min] 595 assert_equal {a 1 b 1 c 2 d 3} [r zrange zsetc 0 -1 withscores] 596 } 597 598 test "ZUNIONSTORE with AGGREGATE MAX - $encoding" { 599 assert_equal 4 [r zunionstore zsetc 2 zseta zsetb aggregate max] 600 assert_equal {a 1 b 2 c 3 d 3} [r zrange zsetc 0 -1 withscores] 601 } 602 603 test "ZINTERSTORE basics - $encoding" { 604 assert_equal 2 [r zinterstore zsetc 2 zseta zsetb] 605 assert_equal {b 3 c 5} [r zrange zsetc 0 -1 withscores] 606 } 607 608 test "ZINTERSTORE with weights - $encoding" { 609 assert_equal 2 [r zinterstore zsetc 2 zseta zsetb weights 2 3] 610 assert_equal {b 7 c 12} [r zrange zsetc 0 -1 withscores] 611 } 612 613 test "ZINTERSTORE with a regular set and weights - $encoding" { 614 r del seta 615 r sadd seta a 616 r sadd seta b 617 r sadd seta c 618 assert_equal 2 [r zinterstore zsetc 2 seta zsetb weights 2 3] 619 assert_equal {b 5 c 8} [r zrange zsetc 0 -1 withscores] 620 } 621 622 test "ZINTERSTORE with AGGREGATE MIN - $encoding" { 623 assert_equal 2 [r zinterstore zsetc 2 zseta zsetb aggregate min] 624 assert_equal {b 1 c 2} [r zrange zsetc 0 -1 withscores] 625 } 626 627 test "ZINTERSTORE with AGGREGATE MAX - $encoding" { 628 assert_equal 2 [r zinterstore zsetc 2 zseta zsetb aggregate max] 629 assert_equal {b 2 c 3} [r zrange zsetc 0 -1 withscores] 630 } 631 632 foreach cmd {ZUNIONSTORE ZINTERSTORE} { 633 test "$cmd with +inf/-inf scores - $encoding" { 634 r del zsetinf1 zsetinf2 635 636 r zadd zsetinf1 +inf key 637 r zadd zsetinf2 +inf key 638 r $cmd zsetinf3 2 zsetinf1 zsetinf2 639 assert_equal inf [r zscore zsetinf3 key] 640 641 r zadd zsetinf1 -inf key 642 r zadd zsetinf2 +inf key 643 r $cmd zsetinf3 2 zsetinf1 zsetinf2 644 assert_equal 0 [r zscore zsetinf3 key] 645 646 r zadd zsetinf1 +inf key 647 r zadd zsetinf2 -inf key 648 r $cmd zsetinf3 2 zsetinf1 zsetinf2 649 assert_equal 0 [r zscore zsetinf3 key] 650 651 r zadd zsetinf1 -inf key 652 r zadd zsetinf2 -inf key 653 r $cmd zsetinf3 2 zsetinf1 zsetinf2 654 assert_equal -inf [r zscore zsetinf3 key] 655 } 656 657 test "$cmd with NaN weights $encoding" { 658 r del zsetinf1 zsetinf2 659 660 r zadd zsetinf1 1.0 key 661 r zadd zsetinf2 1.0 key 662 assert_error "*weight*not*float*" { 663 r $cmd zsetinf3 2 zsetinf1 zsetinf2 weights nan nan 664 } 665 } 666 } 667 668 test "Basic ZPOP with a single key - $encoding" { 669 r del zset 670 assert_equal {} [r zpopmin zset] 671 create_zset zset {-1 a 1 b 2 c 3 d 4 e} 672 assert_equal {a -1} [r zpopmin zset] 673 assert_equal {b 1} [r zpopmin zset] 674 assert_equal {e 4} [r zpopmax zset] 675 assert_equal {d 3} [r zpopmax zset] 676 assert_equal {c 2} [r zpopmin zset] 677 assert_equal 0 [r exists zset] 678 r set foo bar 679 assert_error "*WRONGTYPE*" {r zpopmin foo} 680 } 681 682 test "ZPOP with count - $encoding" { 683 r del z1 z2 z3 foo 684 r set foo bar 685 assert_equal {} [r zpopmin z1 2] 686 assert_error "*WRONGTYPE*" {r zpopmin foo 2} 687 create_zset z1 {0 a 1 b 2 c 3 d} 688 assert_equal {a 0 b 1} [r zpopmin z1 2] 689 assert_equal {d 3 c 2} [r zpopmax z1 2] 690 } 691 692 test "BZPOP with a single existing sorted set - $encoding" { 693 set rd [redis_deferring_client] 694 create_zset zset {0 a 1 b 2 c} 695 696 $rd bzpopmin zset 5 697 assert_equal {zset a 0} [$rd read] 698 $rd bzpopmin zset 5 699 assert_equal {zset b 1} [$rd read] 700 $rd bzpopmax zset 5 701 assert_equal {zset c 2} [$rd read] 702 assert_equal 0 [r exists zset] 703 } 704 705 test "BZPOP with multiple existing sorted sets - $encoding" { 706 set rd [redis_deferring_client] 707 create_zset z1 {0 a 1 b 2 c} 708 create_zset z2 {3 d 4 e 5 f} 709 710 $rd bzpopmin z1 z2 5 711 assert_equal {z1 a 0} [$rd read] 712 $rd bzpopmax z1 z2 5 713 assert_equal {z1 c 2} [$rd read] 714 assert_equal 1 [r zcard z1] 715 assert_equal 3 [r zcard z2] 716 717 $rd bzpopmax z2 z1 5 718 assert_equal {z2 f 5} [$rd read] 719 $rd bzpopmin z2 z1 5 720 assert_equal {z2 d 3} [$rd read] 721 assert_equal 1 [r zcard z1] 722 assert_equal 1 [r zcard z2] 723 } 724 725 test "BZPOP second sorted set has members - $encoding" { 726 set rd [redis_deferring_client] 727 r del z1 728 create_zset z2 {3 d 4 e 5 f} 729 $rd bzpopmax z1 z2 5 730 assert_equal {z2 f 5} [$rd read] 731 $rd bzpopmin z2 z1 5 732 assert_equal {z2 d 3} [$rd read] 733 assert_equal 0 [r zcard z1] 734 assert_equal 1 [r zcard z2] 735 } 736 } 737 738 basics ziplist 739 basics skiplist 740 741 test {ZINTERSTORE regression with two sets, intset+hashtable} { 742 r del seta setb setc 743 r sadd set1 a 744 r sadd set2 10 745 r zinterstore set3 2 set1 set2 746 } {0} 747 748 test {ZUNIONSTORE regression, should not create NaN in scores} { 749 r zadd z -inf neginf 750 r zunionstore out 1 z weights 0 751 r zrange out 0 -1 withscores 752 } {neginf 0} 753 754 test {ZINTERSTORE #516 regression, mixed sets and ziplist zsets} { 755 r sadd one 100 101 102 103 756 r sadd two 100 200 201 202 757 r zadd three 1 500 1 501 1 502 1 503 1 100 758 r zinterstore to_here 3 one two three WEIGHTS 0 0 1 759 r zrange to_here 0 -1 760 } {100} 761 762 test {ZUNIONSTORE result is sorted} { 763 # Create two sets with common and not common elements, perform 764 # the UNION, check that elements are still sorted. 765 r del one two dest 766 set cmd1 [list r zadd one] 767 set cmd2 [list r zadd two] 768 for {set j 0} {$j < 1000} {incr j} { 769 lappend cmd1 [expr rand()] [randomInt 1000] 770 lappend cmd2 [expr rand()] [randomInt 1000] 771 } 772 {*}$cmd1 773 {*}$cmd2 774 assert {[r zcard one] > 100} 775 assert {[r zcard two] > 100} 776 r zunionstore dest 2 one two 777 set oldscore 0 778 foreach {ele score} [r zrange dest 0 -1 withscores] { 779 assert {$score >= $oldscore} 780 set oldscore $score 781 } 782 } 783 784 test "ZSET commands don't accept the empty strings as valid score" { 785 assert_error "*not*float*" {r zadd myzset "" abc} 786 } 787 788 proc stressers {encoding} { 789 if {$encoding == "ziplist"} { 790 # Little extra to allow proper fuzzing in the sorting stresser 791 r config set zset-max-ziplist-entries 256 792 r config set zset-max-ziplist-value 64 793 set elements 128 794 } elseif {$encoding == "skiplist"} { 795 r config set zset-max-ziplist-entries 0 796 r config set zset-max-ziplist-value 0 797 if {$::accurate} {set elements 1000} else {set elements 100} 798 } else { 799 puts "Unknown sorted set encoding" 800 exit 801 } 802 803 test "ZSCORE - $encoding" { 804 r del zscoretest 805 set aux {} 806 for {set i 0} {$i < $elements} {incr i} { 807 set score [expr rand()] 808 lappend aux $score 809 r zadd zscoretest $score $i 810 } 811 812 assert_encoding $encoding zscoretest 813 for {set i 0} {$i < $elements} {incr i} { 814 assert_equal [lindex $aux $i] [r zscore zscoretest $i] 815 } 816 } 817 818 test "ZSCORE after a DEBUG RELOAD - $encoding" { 819 r del zscoretest 820 set aux {} 821 for {set i 0} {$i < $elements} {incr i} { 822 set score [expr rand()] 823 lappend aux $score 824 r zadd zscoretest $score $i 825 } 826 827 r debug reload 828 assert_encoding $encoding zscoretest 829 for {set i 0} {$i < $elements} {incr i} { 830 assert_equal [lindex $aux $i] [r zscore zscoretest $i] 831 } 832 } 833 834 test "ZSET sorting stresser - $encoding" { 835 set delta 0 836 for {set test 0} {$test < 2} {incr test} { 837 unset -nocomplain auxarray 838 array set auxarray {} 839 set auxlist {} 840 r del myzset 841 for {set i 0} {$i < $elements} {incr i} { 842 if {$test == 0} { 843 set score [expr rand()] 844 } else { 845 set score [expr int(rand()*10)] 846 } 847 set auxarray($i) $score 848 r zadd myzset $score $i 849 # Random update 850 if {[expr rand()] < .2} { 851 set j [expr int(rand()*1000)] 852 if {$test == 0} { 853 set score [expr rand()] 854 } else { 855 set score [expr int(rand()*10)] 856 } 857 set auxarray($j) $score 858 r zadd myzset $score $j 859 } 860 } 861 foreach {item score} [array get auxarray] { 862 lappend auxlist [list $score $item] 863 } 864 set sorted [lsort -command zlistAlikeSort $auxlist] 865 set auxlist {} 866 foreach x $sorted { 867 lappend auxlist [lindex $x 1] 868 } 869 870 assert_encoding $encoding myzset 871 set fromredis [r zrange myzset 0 -1] 872 set delta 0 873 for {set i 0} {$i < [llength $fromredis]} {incr i} { 874 if {[lindex $fromredis $i] != [lindex $auxlist $i]} { 875 incr delta 876 } 877 } 878 } 879 assert_equal 0 $delta 880 } 881 882 test "ZRANGEBYSCORE fuzzy test, 100 ranges in $elements element sorted set - $encoding" { 883 set err {} 884 r del zset 885 for {set i 0} {$i < $elements} {incr i} { 886 r zadd zset [expr rand()] $i 887 } 888 889 assert_encoding $encoding zset 890 for {set i 0} {$i < 100} {incr i} { 891 set min [expr rand()] 892 set max [expr rand()] 893 if {$min > $max} { 894 set aux $min 895 set min $max 896 set max $aux 897 } 898 set low [r zrangebyscore zset -inf $min] 899 set ok [r zrangebyscore zset $min $max] 900 set high [r zrangebyscore zset $max +inf] 901 set lowx [r zrangebyscore zset -inf ($min] 902 set okx [r zrangebyscore zset ($min ($max] 903 set highx [r zrangebyscore zset ($max +inf] 904 905 if {[r zcount zset -inf $min] != [llength $low]} { 906 append err "Error, len does not match zcount\n" 907 } 908 if {[r zcount zset $min $max] != [llength $ok]} { 909 append err "Error, len does not match zcount\n" 910 } 911 if {[r zcount zset $max +inf] != [llength $high]} { 912 append err "Error, len does not match zcount\n" 913 } 914 if {[r zcount zset -inf ($min] != [llength $lowx]} { 915 append err "Error, len does not match zcount\n" 916 } 917 if {[r zcount zset ($min ($max] != [llength $okx]} { 918 append err "Error, len does not match zcount\n" 919 } 920 if {[r zcount zset ($max +inf] != [llength $highx]} { 921 append err "Error, len does not match zcount\n" 922 } 923 924 foreach x $low { 925 set score [r zscore zset $x] 926 if {$score > $min} { 927 append err "Error, score for $x is $score > $min\n" 928 } 929 } 930 foreach x $lowx { 931 set score [r zscore zset $x] 932 if {$score >= $min} { 933 append err "Error, score for $x is $score >= $min\n" 934 } 935 } 936 foreach x $ok { 937 set score [r zscore zset $x] 938 if {$score < $min || $score > $max} { 939 append err "Error, score for $x is $score outside $min-$max range\n" 940 } 941 } 942 foreach x $okx { 943 set score [r zscore zset $x] 944 if {$score <= $min || $score >= $max} { 945 append err "Error, score for $x is $score outside $min-$max open range\n" 946 } 947 } 948 foreach x $high { 949 set score [r zscore zset $x] 950 if {$score < $max} { 951 append err "Error, score for $x is $score < $max\n" 952 } 953 } 954 foreach x $highx { 955 set score [r zscore zset $x] 956 if {$score <= $max} { 957 append err "Error, score for $x is $score <= $max\n" 958 } 959 } 960 } 961 assert_equal {} $err 962 } 963 964 test "ZRANGEBYLEX fuzzy test, 100 ranges in $elements element sorted set - $encoding" { 965 set lexset {} 966 r del zset 967 for {set j 0} {$j < $elements} {incr j} { 968 set e [randstring 0 30 alpha] 969 lappend lexset $e 970 r zadd zset 0 $e 971 } 972 set lexset [lsort -unique $lexset] 973 for {set j 0} {$j < 100} {incr j} { 974 set min [randstring 0 30 alpha] 975 set max [randstring 0 30 alpha] 976 set mininc [randomInt 2] 977 set maxinc [randomInt 2] 978 if {$mininc} {set cmin "\[$min"} else {set cmin "($min"} 979 if {$maxinc} {set cmax "\[$max"} else {set cmax "($max"} 980 set rev [randomInt 2] 981 if {$rev} { 982 set cmd zrevrangebylex 983 } else { 984 set cmd zrangebylex 985 } 986 987 # Make sure data is the same in both sides 988 assert {[r zrange zset 0 -1] eq $lexset} 989 990 # Get the Redis output 991 set output [r $cmd zset $cmin $cmax] 992 if {$rev} { 993 set outlen [r zlexcount zset $cmax $cmin] 994 } else { 995 set outlen [r zlexcount zset $cmin $cmax] 996 } 997 998 # Compute the same output via Tcl 999 set o {} 1000 set copy $lexset 1001 if {(!$rev && [string compare $min $max] > 0) || 1002 ($rev && [string compare $max $min] > 0)} { 1003 # Empty output when ranges are inverted. 1004 } else { 1005 if {$rev} { 1006 # Invert the Tcl array using Redis itself. 1007 set copy [r zrevrange zset 0 -1] 1008 # Invert min / max as well 1009 lassign [list $min $max $mininc $maxinc] \ 1010 max min maxinc mininc 1011 } 1012 foreach e $copy { 1013 set mincmp [string compare $e $min] 1014 set maxcmp [string compare $e $max] 1015 if { 1016 ($mininc && $mincmp >= 0 || !$mininc && $mincmp > 0) 1017 && 1018 ($maxinc && $maxcmp <= 0 || !$maxinc && $maxcmp < 0) 1019 } { 1020 lappend o $e 1021 } 1022 } 1023 } 1024 assert {$o eq $output} 1025 assert {$outlen eq [llength $output]} 1026 } 1027 } 1028 1029 test "ZREMRANGEBYLEX fuzzy test, 100 ranges in $elements element sorted set - $encoding" { 1030 set lexset {} 1031 r del zset zsetcopy 1032 for {set j 0} {$j < $elements} {incr j} { 1033 set e [randstring 0 30 alpha] 1034 lappend lexset $e 1035 r zadd zset 0 $e 1036 } 1037 set lexset [lsort -unique $lexset] 1038 for {set j 0} {$j < 100} {incr j} { 1039 # Copy... 1040 r zunionstore zsetcopy 1 zset 1041 set lexsetcopy $lexset 1042 1043 set min [randstring 0 30 alpha] 1044 set max [randstring 0 30 alpha] 1045 set mininc [randomInt 2] 1046 set maxinc [randomInt 2] 1047 if {$mininc} {set cmin "\[$min"} else {set cmin "($min"} 1048 if {$maxinc} {set cmax "\[$max"} else {set cmax "($max"} 1049 1050 # Make sure data is the same in both sides 1051 assert {[r zrange zset 0 -1] eq $lexset} 1052 1053 # Get the range we are going to remove 1054 set torem [r zrangebylex zset $cmin $cmax] 1055 set toremlen [r zlexcount zset $cmin $cmax] 1056 r zremrangebylex zsetcopy $cmin $cmax 1057 set output [r zrange zsetcopy 0 -1] 1058 1059 # Remove the range with Tcl from the original list 1060 if {$toremlen} { 1061 set first [lsearch -exact $lexsetcopy [lindex $torem 0]] 1062 set last [expr {$first+$toremlen-1}] 1063 set lexsetcopy [lreplace $lexsetcopy $first $last] 1064 } 1065 assert {$lexsetcopy eq $output} 1066 } 1067 } 1068 1069 test "ZSETs skiplist implementation backlink consistency test - $encoding" { 1070 set diff 0 1071 for {set j 0} {$j < $elements} {incr j} { 1072 r zadd myzset [expr rand()] "Element-$j" 1073 r zrem myzset "Element-[expr int(rand()*$elements)]" 1074 } 1075 1076 assert_encoding $encoding myzset 1077 set l1 [r zrange myzset 0 -1] 1078 set l2 [r zrevrange myzset 0 -1] 1079 for {set j 0} {$j < [llength $l1]} {incr j} { 1080 if {[lindex $l1 $j] ne [lindex $l2 end-$j]} { 1081 incr diff 1082 } 1083 } 1084 assert_equal 0 $diff 1085 } 1086 1087 test "ZSETs ZRANK augmented skip list stress testing - $encoding" { 1088 set err {} 1089 r del myzset 1090 for {set k 0} {$k < 2000} {incr k} { 1091 set i [expr {$k % $elements}] 1092 if {[expr rand()] < .2} { 1093 r zrem myzset $i 1094 } else { 1095 set score [expr rand()] 1096 r zadd myzset $score $i 1097 assert_encoding $encoding myzset 1098 } 1099 1100 set card [r zcard myzset] 1101 if {$card > 0} { 1102 set index [randomInt $card] 1103 set ele [lindex [r zrange myzset $index $index] 0] 1104 set rank [r zrank myzset $ele] 1105 if {$rank != $index} { 1106 set err "$ele RANK is wrong! ($rank != $index)" 1107 break 1108 } 1109 } 1110 } 1111 assert_equal {} $err 1112 } 1113 1114 test "BZPOPMIN, ZADD + DEL should not awake blocked client" { 1115 set rd [redis_deferring_client] 1116 r del zset 1117 1118 $rd bzpopmin zset 0 1119 r multi 1120 r zadd zset 0 foo 1121 r del zset 1122 r exec 1123 r del zset 1124 r zadd zset 1 bar 1125 $rd read 1126 } {zset bar 1} 1127 1128 test "BZPOPMIN, ZADD + DEL + SET should not awake blocked client" { 1129 set rd [redis_deferring_client] 1130 r del list 1131 1132 r del zset 1133 1134 $rd bzpopmin zset 0 1135 r multi 1136 r zadd zset 0 foo 1137 r del zset 1138 r set zset foo 1139 r exec 1140 r del zset 1141 r zadd zset 1 bar 1142 $rd read 1143 } {zset bar 1} 1144 1145 test "BZPOPMIN with same key multiple times should work" { 1146 set rd [redis_deferring_client] 1147 r del z1 z2 1148 1149 # Data arriving after the BZPOPMIN. 1150 $rd bzpopmin z1 z2 z2 z1 0 1151 r zadd z1 0 a 1152 assert_equal [$rd read] {z1 a 0} 1153 $rd bzpopmin z1 z2 z2 z1 0 1154 r zadd z2 1 b 1155 assert_equal [$rd read] {z2 b 1} 1156 1157 # Data already there. 1158 r zadd z1 0 a 1159 r zadd z2 1 b 1160 $rd bzpopmin z1 z2 z2 z1 0 1161 assert_equal [$rd read] {z1 a 0} 1162 $rd bzpopmin z1 z2 z2 z1 0 1163 assert_equal [$rd read] {z2 b 1} 1164 } 1165 1166 test "MULTI/EXEC is isolated from the point of view of BZPOPMIN" { 1167 set rd [redis_deferring_client] 1168 r del zset 1169 $rd bzpopmin zset 0 1170 r multi 1171 r zadd zset 0 a 1172 r zadd zset 1 b 1173 r zadd zset 2 c 1174 r exec 1175 $rd read 1176 } {zset a 0} 1177 1178 test "BZPOPMIN with variadic ZADD" { 1179 set rd [redis_deferring_client] 1180 r del zset 1181 if {$::valgrind} {after 100} 1182 $rd bzpopmin zset 0 1183 if {$::valgrind} {after 100} 1184 assert_equal 2 [r zadd zset -1 foo 1 bar] 1185 if {$::valgrind} {after 100} 1186 assert_equal {zset foo -1} [$rd read] 1187 assert_equal {bar} [r zrange zset 0 -1] 1188 } 1189 1190 test "BZPOPMIN with zero timeout should block indefinitely" { 1191 set rd [redis_deferring_client] 1192 r del zset 1193 $rd bzpopmin zset 0 1194 after 1000 1195 r zadd zset 0 foo 1196 assert_equal {zset foo 0} [$rd read] 1197 } 1198 } 1199 1200 tags {"slow"} { 1201 stressers ziplist 1202 stressers skiplist 1203 } 1204 1205 test {ZSET skiplist order consistency when elements are moved} { 1206 set original_max [lindex [r config get zset-max-ziplist-entries] 1] 1207 r config set zset-max-ziplist-entries 0 1208 for {set times 0} {$times < 10} {incr times} { 1209 r del zset 1210 for {set j 0} {$j < 1000} {incr j} { 1211 r zadd zset [randomInt 50] ele-[randomInt 10] 1212 } 1213 1214 # Make sure that element ordering is correct 1215 set prev_element {} 1216 set prev_score -1 1217 foreach {element score} [r zrange zset 0 -1 WITHSCORES] { 1218 # Assert that elements are in increasing ordering 1219 assert { 1220 $prev_score < $score || 1221 ($prev_score == $score && 1222 [string compare $prev_element $element] == -1) 1223 } 1224 set prev_element $element 1225 set prev_score $score 1226 } 1227 } 1228 r config set zset-max-ziplist-entries $original_max 1229 } 1230} 1231