Add refactored ndel command and UT 55/2255/6
authorHeinonen Arvo <arvo.heinonen@nokia.com>
Thu, 16 Jan 2020 15:41:11 +0000 (17:41 +0200)
committerHeinonen Arvo <arvo.heinonen@nokia.com>
Thu, 23 Jan 2020 11:24:00 +0000 (13:24 +0200)
Add refactored ndel command 'ndel.atomic'.
Add new unit test for this command.
Remove unused includes.

Signed-off-by: Arvo Heinonen <arvo.heinonen@nokia.com>
Change-Id: Ie051e170ec12af45f076876c94016b989a2ead25

redismodule/Makefile.am
redismodule/src/exstrings.c
redismodule/tst/mock/include/exstringsStub.h
redismodule/tst/src/exstrings_ndel_test.cpp [new file with mode: 0644]
redismodule/tst/src/exstrings_nget_test.cpp

index 4ba5411..2c41e18 100755 (executable)
@@ -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
index 6f57753..4211f56 100755 (executable)
@@ -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;
index fd90662..49e1f48 100755 (executable)
 
 
 #include "redismodule.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
 
 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 (file)
index 0000000..28f2b16
--- /dev/null
@@ -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;
+}
index 317769f..103aa6e 100644 (file)
@@ -24,6 +24,8 @@ extern "C" {
 #include "redismodule.h"
 }
 
+#include <string.h>
+
 #include "CppUTest/TestHarness.h"
 #include "CppUTestExt/MockSupport.h"