mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-23 16:48:27 -05:00
8a86bca5ed
This commit revives the improves the ability to run the test suite against external servers, instead of launching and managing `redis-server` processes as part of the test fixture. This capability existed in the past, using the `--host` and `--port` options. However, it was quite limited and mostly useful when running a specific tests. Attempting to run larger chunks of the test suite experienced many issues: * Many tests depend on being able to start and control `redis-server` themselves, and there's no clear distinction between external server compatible and other tests. * Cluster mode is not supported (resulting with `CROSSSLOT` errors). This PR cleans up many things and makes it possible to run the entire test suite against an external server. It also provides more fine grained controls to handle cases where the external server supports a subset of the Redis commands, limited number of databases, cluster mode, etc. The tests directory now contains a `README.md` file that describes how this works. This commit also includes additional cleanups and fixes: * Tests can now be tagged. * Tag-based selection is now unified across `start_server`, `tags` and `test`. * More information is provided about skipped or ignored tests. * Repeated patterns in tests have been extracted to common procedures, both at a global level and on a per-test file basis. * Cleaned up some cases where test setup was based on a previous test executing (a major anti-pattern that repeats itself in many places). * Cleaned up some cases where test teardown was not part of a test (in the future we should have dedicated teardown code that executes even when tests fail). * Fixed some tests that were flaky running on external servers.
215 lines
6.5 KiB
Tcl
215 lines
6.5 KiB
Tcl
start_server {tags {"hll"}} {
|
|
test {HyperLogLog self test passes} {
|
|
catch {r pfselftest} e
|
|
set e
|
|
} {OK} {needs:pfdebug}
|
|
|
|
test {PFADD without arguments creates an HLL value} {
|
|
r pfadd hll
|
|
r exists hll
|
|
} {1}
|
|
|
|
test {Approximated cardinality after creation is zero} {
|
|
r pfcount hll
|
|
} {0}
|
|
|
|
test {PFADD returns 1 when at least 1 reg was modified} {
|
|
r pfadd hll a b c
|
|
} {1}
|
|
|
|
test {PFADD returns 0 when no reg was modified} {
|
|
r pfadd hll a b c
|
|
} {0}
|
|
|
|
test {PFADD works with empty string (regression)} {
|
|
r pfadd hll ""
|
|
}
|
|
|
|
# Note that the self test stresses much better the
|
|
# cardinality estimation error. We are testing just the
|
|
# command implementation itself here.
|
|
test {PFCOUNT returns approximated cardinality of set} {
|
|
r del hll
|
|
set res {}
|
|
r pfadd hll 1 2 3 4 5
|
|
lappend res [r pfcount hll]
|
|
# Call it again to test cached value invalidation.
|
|
r pfadd hll 6 7 8 8 9 10
|
|
lappend res [r pfcount hll]
|
|
set res
|
|
} {5 10}
|
|
|
|
test {HyperLogLogs are promote from sparse to dense} {
|
|
r del hll
|
|
r config set hll-sparse-max-bytes 3000
|
|
set n 0
|
|
while {$n < 100000} {
|
|
set elements {}
|
|
for {set j 0} {$j < 100} {incr j} {lappend elements [expr rand()]}
|
|
incr n 100
|
|
r pfadd hll {*}$elements
|
|
set card [r pfcount hll]
|
|
set err [expr {abs($card-$n)}]
|
|
assert {$err < (double($card)/100)*5}
|
|
if {$n < 1000} {
|
|
assert {[r pfdebug encoding hll] eq {sparse}}
|
|
} elseif {$n > 10000} {
|
|
assert {[r pfdebug encoding hll] eq {dense}}
|
|
}
|
|
}
|
|
} {} {needs:pfdebug}
|
|
|
|
test {HyperLogLog sparse encoding stress test} {
|
|
for {set x 0} {$x < 1000} {incr x} {
|
|
r del hll1
|
|
r del hll2
|
|
set numele [randomInt 100]
|
|
set elements {}
|
|
for {set j 0} {$j < $numele} {incr j} {
|
|
lappend elements [expr rand()]
|
|
}
|
|
# Force dense representation of hll2
|
|
r pfadd hll2
|
|
r pfdebug todense hll2
|
|
r pfadd hll1 {*}$elements
|
|
r pfadd hll2 {*}$elements
|
|
assert {[r pfdebug encoding hll1] eq {sparse}}
|
|
assert {[r pfdebug encoding hll2] eq {dense}}
|
|
# Cardinality estimated should match exactly.
|
|
assert {[r pfcount hll1] eq [r pfcount hll2]}
|
|
}
|
|
} {} {needs:pfdebug}
|
|
|
|
test {Corrupted sparse HyperLogLogs are detected: Additional at tail} {
|
|
r del hll
|
|
r pfadd hll a b c
|
|
r append hll "hello"
|
|
set e {}
|
|
catch {r pfcount hll} e
|
|
set e
|
|
} {*INVALIDOBJ*}
|
|
|
|
test {Corrupted sparse HyperLogLogs are detected: Broken magic} {
|
|
r del hll
|
|
r pfadd hll a b c
|
|
r setrange hll 0 "0123"
|
|
set e {}
|
|
catch {r pfcount hll} e
|
|
set e
|
|
} {*WRONGTYPE*}
|
|
|
|
test {Corrupted sparse HyperLogLogs are detected: Invalid encoding} {
|
|
r del hll
|
|
r pfadd hll a b c
|
|
r setrange hll 4 "x"
|
|
set e {}
|
|
catch {r pfcount hll} e
|
|
set e
|
|
} {*WRONGTYPE*}
|
|
|
|
test {Corrupted dense HyperLogLogs are detected: Wrong length} {
|
|
r del hll
|
|
r pfadd hll a b c
|
|
r setrange hll 4 "\x00"
|
|
set e {}
|
|
catch {r pfcount hll} e
|
|
set e
|
|
} {*WRONGTYPE*}
|
|
|
|
test {Fuzzing dense/sparse encoding: Redis should always detect errors} {
|
|
for {set j 0} {$j < 1000} {incr j} {
|
|
r del hll
|
|
set items {}
|
|
set numitems [randomInt 3000]
|
|
for {set i 0} {$i < $numitems} {incr i} {
|
|
lappend items [expr {rand()}]
|
|
}
|
|
r pfadd hll {*}$items
|
|
|
|
# Corrupt it in some random way.
|
|
for {set i 0} {$i < 5} {incr i} {
|
|
set len [r strlen hll]
|
|
set pos [randomInt $len]
|
|
set byte [randstring 1 1 binary]
|
|
r setrange hll $pos $byte
|
|
# Don't modify more bytes 50% of times
|
|
if {rand() < 0.5} break
|
|
}
|
|
|
|
# Use the hyperloglog to check if it crashes
|
|
# Redis in some way.
|
|
catch {
|
|
r pfcount hll
|
|
}
|
|
}
|
|
}
|
|
|
|
test {PFADD, PFCOUNT, PFMERGE type checking works} {
|
|
r set foo{t} bar
|
|
catch {r pfadd foo{t} 1} e
|
|
assert_match {*WRONGTYPE*} $e
|
|
catch {r pfcount foo{t}} e
|
|
assert_match {*WRONGTYPE*} $e
|
|
catch {r pfmerge bar{t} foo{t}} e
|
|
assert_match {*WRONGTYPE*} $e
|
|
catch {r pfmerge foo{t} bar{t}} e
|
|
assert_match {*WRONGTYPE*} $e
|
|
}
|
|
|
|
test {PFMERGE results on the cardinality of union of sets} {
|
|
r del hll{t} hll1{t} hll2{t} hll3{t}
|
|
r pfadd hll1{t} a b c
|
|
r pfadd hll2{t} b c d
|
|
r pfadd hll3{t} c d e
|
|
r pfmerge hll{t} hll1{t} hll2{t} hll3{t}
|
|
r pfcount hll{t}
|
|
} {5}
|
|
|
|
test {PFCOUNT multiple-keys merge returns cardinality of union #1} {
|
|
r del hll1{t} hll2{t} hll3{t}
|
|
for {set x 1} {$x < 10000} {incr x} {
|
|
r pfadd hll1{t} "foo-$x"
|
|
r pfadd hll2{t} "bar-$x"
|
|
r pfadd hll3{t} "zap-$x"
|
|
|
|
set card [r pfcount hll1{t} hll2{t} hll3{t}]
|
|
set realcard [expr {$x*3}]
|
|
set err [expr {abs($card-$realcard)}]
|
|
assert {$err < (double($card)/100)*5}
|
|
}
|
|
}
|
|
|
|
test {PFCOUNT multiple-keys merge returns cardinality of union #2} {
|
|
r del hll1{t} hll2{t} hll3{t}
|
|
set elements {}
|
|
for {set x 1} {$x < 10000} {incr x} {
|
|
for {set j 1} {$j <= 3} {incr j} {
|
|
set rint [randomInt 20000]
|
|
r pfadd hll$j{t} $rint
|
|
lappend elements $rint
|
|
}
|
|
}
|
|
set realcard [llength [lsort -unique $elements]]
|
|
set card [r pfcount hll1{t} hll2{t} hll3{t}]
|
|
set err [expr {abs($card-$realcard)}]
|
|
assert {$err < (double($card)/100)*5}
|
|
}
|
|
|
|
test {PFDEBUG GETREG returns the HyperLogLog raw registers} {
|
|
r del hll
|
|
r pfadd hll 1 2 3
|
|
llength [r pfdebug getreg hll]
|
|
} {16384} {needs:pfdebug}
|
|
|
|
test {PFADD / PFCOUNT cache invalidation works} {
|
|
r del hll
|
|
r pfadd hll a b c
|
|
r pfcount hll
|
|
assert {[r getrange hll 15 15] eq "\x00"}
|
|
r pfadd hll a b c
|
|
assert {[r getrange hll 15 15] eq "\x00"}
|
|
r pfadd hll 1 2 3
|
|
assert {[r getrange hll 15 15] eq "\x80"}
|
|
}
|
|
}
|