diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 17:31:02 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 17:31:02 +0000 |
commit | bb12c1fd00eb51118749bbbc69c5596835fcbd3b (patch) | |
tree | 88038a98bd31c1b765f3390767a2ec12e37c79ec /tests/unit/expire.tcl | |
parent | Initial commit. (diff) | |
download | redis-bb12c1fd00eb51118749bbbc69c5596835fcbd3b.tar.xz redis-bb12c1fd00eb51118749bbbc69c5596835fcbd3b.zip |
Adding upstream version 5:7.0.15.upstream/5%7.0.15upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/unit/expire.tcl')
-rw-r--r-- | tests/unit/expire.tcl | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/tests/unit/expire.tcl b/tests/unit/expire.tcl new file mode 100644 index 0000000..322c544 --- /dev/null +++ b/tests/unit/expire.tcl @@ -0,0 +1,807 @@ +start_server {tags {"expire"}} { + test {EXPIRE - set timeouts multiple times} { + r set x foobar + set v1 [r expire x 5] + set v2 [r ttl x] + set v3 [r expire x 10] + set v4 [r ttl x] + r expire x 2 + list $v1 $v2 $v3 $v4 + } {1 [45] 1 10} + + test {EXPIRE - It should be still possible to read 'x'} { + r get x + } {foobar} + + tags {"slow"} { + test {EXPIRE - After 2.1 seconds the key should no longer be here} { + after 2100 + list [r get x] [r exists x] + } {{} 0} + } + + test {EXPIRE - write on expire should work} { + r del x + r lpush x foo + r expire x 1000 + r lpush x bar + r lrange x 0 -1 + } {bar foo} + + test {EXPIREAT - Check for EXPIRE alike behavior} { + r del x + r set x foo + r expireat x [expr [clock seconds]+15] + r ttl x + } {1[345]} + + test {SETEX - Set + Expire combo operation. Check for TTL} { + r setex x 12 test + r ttl x + } {1[012]} + + test {SETEX - Check value} { + r get x + } {test} + + test {SETEX - Overwrite old key} { + r setex y 1 foo + r get y + } {foo} + + tags {"slow"} { + test {SETEX - Wait for the key to expire} { + after 1100 + r get y + } {} + } + + test {SETEX - Wrong time parameter} { + catch {r setex z -10 foo} e + set _ $e + } {*invalid expire*} + + test {PERSIST can undo an EXPIRE} { + r set x foo + r expire x 50 + list [r ttl x] [r persist x] [r ttl x] [r get x] + } {50 1 -1 foo} + + test {PERSIST returns 0 against non existing or non volatile keys} { + r set x foo + list [r persist foo] [r persist nokeyatall] + } {0 0} + + test {EXPIRE precision is now the millisecond} { + # This test is very likely to do a false positive if the + # server is under pressure, so if it does not work give it a few more + # chances. + for {set j 0} {$j < 10} {incr j} { + r del x + r setex x 1 somevalue + after 900 + set a [r get x] + after 1100 + set b [r get x] + if {$a eq {somevalue} && $b eq {}} break + } + if {$::verbose} { + puts "millisecond expire test attempts: $j" + } + list $a $b + } {somevalue {}} + + test "PSETEX can set sub-second expires" { + # This test is very likely to do a false positive if the server is + # under pressure, so if it does not work give it a few more chances. + for {set j 0} {$j < 50} {incr j} { + r del x + r psetex x 100 somevalue + set a [r get x] + after 101 + set b [r get x] + + if {$a eq {somevalue} && $b eq {}} break + } + if {$::verbose} { puts "PSETEX sub-second expire test attempts: $j" } + list $a $b + } {somevalue {}} + + test "PEXPIRE can set sub-second expires" { + # This test is very likely to do a false positive if the server is + # under pressure, so if it does not work give it a few more chances. + for {set j 0} {$j < 50} {incr j} { + r set x somevalue + r pexpire x 100 + set c [r get x] + after 101 + set d [r get x] + + if {$c eq {somevalue} && $d eq {}} break + } + if {$::verbose} { puts "PEXPIRE sub-second expire test attempts: $j" } + list $c $d + } {somevalue {}} + + test "PEXPIREAT can set sub-second expires" { + # This test is very likely to do a false positive if the server is + # under pressure, so if it does not work give it a few more chances. + for {set j 0} {$j < 50} {incr j} { + r set x somevalue + set now [r time] + r pexpireat x [expr ([lindex $now 0]*1000)+([lindex $now 1]/1000)+200] + set e [r get x] + after 201 + set f [r get x] + + if {$e eq {somevalue} && $f eq {}} break + } + if {$::verbose} { puts "PEXPIREAT sub-second expire test attempts: $j" } + list $e $f + } {somevalue {}} + + test {TTL returns time to live in seconds} { + r del x + r setex x 10 somevalue + set ttl [r ttl x] + assert {$ttl > 8 && $ttl <= 10} + } + + test {PTTL returns time to live in milliseconds} { + r del x + r setex x 1 somevalue + set ttl [r pttl x] + assert {$ttl > 900 && $ttl <= 1000} + } + + test {TTL / PTTL / EXPIRETIME / PEXPIRETIME return -1 if key has no expire} { + r del x + r set x hello + list [r ttl x] [r pttl x] [r expiretime x] [r pexpiretime x] + } {-1 -1 -1 -1} + + test {TTL / PTTL / EXPIRETIME / PEXPIRETIME return -2 if key does not exit} { + r del x + list [r ttl x] [r pttl x] [r expiretime x] [r pexpiretime x] + } {-2 -2 -2 -2} + + test {EXPIRETIME returns absolute expiration time in seconds} { + r del x + set abs_expire [expr [clock seconds] + 100] + r set x somevalue exat $abs_expire + assert_equal [r expiretime x] $abs_expire + } + + test {PEXPIRETIME returns absolute expiration time in milliseconds} { + r del x + set abs_expire [expr [clock milliseconds] + 100000] + r set x somevalue pxat $abs_expire + assert_equal [r pexpiretime x] $abs_expire + } + + test {Redis should actively expire keys incrementally} { + r flushdb + r psetex key1 500 a + r psetex key2 500 a + r psetex key3 500 a + assert_equal 3 [r dbsize] + # Redis expires random keys ten times every second so we are + # fairly sure that all the three keys should be evicted after + # two seconds. + wait_for_condition 20 100 { + [r dbsize] eq 0 + } fail { + "Keys did not actively expire." + } + } + + test {Redis should lazy expire keys} { + r flushdb + r debug set-active-expire 0 + r psetex key1{t} 500 a + r psetex key2{t} 500 a + r psetex key3{t} 500 a + set size1 [r dbsize] + # Redis expires random keys ten times every second so we are + # fairly sure that all the three keys should be evicted after + # one second. + after 1000 + set size2 [r dbsize] + r mget key1{t} key2{t} key3{t} + set size3 [r dbsize] + r debug set-active-expire 1 + list $size1 $size2 $size3 + } {3 3 0} {needs:debug} + + test {EXPIRE should not resurrect keys (issue #1026)} { + r debug set-active-expire 0 + r set foo bar + r pexpire foo 500 + after 1000 + r expire foo 10 + r debug set-active-expire 1 + r exists foo + } {0} {needs:debug} + + test {5 keys in, 5 keys out} { + r flushdb + r set a c + r expire a 5 + r set t c + r set e c + r set s c + r set foo b + assert_equal [lsort [r keys *]] {a e foo s t} + r del a ; # Do not leak volatile keys to other tests + } + + test {EXPIRE with empty string as TTL should report an error} { + r set foo bar + catch {r expire foo ""} e + set e + } {*not an integer*} + + test {SET with EX with big integer should report an error} { + catch {r set foo bar EX 10000000000000000} e + set e + } {ERR invalid expire time in 'set' command} + + test {SET with EX with smallest integer should report an error} { + catch {r SET foo bar EX -9999999999999999} e + set e + } {ERR invalid expire time in 'set' command} + + test {GETEX with big integer should report an error} { + r set foo bar + catch {r GETEX foo EX 10000000000000000} e + set e + } {ERR invalid expire time in 'getex' command} + + test {GETEX with smallest integer should report an error} { + r set foo bar + catch {r GETEX foo EX -9999999999999999} e + set e + } {ERR invalid expire time in 'getex' command} + + test {EXPIRE with big integer overflows when converted to milliseconds} { + r set foo bar + + # Hit `when > LLONG_MAX - basetime` + assert_error "ERR invalid expire time in 'expire' command" {r EXPIRE foo 9223370399119966} + + # Hit `when > LLONG_MAX / 1000` + assert_error "ERR invalid expire time in 'expire' command" {r EXPIRE foo 9223372036854776} + assert_error "ERR invalid expire time in 'expire' command" {r EXPIRE foo 10000000000000000} + assert_error "ERR invalid expire time in 'expire' command" {r EXPIRE foo 18446744073709561} + + assert_equal {-1} [r ttl foo] + } + + test {PEXPIRE with big integer overflow when basetime is added} { + r set foo bar + catch {r PEXPIRE foo 9223372036854770000} e + set e + } {ERR invalid expire time in 'pexpire' command} + + test {EXPIRE with big negative integer} { + r set foo bar + + # Hit `when < LLONG_MIN / 1000` + assert_error "ERR invalid expire time in 'expire' command" {r EXPIRE foo -9223372036854776} + assert_error "ERR invalid expire time in 'expire' command" {r EXPIRE foo -9999999999999999} + + r ttl foo + } {-1} + + test {PEXPIREAT with big integer works} { + r set foo bar + r PEXPIREAT foo 9223372036854770000 + } {1} + + test {PEXPIREAT with big negative integer works} { + r set foo bar + r PEXPIREAT foo -9223372036854770000 + r ttl foo + } {-2} + + # Start a new server with empty data and AOF file. + start_server {overrides {appendonly {yes} appendfsync always} tags {external:skip}} { + test {All time-to-live(TTL) in commands are propagated as absolute timestamp in milliseconds in AOF} { + # This test makes sure that expire times are propagated as absolute + # times to the AOF file and not as relative time, so that when the AOF + # is reloaded the TTLs are not being shifted forward to the future. + # We want the time to logically pass when the server is restarted! + + set aof [get_last_incr_aof_path r] + + # Apply each TTL-related command to a unique key + # SET commands + r set foo1 bar ex 100 + r set foo2 bar px 100000 + r set foo3 bar exat [expr [clock seconds]+100] + r set foo4 bar pxat [expr [clock milliseconds]+100000] + r setex foo5 100 bar + r psetex foo6 100000 bar + # EXPIRE-family commands + r set foo7 bar + r expire foo7 100 + r set foo8 bar + r pexpire foo8 100000 + r set foo9 bar + r expireat foo9 [expr [clock seconds]+100] + r set foo10 bar + r pexpireat foo10 [expr [clock seconds]*1000+100000] + r set foo11 bar + r expireat foo11 [expr [clock seconds]-100] + # GETEX commands + r set foo12 bar + r getex foo12 ex 100 + r set foo13 bar + r getex foo13 px 100000 + r set foo14 bar + r getex foo14 exat [expr [clock seconds]+100] + r set foo15 bar + r getex foo15 pxat [expr [clock milliseconds]+100000] + # RESTORE commands + r set foo16 bar + set encoded [r dump foo16] + r restore foo17 100000 $encoded + r restore foo18 [expr [clock milliseconds]+100000] $encoded absttl + + # Assert that each TTL-relatd command are persisted with absolute timestamps in AOF + assert_aof_content $aof { + {select *} + {set foo1 bar PXAT *} + {set foo2 bar PXAT *} + {set foo3 bar PXAT *} + {set foo4 bar PXAT *} + {set foo5 bar PXAT *} + {set foo6 bar PXAT *} + {set foo7 bar} + {pexpireat foo7 *} + {set foo8 bar} + {pexpireat foo8 *} + {set foo9 bar} + {pexpireat foo9 *} + {set foo10 bar} + {pexpireat foo10 *} + {set foo11 bar} + {del foo11} + {set foo12 bar} + {pexpireat foo12 *} + {set foo13 bar} + {pexpireat foo13 *} + {set foo14 bar} + {pexpireat foo14 *} + {set foo15 bar} + {pexpireat foo15 *} + {set foo16 bar} + {restore foo17 * {*} ABSTTL} + {restore foo18 * {*} absttl} + } + + # Remember the absolute TTLs of all the keys + set ttl1 [r pexpiretime foo1] + set ttl2 [r pexpiretime foo2] + set ttl3 [r pexpiretime foo3] + set ttl4 [r pexpiretime foo4] + set ttl5 [r pexpiretime foo5] + set ttl6 [r pexpiretime foo6] + set ttl7 [r pexpiretime foo7] + set ttl8 [r pexpiretime foo8] + set ttl9 [r pexpiretime foo9] + set ttl10 [r pexpiretime foo10] + assert_equal "-2" [r pexpiretime foo11] ; # foo11 is gone + set ttl12 [r pexpiretime foo12] + set ttl13 [r pexpiretime foo13] + set ttl14 [r pexpiretime foo14] + set ttl15 [r pexpiretime foo15] + assert_equal "-1" [r pexpiretime foo16] ; # foo16 has no TTL + set ttl17 [r pexpiretime foo17] + set ttl18 [r pexpiretime foo18] + + # Let some time pass and reload data from AOF + after 2000 + r debug loadaof + + # Assert that relative TTLs are roughly the same + assert_range [r ttl foo1] 90 98 + assert_range [r ttl foo2] 90 98 + assert_range [r ttl foo3] 90 98 + assert_range [r ttl foo4] 90 98 + assert_range [r ttl foo5] 90 98 + assert_range [r ttl foo6] 90 98 + assert_range [r ttl foo7] 90 98 + assert_range [r ttl foo8] 90 98 + assert_range [r ttl foo9] 90 98 + assert_range [r ttl foo10] 90 98 + assert_equal [r ttl foo11] "-2" ; # foo11 is gone + assert_range [r ttl foo12] 90 98 + assert_range [r ttl foo13] 90 98 + assert_range [r ttl foo14] 90 98 + assert_range [r ttl foo15] 90 98 + assert_equal [r ttl foo16] "-1" ; # foo16 has no TTL + assert_range [r ttl foo17] 90 98 + assert_range [r ttl foo18] 90 98 + + # Assert that all keys have restored the same absolute TTLs from AOF + assert_equal [r pexpiretime foo1] $ttl1 + assert_equal [r pexpiretime foo2] $ttl2 + assert_equal [r pexpiretime foo3] $ttl3 + assert_equal [r pexpiretime foo4] $ttl4 + assert_equal [r pexpiretime foo5] $ttl5 + assert_equal [r pexpiretime foo6] $ttl6 + assert_equal [r pexpiretime foo7] $ttl7 + assert_equal [r pexpiretime foo8] $ttl8 + assert_equal [r pexpiretime foo9] $ttl9 + assert_equal [r pexpiretime foo10] $ttl10 + assert_equal [r pexpiretime foo11] "-2" ; # foo11 is gone + assert_equal [r pexpiretime foo12] $ttl12 + assert_equal [r pexpiretime foo13] $ttl13 + assert_equal [r pexpiretime foo14] $ttl14 + assert_equal [r pexpiretime foo15] $ttl15 + assert_equal [r pexpiretime foo16] "-1" ; # foo16 has no TTL + assert_equal [r pexpiretime foo17] $ttl17 + assert_equal [r pexpiretime foo18] $ttl18 + } {} {needs:debug} + } + + test {All TTL in commands are propagated as absolute timestamp in replication stream} { + # Make sure that both relative and absolute expire commands are propagated + # as absolute to replicas for two reasons: + # 1) We want to avoid replicas retaining data much longer than primary due + # to replication lag. + # 2) We want to unify the way TTLs are replicated in both RDB and replication + # stream, which is as absolute timestamps. + # See: https://github.com/redis/redis/issues/8433 + + r flushall ; # Clean up keyspace to avoid interference by keys from other tests + set repl [attach_to_replication_stream] + # SET commands + r set foo1 bar ex 200 + r set foo1 bar px 100000 + r set foo1 bar exat [expr [clock seconds]+100] + r set foo1 bar pxat [expr [clock milliseconds]+100000] + r setex foo1 100 bar + r psetex foo1 100000 bar + r set foo2 bar + # EXPIRE-family commands + r expire foo2 100 + r pexpire foo2 100000 + r set foo3 bar + r expireat foo3 [expr [clock seconds]+100] + r pexpireat foo3 [expr [clock seconds]*1000+100000] + r expireat foo3 [expr [clock seconds]-100] + # GETEX-family commands + r set foo4 bar + r getex foo4 ex 200 + r getex foo4 px 200000 + r getex foo4 exat [expr [clock seconds]+100] + r getex foo4 pxat [expr [clock milliseconds]+100000] + # RESTORE commands + r set foo5 bar + set encoded [r dump foo5] + r restore foo6 100000 $encoded + r restore foo7 [expr [clock milliseconds]+100000] $encoded absttl + + assert_replication_stream $repl { + {select *} + {set foo1 bar PXAT *} + {set foo1 bar PXAT *} + {set foo1 bar PXAT *} + {set foo1 bar PXAT *} + {set foo1 bar PXAT *} + {set foo1 bar PXAT *} + {set foo2 bar} + {pexpireat foo2 *} + {pexpireat foo2 *} + {set foo3 bar} + {pexpireat foo3 *} + {pexpireat foo3 *} + {del foo3} + {set foo4 bar} + {pexpireat foo4 *} + {pexpireat foo4 *} + {pexpireat foo4 *} + {pexpireat foo4 *} + {set foo5 bar} + {restore foo6 * {*} ABSTTL} + {restore foo7 * {*} absttl} + } + close_replication_stream $repl + } {} {needs:repl} + + # Start another server to test replication of TTLs + start_server {tags {needs:repl external:skip}} { + # Set the outer layer server as primary + set primary [srv -1 client] + set primary_host [srv -1 host] + set primary_port [srv -1 port] + # Set this inner layer server as replica + set replica [srv 0 client] + + test {First server should have role slave after REPLICAOF} { + $replica replicaof $primary_host $primary_port + wait_for_condition 50 100 { + [s 0 role] eq {slave} + } else { + fail "Replication not started." + } + } + + test {For all replicated TTL-related commands, absolute expire times are identical on primary and replica} { + # Apply each TTL-related command to a unique key on primary + # SET commands + $primary set foo1 bar ex 100 + $primary set foo2 bar px 100000 + $primary set foo3 bar exat [expr [clock seconds]+100] + $primary set foo4 bar pxat [expr [clock milliseconds]+100000] + $primary setex foo5 100 bar + $primary psetex foo6 100000 bar + # EXPIRE-family commands + $primary set foo7 bar + $primary expire foo7 100 + $primary set foo8 bar + $primary pexpire foo8 100000 + $primary set foo9 bar + $primary expireat foo9 [expr [clock seconds]+100] + $primary set foo10 bar + $primary pexpireat foo10 [expr [clock milliseconds]+100000] + # GETEX commands + $primary set foo11 bar + $primary getex foo11 ex 100 + $primary set foo12 bar + $primary getex foo12 px 100000 + $primary set foo13 bar + $primary getex foo13 exat [expr [clock seconds]+100] + $primary set foo14 bar + $primary getex foo14 pxat [expr [clock milliseconds]+100000] + # RESTORE commands + $primary set foo15 bar + set encoded [$primary dump foo15] + $primary restore foo16 100000 $encoded + $primary restore foo17 [expr [clock milliseconds]+100000] $encoded absttl + + # Wait for replica to get the keys and TTLs + assert {[$primary wait 1 0] == 1} + + # Verify absolute TTLs are identical on primary and replica for all keys + # This is because TTLs are always replicated as absolute values + foreach key [$primary keys *] { + assert_equal [$primary pexpiretime $key] [$replica pexpiretime $key] + } + } + + test {expired key which is created in writeable replicas should be deleted by active expiry} { + $primary flushall + $replica config set replica-read-only no + foreach {yes_or_no} {yes no} { + $replica config set appendonly $yes_or_no + waitForBgrewriteaof $replica + set prev_expired [s expired_keys] + $replica set foo bar PX 1 + wait_for_condition 100 10 { + [s expired_keys] eq $prev_expired + 1 + } else { + fail "key not expired" + } + assert_equal {} [$replica get foo] + } + } + } + + test {SET command will remove expire} { + r set foo bar EX 100 + r set foo bar + r ttl foo + } {-1} + + test {SET - use KEEPTTL option, TTL should not be removed} { + r set foo bar EX 100 + r set foo bar KEEPTTL + set ttl [r ttl foo] + assert {$ttl <= 100 && $ttl > 90} + } + + test {SET - use KEEPTTL option, TTL should not be removed after loadaof} { + r config set appendonly yes + r set foo bar EX 100 + r set foo bar2 KEEPTTL + after 2000 + r debug loadaof + set ttl [r ttl foo] + assert {$ttl <= 98 && $ttl > 90} + } {} {needs:debug} + + test {GETEX use of PERSIST option should remove TTL} { + r set foo bar EX 100 + r getex foo PERSIST + r ttl foo + } {-1} + + test {GETEX use of PERSIST option should remove TTL after loadaof} { + r set foo bar EX 100 + r getex foo PERSIST + after 2000 + r debug loadaof + r ttl foo + } {-1} {needs:debug} + + test {GETEX propagate as to replica as PERSIST, DEL, or nothing} { + set repl [attach_to_replication_stream] + r set foo bar EX 100 + r getex foo PERSIST + r getex foo + r getex foo exat [expr [clock seconds]-100] + assert_replication_stream $repl { + {select *} + {set foo bar PXAT *} + {persist foo} + {del foo} + } + close_replication_stream $repl + } {} {needs:repl} + + test {EXPIRE with NX option on a key with ttl} { + r SET foo bar EX 100 + assert_equal [r EXPIRE foo 200 NX] 0 + assert_range [r TTL foo] 50 100 + } {} + + test {EXPIRE with NX option on a key without ttl} { + r SET foo bar + assert_equal [r EXPIRE foo 200 NX] 1 + assert_range [r TTL foo] 100 200 + } {} + + test {EXPIRE with XX option on a key with ttl} { + r SET foo bar EX 100 + assert_equal [r EXPIRE foo 200 XX] 1 + assert_range [r TTL foo] 100 200 + } {} + + test {EXPIRE with XX option on a key without ttl} { + r SET foo bar + assert_equal [r EXPIRE foo 200 XX] 0 + assert_equal [r TTL foo] -1 + } {} + + test {EXPIRE with GT option on a key with lower ttl} { + r SET foo bar EX 100 + assert_equal [r EXPIRE foo 200 GT] 1 + assert_range [r TTL foo] 100 200 + } {} + + test {EXPIRE with GT option on a key with higher ttl} { + r SET foo bar EX 200 + assert_equal [r EXPIRE foo 100 GT] 0 + assert_range [r TTL foo] 100 200 + } {} + + test {EXPIRE with GT option on a key without ttl} { + r SET foo bar + assert_equal [r EXPIRE foo 200 GT] 0 + assert_equal [r TTL foo] -1 + } {} + + test {EXPIRE with LT option on a key with higher ttl} { + r SET foo bar EX 100 + assert_equal [r EXPIRE foo 200 LT] 0 + assert_range [r TTL foo] 50 100 + } {} + + test {EXPIRE with LT option on a key with lower ttl} { + r SET foo bar EX 200 + assert_equal [r EXPIRE foo 100 LT] 1 + assert_range [r TTL foo] 50 100 + } {} + + test {EXPIRE with LT option on a key without ttl} { + r SET foo bar + assert_equal [r EXPIRE foo 100 LT] 1 + assert_range [r TTL foo] 50 100 + } {} + + test {EXPIRE with LT and XX option on a key with ttl} { + r SET foo bar EX 200 + assert_equal [r EXPIRE foo 100 LT XX] 1 + assert_range [r TTL foo] 50 100 + } {} + + test {EXPIRE with LT and XX option on a key without ttl} { + r SET foo bar + assert_equal [r EXPIRE foo 200 LT XX] 0 + assert_equal [r TTL foo] -1 + } {} + + test {EXPIRE with conflicting options: LT GT} { + catch {r EXPIRE foo 200 LT GT} e + set e + } {ERR GT and LT options at the same time are not compatible} + + test {EXPIRE with conflicting options: NX GT} { + catch {r EXPIRE foo 200 NX GT} e + set e + } {ERR NX and XX, GT or LT options at the same time are not compatible} + + test {EXPIRE with conflicting options: NX LT} { + catch {r EXPIRE foo 200 NX LT} e + set e + } {ERR NX and XX, GT or LT options at the same time are not compatible} + + test {EXPIRE with conflicting options: NX XX} { + catch {r EXPIRE foo 200 NX XX} e + set e + } {ERR NX and XX, GT or LT options at the same time are not compatible} + + test {EXPIRE with unsupported options} { + catch {r EXPIRE foo 200 AB} e + set e + } {ERR Unsupported option AB} + + test {EXPIRE with unsupported options} { + catch {r EXPIRE foo 200 XX AB} e + set e + } {ERR Unsupported option AB} + + test {EXPIRE with negative expiry} { + r SET foo bar EX 100 + assert_equal [r EXPIRE foo -10 LT] 1 + assert_equal [r TTL foo] -2 + } {} + + test {EXPIRE with negative expiry on a non-valitale key} { + r SET foo bar + assert_equal [r EXPIRE foo -10 LT] 1 + assert_equal [r TTL foo] -2 + } {} + + test {EXPIRE with non-existed key} { + assert_equal [r EXPIRE none 100 NX] 0 + assert_equal [r EXPIRE none 100 XX] 0 + assert_equal [r EXPIRE none 100 GT] 0 + assert_equal [r EXPIRE none 100 LT] 0 + } {} + + test {SCAN: Lazy-expire should not be wrapped in MULTI/EXEC} { + r debug set-active-expire 0 + r flushall + + r set foo1 bar PX 1 + r set foo2 bar PX 1 + after 2 + + set repl [attach_to_replication_stream] + + r scan 0 + + assert_replication_stream $repl { + {select *} + {del foo*} + {del foo*} + } + close_replication_stream $repl + assert_equal [r debug set-active-expire 1] {OK} + } {} {needs:debug} + + test {RANDOMKEY: Lazy-expire should not be wrapped in MULTI/EXEC} { + r debug set-active-expire 0 + r flushall + + r set foo1 bar PX 1 + r set foo2 bar PX 1 + after 2 + + set repl [attach_to_replication_stream] + + r randomkey + + assert_replication_stream $repl { + {select *} + {del foo*} + {del foo*} + } + close_replication_stream $repl + assert_equal [r debug set-active-expire 1] {OK} + } {} {needs:debug} +} |