From 48a9d63af3c288527c9abbf13206960c0055f62b Mon Sep 17 00:00:00 2001 From: Yossi Gottlieb Date: Wed, 11 Nov 2020 22:57:33 +0200 Subject: [PATCH] Add timer module API tests. (#8041) --- tests/modules/Makefile | 3 +- tests/modules/timer.c | 103 +++++++++++++++++++++++++++++++++ tests/unit/moduleapi/timer.tcl | 57 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 tests/modules/timer.c create mode 100644 tests/unit/moduleapi/timer.tcl diff --git a/tests/modules/Makefile b/tests/modules/Makefile index a8b08ecf0..8df05ed01 100644 --- a/tests/modules/Makefile +++ b/tests/modules/Makefile @@ -25,7 +25,8 @@ TEST_MODULES = \ auth.so \ keyspace_events.so \ blockedclient.so \ - getkeys.so + getkeys.so \ + timer.so .PHONY: all diff --git a/tests/modules/timer.c b/tests/modules/timer.c new file mode 100644 index 000000000..d2a8d8e74 --- /dev/null +++ b/tests/modules/timer.c @@ -0,0 +1,103 @@ + +#define REDISMODULE_EXPERIMENTAL_API +#include "redismodule.h" + +static void timer_callback(RedisModuleCtx *ctx, void *data) +{ + RedisModuleString *keyname = data; + RedisModuleCallReply *reply; + + reply = RedisModule_Call(ctx, "INCR", "s", keyname); + if (reply != NULL) + RedisModule_FreeCallReply(reply); + RedisModule_FreeString(ctx, keyname); +} + +int test_createtimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) +{ + if (argc != 3) { + RedisModule_WrongArity(ctx); + return REDISMODULE_OK; + } + + long long period; + if (RedisModule_StringToLongLong(argv[1], &period) == REDISMODULE_ERR) { + RedisModule_ReplyWithError(ctx, "Invalid time specified."); + return REDISMODULE_OK; + } + + RedisModuleString *keyname = argv[2]; + RedisModule_RetainString(ctx, keyname); + + RedisModuleTimerID id = RedisModule_CreateTimer(ctx, period, timer_callback, keyname); + RedisModule_ReplyWithLongLong(ctx, id); + + return REDISMODULE_OK; +} + +int test_gettimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) +{ + if (argc != 2) { + RedisModule_WrongArity(ctx); + return REDISMODULE_OK; + } + + long long id; + if (RedisModule_StringToLongLong(argv[1], &id) == REDISMODULE_ERR) { + RedisModule_ReplyWithError(ctx, "Invalid id specified."); + return REDISMODULE_OK; + } + + uint64_t remaining; + RedisModuleString *keyname; + if (RedisModule_GetTimerInfo(ctx, id, &remaining, (void **)&keyname) == REDISMODULE_ERR) { + RedisModule_ReplyWithNull(ctx); + } else { + RedisModule_ReplyWithArray(ctx, 2); + RedisModule_ReplyWithString(ctx, keyname); + RedisModule_ReplyWithLongLong(ctx, remaining); + } + + return REDISMODULE_OK; +} + +int test_stoptimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) +{ + if (argc != 2) { + RedisModule_WrongArity(ctx); + return REDISMODULE_OK; + } + + long long id; + if (RedisModule_StringToLongLong(argv[1], &id) == REDISMODULE_ERR) { + RedisModule_ReplyWithError(ctx, "Invalid id specified."); + return REDISMODULE_OK; + } + + int ret = 0; + RedisModuleString *keyname; + if (RedisModule_StopTimer(ctx, id, (void **) &keyname) == REDISMODULE_OK) { + RedisModule_FreeString(ctx, keyname); + ret = 1; + } + + RedisModule_ReplyWithLongLong(ctx, ret); + return REDISMODULE_OK; +} + + +int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + REDISMODULE_NOT_USED(argv); + REDISMODULE_NOT_USED(argc); + if (RedisModule_Init(ctx,"timer",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"test.createtimer", test_createtimer,"",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"test.gettimer", test_gettimer,"",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"test.stoptimer", test_stoptimer,"",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + + return REDISMODULE_OK; +} diff --git a/tests/unit/moduleapi/timer.tcl b/tests/unit/moduleapi/timer.tcl new file mode 100644 index 000000000..10a902276 --- /dev/null +++ b/tests/unit/moduleapi/timer.tcl @@ -0,0 +1,57 @@ +set testmodule [file normalize tests/modules/timer.so] + +start_server {tags {"modules"}} { + r module load $testmodule + + test {RM_CreateTimer: a sequence of timers work} { + # We can't guarantee same-ms but we try using MULTI/EXEC + r multi + for {set i 0} {$i < 20} {incr i} { + r test.createtimer 10 timer-incr-key + } + r exec + + after 500 + assert_equal 20 [r get timer-incr-key] + } + + test {RM_GetTimer: basic sanity} { + # Getting non-existing timer + assert_equal {} [r test.gettimer 0] + + # Getting a real timer + set id [r test.createtimer 10000 timer-incr-key] + set info [r test.gettimer $id] + + assert_equal "timer-incr-key" [lindex $info 0] + set remaining [lindex $info 1] + assert {$remaining < 10000 && $remaining > 1} + } + + test {RM_StopTimer: basic sanity} { + r set "timer-incr-key" 0 + set id [r test.createtimer 1000 timer-incr-key] + + assert_equal 1 [r test.stoptimer $id] + + # Wait to be sure timer doesn't execute + after 2000 + assert_equal 0 [r get timer-incr-key] + + # Stop non-existing timer + assert_equal 0 [r test.stoptimer $id] + } + + test {Timer appears non-existing after it fires} { + r set "timer-incr-key" 0 + set id [r test.createtimer 10 timer-incr-key] + + # verify timer fired + after 500 + assert_equal 1 [r get timer-incr-key] + + # verify id does not exist + assert_equal {} [r test.gettimer $id] + } +} +