summaryrefslogtreecommitdiffstats
path: root/tests/unit/moduleapi/hooks.tcl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:40:54 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:40:54 +0000
commit317c0644ccf108aa23ef3fd8358bd66c2840bfc0 (patch)
treec417b3d25c86b775989cb5ac042f37611b626c8a /tests/unit/moduleapi/hooks.tcl
parentInitial commit. (diff)
downloadredis-317c0644ccf108aa23ef3fd8358bd66c2840bfc0.tar.xz
redis-317c0644ccf108aa23ef3fd8358bd66c2840bfc0.zip
Adding upstream version 5:7.2.4.upstream/5%7.2.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/unit/moduleapi/hooks.tcl')
-rw-r--r--tests/unit/moduleapi/hooks.tcl321
1 files changed, 321 insertions, 0 deletions
diff --git a/tests/unit/moduleapi/hooks.tcl b/tests/unit/moduleapi/hooks.tcl
new file mode 100644
index 0000000..94b0f6f
--- /dev/null
+++ b/tests/unit/moduleapi/hooks.tcl
@@ -0,0 +1,321 @@
+set testmodule [file normalize tests/modules/hooks.so]
+
+tags "modules" {
+ start_server [list overrides [list loadmodule "$testmodule" appendonly yes]] {
+ test {Test module aof save on server start from empty} {
+ assert {[r hooks.event_count persistence-syncaof-start] == 1}
+ }
+
+ test {Test clients connection / disconnection hooks} {
+ for {set j 0} {$j < 2} {incr j} {
+ set rd1 [redis_deferring_client]
+ $rd1 close
+ }
+ assert {[r hooks.event_count client-connected] > 1}
+ assert {[r hooks.event_count client-disconnected] > 1}
+ }
+
+ test {Test module client change event for blocked client} {
+ set rd [redis_deferring_client]
+ # select db other than 0
+ $rd select 1
+ # block on key
+ $rd brpop foo 0
+ # kill blocked client
+ r client kill skipme yes
+ # assert server is still up
+ assert_equal [r ping] PONG
+ $rd close
+ }
+
+ test {Test module cron hook} {
+ after 100
+ assert {[r hooks.event_count cron-loop] > 0}
+ set hz [r hooks.event_last cron-loop]
+ assert_equal $hz 10
+ }
+
+ test {Test module loaded / unloaded hooks} {
+ set othermodule [file normalize tests/modules/infotest.so]
+ r module load $othermodule
+ r module unload infotest
+ assert_equal [r hooks.event_last module-loaded] "infotest"
+ assert_equal [r hooks.event_last module-unloaded] "infotest"
+ }
+
+ test {Test module aofrw hook} {
+ r debug populate 1000 foo 10000 ;# 10mb worth of data
+ r config set rdbcompression no ;# rdb progress is only checked once in 2mb
+ r BGREWRITEAOF
+ waitForBgrewriteaof r
+ assert_equal [string match {*module-event-persistence-aof-start*} [exec tail -20 < [srv 0 stdout]]] 1
+ assert_equal [string match {*module-event-persistence-end*} [exec tail -20 < [srv 0 stdout]]] 1
+ }
+
+ test {Test module aof load and rdb/aof progress hooks} {
+ # create some aof tail (progress is checked only once in 1000 commands)
+ for {set j 0} {$j < 4000} {incr j} {
+ r set "bar$j" x
+ }
+ # set some configs that will cause many loading progress events during aof loading
+ r config set key-load-delay 500
+ r config set dynamic-hz no
+ r config set hz 500
+ r DEBUG LOADAOF
+ assert_equal [r hooks.event_last loading-aof-start] 0
+ assert_equal [r hooks.event_last loading-end] 0
+ assert {[r hooks.event_count loading-rdb-start] == 0}
+ assert_lessthan 2 [r hooks.event_count loading-progress-rdb] ;# comes from the preamble section
+ assert_lessthan 2 [r hooks.event_count loading-progress-aof]
+ if {$::verbose} {
+ puts "rdb progress events [r hooks.event_count loading-progress-rdb]"
+ puts "aof progress events [r hooks.event_count loading-progress-aof]"
+ }
+ }
+ # undo configs before next test
+ r config set dynamic-hz yes
+ r config set key-load-delay 0
+
+ test {Test module rdb save hook} {
+ # debug reload does: save, flush, load:
+ assert {[r hooks.event_count persistence-syncrdb-start] == 0}
+ assert {[r hooks.event_count loading-rdb-start] == 0}
+ r debug reload
+ assert {[r hooks.event_count persistence-syncrdb-start] == 1}
+ assert {[r hooks.event_count loading-rdb-start] == 1}
+ }
+
+ test {Test key unlink hook} {
+ r set testkey1 hello
+ r del testkey1
+ assert {[r hooks.event_count key-info-testkey1] == 1}
+ assert_equal [r hooks.event_last key-info-testkey1] testkey1
+ r lpush testkey1 hello
+ r lpop testkey1
+ assert {[r hooks.event_count key-info-testkey1] == 2}
+ assert_equal [r hooks.event_last key-info-testkey1] testkey1
+ r set testkey2 world
+ r unlink testkey2
+ assert {[r hooks.event_count key-info-testkey2] == 1}
+ assert_equal [r hooks.event_last key-info-testkey2] testkey2
+ }
+
+ test {Test removed key event} {
+ r set str abcd
+ r set str abcde
+ # For String Type value is returned
+ assert_equal {abcd overwritten} [r hooks.is_key_removed str]
+ assert_equal -1 [r hooks.pexpireat str]
+
+ r del str
+ assert_equal {abcde deleted} [r hooks.is_key_removed str]
+ assert_equal -1 [r hooks.pexpireat str]
+
+ # test int encoded string
+ r set intstr 12345678
+ # incr doesn't fire event
+ r incr intstr
+ catch {[r hooks.is_key_removed intstr]} output
+ assert_match {ERR * removed} $output
+ r del intstr
+ assert_equal {12345679 deleted} [r hooks.is_key_removed intstr]
+
+ catch {[r hooks.is_key_removed not-exists]} output
+ assert_match {ERR * removed} $output
+
+ r hset hash f v
+ r hdel hash f
+ assert_equal {0 deleted} [r hooks.is_key_removed hash]
+
+ r hset hash f v a b
+ r del hash
+ assert_equal {2 deleted} [r hooks.is_key_removed hash]
+
+ r lpush list 1
+ r lpop list
+ assert_equal {0 deleted} [r hooks.is_key_removed list]
+
+ r lpush list 1 2 3
+ r del list
+ assert_equal {3 deleted} [r hooks.is_key_removed list]
+
+ r sadd set 1
+ r spop set
+ assert_equal {0 deleted} [r hooks.is_key_removed set]
+
+ r sadd set 1 2 3 4
+ r del set
+ assert_equal {4 deleted} [r hooks.is_key_removed set]
+
+ r zadd zset 1 f
+ r zpopmin zset
+ assert_equal {0 deleted} [r hooks.is_key_removed zset]
+
+ r zadd zset 1 f 2 d
+ r del zset
+ assert_equal {2 deleted} [r hooks.is_key_removed zset]
+
+ r xadd stream 1-1 f v
+ r xdel stream 1-1
+ # Stream does not delete object when del entry
+ catch {[r hooks.is_key_removed stream]} output
+ assert_match {ERR * removed} $output
+ r del stream
+ assert_equal {0 deleted} [r hooks.is_key_removed stream]
+
+ r xadd stream 2-1 f v
+ r del stream
+ assert_equal {1 deleted} [r hooks.is_key_removed stream]
+
+ # delete key because of active expire
+ set size [r dbsize]
+ r set active-expire abcd px 1
+ #ensure active expire
+ wait_for_condition 50 100 {
+ [r dbsize] == $size
+ } else {
+ fail "Active expire not trigger"
+ }
+ assert_equal {abcd expired} [r hooks.is_key_removed active-expire]
+ # current time is greater than pexpireat
+ set now [r time]
+ set mill [expr ([lindex $now 0]*1000)+([lindex $now 1]/1000)]
+ assert {$mill >= [r hooks.pexpireat active-expire]}
+
+ # delete key because of lazy expire
+ r debug set-active-expire 0
+ r set lazy-expire abcd px 1
+ after 10
+ r get lazy-expire
+ assert_equal {abcd expired} [r hooks.is_key_removed lazy-expire]
+ set now [r time]
+ set mill [expr ([lindex $now 0]*1000)+([lindex $now 1]/1000)]
+ assert {$mill >= [r hooks.pexpireat lazy-expire]}
+ r debug set-active-expire 1
+
+ # delete key not yet expired
+ set now [r time]
+ set expireat [expr ([lindex $now 0]*1000)+([lindex $now 1]/1000)+1000000]
+ r set not-expire abcd pxat $expireat
+ r del not-expire
+ assert_equal {abcd deleted} [r hooks.is_key_removed not-expire]
+ assert_equal $expireat [r hooks.pexpireat not-expire]
+
+ # Test key evict
+ set used [expr {[s used_memory] - [s mem_not_counted_for_evict]}]
+ set limit [expr {$used+100*1024}]
+ set old_policy [lindex [r config get maxmemory-policy] 1]
+ r config set maxmemory $limit
+ # We set policy volatile-random, so only keys with ttl will be evicted
+ r config set maxmemory-policy volatile-random
+ r setex volatile-key 10000 x
+ # We use SETBIT here, so we can set a big key and get the used_memory
+ # bigger than maxmemory. Next command will evict volatile keys. We
+ # can't use SET, as SET uses big input buffer, so it will fail.
+ r setbit big-key 1600000 0 ;# this will consume 200kb
+ r getbit big-key 0
+ assert_equal {x evicted} [r hooks.is_key_removed volatile-key]
+ r config set maxmemory-policy $old_policy
+ r config set maxmemory 0
+ } {OK} {needs:debug}
+
+ test {Test flushdb hooks} {
+ r flushdb
+ assert_equal [r hooks.event_last flush-start] 9
+ assert_equal [r hooks.event_last flush-end] 9
+ r flushall
+ assert_equal [r hooks.event_last flush-start] -1
+ assert_equal [r hooks.event_last flush-end] -1
+ }
+
+ # replication related tests
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+ start_server {} {
+ r module load $testmodule
+ set replica [srv 0 client]
+ set replica_host [srv 0 host]
+ set replica_port [srv 0 port]
+ $replica replicaof $master_host $master_port
+
+ wait_replica_online $master
+
+ test {Test master link up hook} {
+ assert_equal [r hooks.event_count masterlink-up] 1
+ assert_equal [r hooks.event_count masterlink-down] 0
+ }
+
+ test {Test role-replica hook} {
+ assert_equal [r hooks.event_count role-replica] 1
+ assert_equal [r hooks.event_count role-master] 0
+ assert_equal [r hooks.event_last role-replica] [s 0 master_host]
+ }
+
+ test {Test replica-online hook} {
+ assert_equal [r -1 hooks.event_count replica-online] 1
+ assert_equal [r -1 hooks.event_count replica-offline] 0
+ }
+
+ test {Test master link down hook} {
+ r client kill type master
+ assert_equal [r hooks.event_count masterlink-down] 1
+
+ wait_for_condition 50 100 {
+ [string match {*master_link_status:up*} [r info replication]]
+ } else {
+ fail "Replica didn't reconnect"
+ }
+
+ assert_equal [r hooks.event_count masterlink-down] 1
+ assert_equal [r hooks.event_count masterlink-up] 2
+ }
+
+ wait_for_condition 50 10 {
+ [string match {*master_link_status:up*} [r info replication]]
+ } else {
+ fail "Can't turn the instance into a replica"
+ }
+
+ $replica replicaof no one
+
+ test {Test role-master hook} {
+ assert_equal [r hooks.event_count role-replica] 1
+ assert_equal [r hooks.event_count role-master] 1
+ assert_equal [r hooks.event_last role-master] {}
+ }
+
+ test {Test replica-offline hook} {
+ assert_equal [r -1 hooks.event_count replica-online] 2
+ assert_equal [r -1 hooks.event_count replica-offline] 2
+ }
+ # get the replica stdout, to be used by the next test
+ set replica_stdout [srv 0 stdout]
+ }
+
+ test {Test swapdb hooks} {
+ r swapdb 0 10
+ assert_equal [r hooks.event_last swapdb-first] 0
+ assert_equal [r hooks.event_last swapdb-second] 10
+ }
+
+ test {Test configchange hooks} {
+ r config set rdbcompression no
+ assert_equal [r hooks.event_last config-change-count] 1
+ assert_equal [r hooks.event_last config-change-first] rdbcompression
+ }
+
+ # look into the log file of the server that just exited
+ test {Test shutdown hook} {
+ assert_equal [string match {*module-event-shutdown*} [exec tail -5 < $replica_stdout]] 1
+ }
+ }
+
+ start_server {} {
+ test {OnLoad failure will handle un-registration} {
+ catch {r module load $testmodule noload}
+ r flushall
+ r ping
+ }
+ }
+}