From 4ee7adebe245a8b294c771b20d5fb494707312a5 Mon Sep 17 00:00:00 2001 From: Heinonen Arvo Date: Thu, 16 Jan 2020 17:41:11 +0200 Subject: [PATCH] Add refactored ndel command and UT Add refactored ndel command 'ndel.atomic'. Add new unit test for this command. Remove unused includes. Signed-off-by: Arvo Heinonen Change-Id: Ie051e170ec12af45f076876c94016b989a2ead25 --- redismodule/Makefile.am | 1 + redismodule/src/exstrings.c | 55 +++++++++ redismodule/tst/mock/include/exstringsStub.h | 5 +- redismodule/tst/src/exstrings_ndel_test.cpp | 164 +++++++++++++++++++++++++++ redismodule/tst/src/exstrings_nget_test.cpp | 2 + 5 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 redismodule/tst/src/exstrings_ndel_test.cpp diff --git a/redismodule/Makefile.am b/redismodule/Makefile.am index 4ba5411..2c41e18 100755 --- a/redismodule/Makefile.am +++ b/redismodule/Makefile.am @@ -75,6 +75,7 @@ redismodule_ut2_SOURCES = \ tst/mock/include/redismodule.h \ tst/mock/src/commonStub.cpp \ tst/mock/src/redismoduleNewStub.cpp \ + tst/src/exstrings_ndel_test.cpp \ tst/src/exstrings_nget_test.cpp \ tst/src/main.cpp \ tst/src/ut_helpers.cpp diff --git a/redismodule/src/exstrings.c b/redismodule/src/exstrings.c index 6f57753..4211f56 100755 --- a/redismodule/src/exstrings.c +++ b/redismodule/src/exstrings.c @@ -840,6 +840,57 @@ int NGet_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int return Nget_RedisCommand(ctx, &nget_args, false); } +int NDel_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) +{ + RedisModule_AutoMemory(ctx); + int ret = REDISMODULE_OK; + long long replylen = 0; + RedisModuleCallReply *reply = NULL; + ExstringsStatus status = EXSTRINGS_STATUS_NOT_SET; + ScanSomeState scan_state; + ScannedKeys *scanned_keys = NULL; + + InitStaticVariable(); + if (argc != 2) + return RedisModule_WrongArity(ctx); + + scan_state.key = argv[1]; + scan_state.count = def_count_str; + scan_state.cursor = 0; + + do { + status = EXSTRINGS_STATUS_NOT_SET; + scanned_keys = scanSome(ctx, &scan_state, &status); + + if (status != EXSTRINGS_STATUS_NO_ERRORS) { + ret = REDISMODULE_ERR; + break; + } else if (scanned_keys == NULL) { + continue; + } + + reply = RedisModule_Call(ctx, "UNLINK", "v!", scanned_keys->keys, scanned_keys->len); + + status = EXSTRINGS_STATUS_NOT_SET; + forwardIfError(ctx, reply, &status); + if (status != EXSTRINGS_STATUS_NO_ERRORS) { + freeScannedKeys(ctx, scanned_keys); + ret = REDISMODULE_ERR; + break; + } + + replylen += RedisModule_CallReplyInteger(reply); + RedisModule_FreeCallReply(reply); + freeScannedKeys(ctx, scanned_keys); + } while (scan_state.cursor != 0); + + if (ret == REDISMODULE_OK) { + RedisModule_ReplyWithLongLong(ctx, replylen); + } + + return ret; +} + /* This function must be present on each Redis module. It is used in order to * register the commands into the Redis server. */ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { @@ -873,6 +924,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) NGet_NoAtomic_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"ndel.atomic", + NDel_Atomic_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) + return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"msetpub", SetPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; diff --git a/redismodule/tst/mock/include/exstringsStub.h b/redismodule/tst/mock/include/exstringsStub.h index fd90662..49e1f48 100755 --- a/redismodule/tst/mock/include/exstringsStub.h +++ b/redismodule/tst/mock/include/exstringsStub.h @@ -24,10 +24,6 @@ #include "redismodule.h" -#include -#include -#include -#include int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag); int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); @@ -49,6 +45,7 @@ int DelMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int DelIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); +int NDel_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int NGet_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int NGet_NoAtomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); void *NGet_NoAtomic_ThreadMain(void *arg); diff --git a/redismodule/tst/src/exstrings_ndel_test.cpp b/redismodule/tst/src/exstrings_ndel_test.cpp new file mode 100644 index 0000000..28f2b16 --- /dev/null +++ b/redismodule/tst/src/exstrings_ndel_test.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018-2020 Nokia. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This source code is part of the near-RT RIC (RAN Intelligent Controller) + * platform project (RICP). + */ + +extern "C" { +#include "exstringsStub.h" +#include "redismodule.h" +} + +#include "CppUTest/TestHarness.h" +#include "CppUTestExt/MockSupport.h" + +#include "ut_helpers.hpp" + +void nDelReturnNKeysFromUnlink(int count) +{ + mock() + .expectOneCall("RedisModule_CallReplyInteger") + .andReturnValue(count); + +} + +TEST_GROUP(exstrings_ndel) +{ + void setup() + { + mock().enable(); + mock().ignoreOtherCalls(); + } + + void teardown() + { + mock().clear(); + mock().disable(); + } + +}; + +TEST(exstrings_ndel, ndel_atomic_automemory_enabled) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = createRedisStrVec(2); + + mock().ignoreOtherCalls(); + mock().expectOneCall("RedisModule_AutoMemory"); + int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 3); + mock().checkExpectations(); + CHECK_EQUAL(ret, REDISMODULE_ERR); + + delete []redisStrVec; +} + +TEST(exstrings_ndel, ndel_atomic_command_parameter_parameter_number_incorrect) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = createRedisStrVec(2); + + mock().ignoreOtherCalls(); + mock().expectOneCall("RedisModule_WrongArity"); + int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 3); + mock().checkExpectations(); + CHECK_EQUAL(ret, REDISMODULE_ERR); + + delete []redisStrVec; +} + +TEST(exstrings_ndel, ndel_atomic_command_scan_0_keys_found) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = createRedisStrVec(2); + + mock().ignoreOtherCalls(); + returnNKeysFromScanSome(0); + mock().expectOneCall("RedisModule_ReplyWithLongLong") + .withParameter("ll", 0); + int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2); + mock().checkExpectations(); + CHECK_EQUAL(ret, REDISMODULE_OK); + + delete []redisStrVec; +} + +TEST(exstrings_ndel, ndel_atomic_command_scan_3_keys_found_3_keys_deleted) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = createRedisStrVec(2); + + mock().ignoreOtherCalls(); + mock().expectOneCall("RedisModule_Call") + .withParameter("cmdname", "SCAN"); + returnNKeysFromScanSome(3); + mock() + .expectOneCall("RedisModule_Call") + .withParameter("cmdname", "UNLINK"); + nDelReturnNKeysFromUnlink(3); + mock().expectOneCall("RedisModule_ReplyWithLongLong") + .withParameter("ll", 3); + int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2); + mock().checkExpectations(); + CHECK_EQUAL(ret, REDISMODULE_OK); + + delete []redisStrVec; +} + +TEST(exstrings_ndel, ndel_atomic_command_scan_3_keys_found_0_keys_deleted) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = createRedisStrVec(2); + + mock().ignoreOtherCalls(); + mock().expectOneCall("RedisModule_Call") + .withParameter("cmdname", "SCAN"); + returnNKeysFromScanSome(3); + mock() + .expectOneCall("RedisModule_Call") + .withParameter("cmdname", "UNLINK"); + nDelReturnNKeysFromUnlink(0); + mock().expectOneCall("RedisModule_ReplyWithLongLong") + .withParameter("ll", 0); + int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2); + mock().checkExpectations(); + CHECK_EQUAL(ret, REDISMODULE_OK); + + delete []redisStrVec; +} + +TEST(exstrings_ndel, ndel_atomic_command_scan_3_keys_found_1_keys_deleted) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = createRedisStrVec(2); + + mock().ignoreOtherCalls(); + mock().expectOneCall("RedisModule_Call") + .withParameter("cmdname", "SCAN"); + returnNKeysFromScanSome(3); + mock() + .expectOneCall("RedisModule_Call") + .withParameter("cmdname", "UNLINK"); + nDelReturnNKeysFromUnlink(1); + mock().expectOneCall("RedisModule_ReplyWithLongLong") + .withParameter("ll", 1); + int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2); + mock().checkExpectations(); + CHECK_EQUAL(ret, REDISMODULE_OK); + + delete []redisStrVec; +} diff --git a/redismodule/tst/src/exstrings_nget_test.cpp b/redismodule/tst/src/exstrings_nget_test.cpp index 317769f..103aa6e 100644 --- a/redismodule/tst/src/exstrings_nget_test.cpp +++ b/redismodule/tst/src/exstrings_nget_test.cpp @@ -24,6 +24,8 @@ extern "C" { #include "redismodule.h" } +#include + #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" -- 2.16.6