Add updated version of Redis modules 53/2253/2
authorHeinonen Arvo <arvo.heinonen@nokia.com>
Thu, 12 Dec 2019 14:22:12 +0000 (16:22 +0200)
committerHeinonen Arvo <arvo.heinonen@nokia.com>
Tue, 21 Jan 2020 08:28:19 +0000 (10:28 +0200)
Adapted from Nokia internal RCP code repository, revision 120a6bb from
branch 'rcp2.0'.

Changes to original:
* Unit tests and checking for unit test dependencies is now disabled
  by default.
* Unit tests can be enabled with the configure flag '--enable-unit-test'
* Remove Nget and Ndel. These will be refactored and reintroduced in
  a later commit.
* Run valgrind in UT to check for memory leaks.
* For opaque types there is not need to use real redis types in UT.
  Instead define opaque types as dummy structs in
  'tst/mock/include/redismodule.h'.
* Add instructions on running UT to redismodule/README.md.
* Remove dead code and unused includes.
* Fix compiler warnings in UT.
* Treat warnings as errors in UT.

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

12 files changed:
redismodule/Makefile.am
redismodule/README.md
redismodule/configure.ac
redismodule/include/redismodule.h
redismodule/run-tests.sh.in
redismodule/src/exstrings.c
redismodule/tst/mock/include/commonStub.h [new file with mode: 0644]
redismodule/tst/mock/include/exstringsStub.h
redismodule/tst/mock/include/redismodule.h
redismodule/tst/mock/src/commonStub.cpp [new file with mode: 0644]
redismodule/tst/mock/src/redismoduleStub.cpp
redismodule/tst/src/exstrings_test.cpp

index f2b9795..6faacad 100755 (executable)
@@ -8,57 +8,74 @@ BASE_LDFLAGS =
 
 libredismodule_la_SOURCES = \
        include/redismodule.h\
-       src/exstrings.c 
+       src/exstrings.c
 
 libredismodule_la_CFLAGS = \
-       -std=c11 -fPIC -g \
-       -I${includedir} -I${top_srcdir}/include 
+       -std=c11 -fPIC -g -Wall -Werror -Wextra \
+       -DREDISMODULE_EXPERIMENTAL_API \
+       -I${includedir} -I${top_srcdir}/include
 
 
 libredismodule_la_LDFLAGS = $(BASE_LDFLAGS) -avoid-version -module -shared
 
 #pkgincludedir = ${includedir}
-#pkginclude_HEADERS = include/redismodule.h 
+#pkginclude_HEADERS = include/redismodule.h
 
-clean-local: 
+clean-local:
        rm -rf ${builddir}/libredismodule.pc
 
+if UNIT_TEST_ENABLED
 # UT
 CPP_U_TEST=$(CPP_U_TEST_LATEST)
 check_PROGRAMS = redismodule_ut
-#TESTS = ${check_PROGRAMS} 
+#TESTS = ${check_PROGRAMS}
 redismodule_ut_SOURCES = \
-       tst/mock/include/redismodule.h  \
-       tst/mock/include/exstringsStub.h \
        src/exstrings.c \
+       tst/mock/include/commonStub.h \
+       tst/mock/include/exstringsStub.h \
+       tst/mock/include/redismodule.h  \
+       tst/mock/src/commonStub.cpp \
        tst/mock/src/redismoduleStub.cpp \
-       tst/src/main.cpp \
-       tst/src/exstrings_test.cpp 
+       tst/src/exstrings_test.cpp \
+       tst/src/main.cpp
 
 
 redismodule_ut_CFLAGS = \
-        -std=c11 -g -Wall \
-        -fprofile-arcs -ftest-coverage \
-        -D__UT__ \
+               -std=c11 -g -Wall \
+               -fprofile-arcs -ftest-coverage \
+               -D__UT__ \
+               $(LIBCPPUTEST_CFLAGS) \
                -I${top_srcdir}/tst/mock/include \
                -I${includedir} \
                -I${top_srcdir}/include \
-               -I${CPP_U_TEST_LATEST}/include 
+               -I${CPP_U_TEST_LATEST}/include \
+               -Wall -Werror -Wextra
 
 redismodule_ut_CXXFLAGS = \
        -std=c++11 -g -Wall \
        -fprofile-arcs -ftest-coverage \
        -D__UT__ \
+       $(LIBCPPUTEST_CFLAGS) \
        -I${top_srcdir}/tst/mock/include \
        -I${includedir} \
        -I${top_srcdir}/include \
-       -I${CPP_U_TEST_LATEST}/include 
+       -I${CPP_U_TEST_LATEST}/include \
+       -Wall -Werror -Wextra
 
 
 redismodule_ut_LDFLAGS = -Wl,-rpath=${libdir} ${UT_COVERAGE_LDFLAGS}
-redismodule_ut_LDADD = -L${libdir} -L${CPP_U_TEST_LATEST}/lib -lCppUTest -lCppUTestExt -lgcov 
+redismodule_ut_LDADD = -L${libdir} $(LIBCPPUTEST_LIBS) -lgcov
+
 
 test: redismodule_ut
        ./run-tests.sh
 
 TESTS = run-tests.sh
+
+else
+
+test:
+       echo 'enable ut with configure flag: --enable-unit-test'
+       exit 1
+
+endif #UNIT_TEST_ENABLED
index 7add0a6..306edd8 100755 (executable)
@@ -3,6 +3,26 @@
 This subdirectory provides implementation for the commands which are implemented
 as a [Redis modules](https://redis.io/topics/modules-intro).
 
+# Compiling and UT (Unit Tests)
+
+To compile and install run standard automake commands
+in the redismodule directory:
+```
+./autogen.sh
+./configure
+make
+make install
+```
+
+To run unit tests `cpputest` and `valgrind`
+need to be installed as additional dependencies.
+To enable and run unit tests use the commands:
+```
+./autogen.sh
+./configure --enable-unit-test
+make test
+```
+
 # Commands
 
 ## SETIE key value oldvalue [expiration EX seconds|PX milliseconds]
index ecc73e5..a688bef 100755 (executable)
@@ -16,6 +16,15 @@ AC_PROG_CC
 AC_PROG_INSTALL
 AC_PROG_MAKE_SET
 
+AC_ARG_ENABLE([unit-test],
+[  --enable-unit-test    Check for UT dependencies],
+[  PKG_CHECK_MODULES([LIBCPPUTEST],[cpputest])
+   AC_CHECK_PROG(VALGRIND_CHECK, valgrind, yes)
+   AS_IF([test x"$VALGRIND_CHECK" != x"yes"], [AC_MSG_ERROR([Install valgrind to run UT.])])
+   UNIT_TEST_ENABLED=true
+],
+[  UNIT_TEST_ENABLED=false  ])
+AM_CONDITIONAL([UNIT_TEST_ENABLED], [$UNIT_TEST_ENABLED])
 
 # Checks for header files.
 
index c6f97d5..e64b1a9 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nokia.
+ * 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.
 #define REDISMODULE_HASH_CFIELDS    (1<<2)
 #define REDISMODULE_HASH_EXISTS     (1<<3)
 
-/* Context Flags: Info about the current context returned by RM_GetContextFlags */
+/* Context Flags: Info about the current context returned by
+ * RM_GetContextFlags(). */
 
 /* The command is running in the context of a Lua script */
-#define REDISMODULE_CTX_FLAGS_LUA 0x0001
+#define REDISMODULE_CTX_FLAGS_LUA (1<<0)
 /* The command is running inside a Redis transaction */
-#define REDISMODULE_CTX_FLAGS_MULTI 0x0002
+#define REDISMODULE_CTX_FLAGS_MULTI (1<<1)
 /* The instance is a master */
-#define REDISMODULE_CTX_FLAGS_MASTER 0x0004
+#define REDISMODULE_CTX_FLAGS_MASTER (1<<2)
 /* The instance is a slave */
-#define REDISMODULE_CTX_FLAGS_SLAVE 0x0008
+#define REDISMODULE_CTX_FLAGS_SLAVE (1<<3)
 /* The instance is read-only (usually meaning it's a slave as well) */
-#define REDISMODULE_CTX_FLAGS_READONLY 0x0010
+#define REDISMODULE_CTX_FLAGS_READONLY (1<<4)
 /* The instance is running in cluster mode */
-#define REDISMODULE_CTX_FLAGS_CLUSTER 0x0020
+#define REDISMODULE_CTX_FLAGS_CLUSTER (1<<5)
 /* The instance has AOF enabled */
-#define REDISMODULE_CTX_FLAGS_AOF 0x0040 //
+#define REDISMODULE_CTX_FLAGS_AOF (1<<6)
 /* The instance has RDB enabled */
-#define REDISMODULE_CTX_FLAGS_RDB 0x0080 //
+#define REDISMODULE_CTX_FLAGS_RDB (1<<7)
 /* The instance has Maxmemory set */
-#define REDISMODULE_CTX_FLAGS_MAXMEMORY 0x0100
+#define REDISMODULE_CTX_FLAGS_MAXMEMORY (1<<8)
 /* Maxmemory is set and has an eviction policy that may delete keys */
-#define REDISMODULE_CTX_FLAGS_EVICT 0x0200 
+#define REDISMODULE_CTX_FLAGS_EVICT (1<<9)
+/* Redis is out of memory according to the maxmemory flag. */
+#define REDISMODULE_CTX_FLAGS_OOM (1<<10)
+/* Less than 25% of memory available according to maxmemory. */
+#define REDISMODULE_CTX_FLAGS_OOM_WARNING (1<<11)
+/* The command was sent over the replication link. */
+#define REDISMODULE_CTX_FLAGS_REPLICATED (1<<12)
+/* Redis is currently loading either from AOF or RDB. */
+#define REDISMODULE_CTX_FLAGS_LOADING (1<<13)
 
 
 #define REDISMODULE_NOTIFY_GENERIC (1<<2)     /* g */
 #define REDISMODULE_NOTIFY_ZSET (1<<7)        /* z */
 #define REDISMODULE_NOTIFY_EXPIRED (1<<8)     /* x */
 #define REDISMODULE_NOTIFY_EVICTED (1<<9)     /* e */
-#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED)      /* A */
+#define REDISMODULE_NOTIFY_STREAM (1<<10)     /* t */
+#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM)      /* A */
 
 
 /* A special pointer that we can use between the core and the module to signal
 #define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
 #define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
 
+/* Cluster API defines. */
+#define REDISMODULE_NODE_ID_LEN 40
+#define REDISMODULE_NODE_MYSELF     (1<<0)
+#define REDISMODULE_NODE_MASTER     (1<<1)
+#define REDISMODULE_NODE_SLAVE      (1<<2)
+#define REDISMODULE_NODE_PFAIL      (1<<3)
+#define REDISMODULE_NODE_FAIL       (1<<4)
+#define REDISMODULE_NODE_NOFAILOVER (1<<5)
+
+#define REDISMODULE_CLUSTER_FLAG_NONE 0
+#define REDISMODULE_CLUSTER_FLAG_NO_FAILOVER (1<<1)
+#define REDISMODULE_CLUSTER_FLAG_NO_REDIRECTION (1<<2)
+
 #define REDISMODULE_NOT_USED(V) ((void) V)
 
+/* Bit flags for aux_save_triggers and the aux_load and aux_save callbacks */
+#define REDISMODULE_AUX_BEFORE_RDB (1<<0)
+#define REDISMODULE_AUX_AFTER_RDB (1<<1)
+
+/* This type represents a timer handle, and is returned when a timer is
+ * registered and used in order to invalidate a timer. It's just a 64 bit
+ * number, because this is how each timer is represented inside the radix tree
+ * of timers that are going to expire, sorted by expire time. */
+typedef uint64_t RedisModuleTimerID;
+
+/* CommandFilter Flags */
+
+/* Do filter RedisModule_Call() commands initiated by module itself. */
+#define REDISMODULE_CMDFILTER_NOSELF    (1<<0)
+
 /* ------------------------- End of common defines ------------------------ */
 
 #ifndef REDISMODULE_CORE
@@ -141,18 +179,28 @@ typedef struct RedisModuleIO RedisModuleIO;
 typedef struct RedisModuleType RedisModuleType;
 typedef struct RedisModuleDigest RedisModuleDigest;
 typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
-
-typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
-
-typedef int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
+typedef struct RedisModuleClusterInfo RedisModuleClusterInfo;
+typedef struct RedisModuleDict RedisModuleDict;
+typedef struct RedisModuleDictIter RedisModuleDictIter;
+typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx;
+typedef struct RedisModuleCommandFilter RedisModuleCommandFilter;
+
+typedef int (*RedisModuleCmdFunc)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc);
+typedef int (*RedisModuleNotificationFunc)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
 typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
 typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
+typedef int (*RedisModuleTypeAuxLoadFunc)(RedisModuleIO *rdb, int encver, int when);
+typedef void (*RedisModuleTypeAuxSaveFunc)(RedisModuleIO *rdb, int when);
 typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
 typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
 typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
 typedef void (*RedisModuleTypeFreeFunc)(void *value);
+typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len);
+typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
+typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter);
 
-#define REDISMODULE_TYPE_METHOD_VERSION 1
+#define REDISMODULE_TYPE_METHOD_VERSION 2
 typedef struct RedisModuleTypeMethods {
     uint64_t version;
     RedisModuleTypeLoadFunc rdb_load;
@@ -161,6 +209,9 @@ typedef struct RedisModuleTypeMethods {
     RedisModuleTypeMemUsageFunc mem_usage;
     RedisModuleTypeDigestFunc digest;
     RedisModuleTypeFreeFunc free;
+    RedisModuleTypeAuxLoadFunc aux_load;
+    RedisModuleTypeAuxSaveFunc aux_save;
+    int aux_save_triggers;
 } RedisModuleTypeMethods;
 
 #define REDISMODULE_GET_API(name) \
@@ -206,6 +257,7 @@ int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx,
 int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
 void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
 int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
+int REDISMODULE_API_FUNC(RedisModule_ReplyWithCString)(RedisModuleCtx *ctx, const char *buf);
 int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
 int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
 int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
@@ -267,25 +319,73 @@ int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, Re
 void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
 int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
 RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
+const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetKeyNameFromIO)(RedisModuleIO *io);
 long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
 void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
 void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
 void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
+RedisModuleDict *REDISMODULE_API_FUNC(RedisModule_CreateDict)(RedisModuleCtx *ctx);
+void REDISMODULE_API_FUNC(RedisModule_FreeDict)(RedisModuleCtx *ctx, RedisModuleDict *d);
+uint64_t REDISMODULE_API_FUNC(RedisModule_DictSize)(RedisModuleDict *d);
+int REDISMODULE_API_FUNC(RedisModule_DictSetC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr);
+int REDISMODULE_API_FUNC(RedisModule_DictReplaceC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr);
+int REDISMODULE_API_FUNC(RedisModule_DictSet)(RedisModuleDict *d, RedisModuleString *key, void *ptr);
+int REDISMODULE_API_FUNC(RedisModule_DictReplace)(RedisModuleDict *d, RedisModuleString *key, void *ptr);
+void *REDISMODULE_API_FUNC(RedisModule_DictGetC)(RedisModuleDict *d, void *key, size_t keylen, int *nokey);
+void *REDISMODULE_API_FUNC(RedisModule_DictGet)(RedisModuleDict *d, RedisModuleString *key, int *nokey);
+int REDISMODULE_API_FUNC(RedisModule_DictDelC)(RedisModuleDict *d, void *key, size_t keylen, void *oldval);
+int REDISMODULE_API_FUNC(RedisModule_DictDel)(RedisModuleDict *d, RedisModuleString *key, void *oldval);
+RedisModuleDictIter *REDISMODULE_API_FUNC(RedisModule_DictIteratorStartC)(RedisModuleDict *d, const char *op, void *key, size_t keylen);
+RedisModuleDictIter *REDISMODULE_API_FUNC(RedisModule_DictIteratorStart)(RedisModuleDict *d, const char *op, RedisModuleString *key);
+void REDISMODULE_API_FUNC(RedisModule_DictIteratorStop)(RedisModuleDictIter *di);
+int REDISMODULE_API_FUNC(RedisModule_DictIteratorReseekC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
+int REDISMODULE_API_FUNC(RedisModule_DictIteratorReseek)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
+void *REDISMODULE_API_FUNC(RedisModule_DictNextC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr);
+void *REDISMODULE_API_FUNC(RedisModule_DictPrevC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictNext)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr);
+RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictPrev)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr);
+int REDISMODULE_API_FUNC(RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
+int REDISMODULE_API_FUNC(RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
 
 /* Experimental APIs */
 #ifdef REDISMODULE_EXPERIMENTAL_API
-RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms);
+#define REDISMODULE_EXPERIMENTAL_API_VERSION 3
+RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms);
 int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
 int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
 int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
 void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
+RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientHandle)(RedisModuleCtx *ctx);
 int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
 RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
 void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
 void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
 void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
 int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
-
+int REDISMODULE_API_FUNC(RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx);
+void REDISMODULE_API_FUNC(RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback);
+int REDISMODULE_API_FUNC(RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len);
+int REDISMODULE_API_FUNC(RedisModule_GetClusterNodeInfo)(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags);
+char **REDISMODULE_API_FUNC(RedisModule_GetClusterNodesList)(RedisModuleCtx *ctx, size_t *numnodes);
+void REDISMODULE_API_FUNC(RedisModule_FreeClusterNodesList)(char **ids);
+RedisModuleTimerID REDISMODULE_API_FUNC(RedisModule_CreateTimer)(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data);
+int REDISMODULE_API_FUNC(RedisModule_StopTimer)(RedisModuleCtx *ctx, RedisModuleTimerID id, void **data);
+int REDISMODULE_API_FUNC(RedisModule_GetTimerInfo)(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data);
+const char *REDISMODULE_API_FUNC(RedisModule_GetMyClusterID)(void);
+size_t REDISMODULE_API_FUNC(RedisModule_GetClusterSize)(void);
+void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t len);
+void REDISMODULE_API_FUNC(RedisModule_GetRandomHexChars)(char *dst, size_t len);
+void REDISMODULE_API_FUNC(RedisModule_SetDisconnectCallback)(RedisModuleBlockedClient *bc, RedisModuleDisconnectFunc callback);
+void REDISMODULE_API_FUNC(RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags);
+int REDISMODULE_API_FUNC(RedisModule_ExportSharedAPI)(RedisModuleCtx *ctx, const char *apiname, void *func);
+void *REDISMODULE_API_FUNC(RedisModule_GetSharedAPI)(RedisModuleCtx *ctx, const char *apiname);
+RedisModuleCommandFilter *REDISMODULE_API_FUNC(RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags);
+int REDISMODULE_API_FUNC(RedisModule_UnregisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter);
+int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgsCount)(RedisModuleCommandFilterCtx *fctx);
+const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos);
+int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg);
+int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg);
+int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos);
 #endif
 
 /* This is included inline inside each Redis module. */
@@ -308,6 +408,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
     REDISMODULE_GET_API(ReplyWithArray);
     REDISMODULE_GET_API(ReplySetArrayLength);
     REDISMODULE_GET_API(ReplyWithStringBuffer);
+    REDISMODULE_GET_API(ReplyWithCString);
     REDISMODULE_GET_API(ReplyWithString);
     REDISMODULE_GET_API(ReplyWithNull);
     REDISMODULE_GET_API(ReplyWithCallReply);
@@ -391,10 +492,33 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
     REDISMODULE_GET_API(RetainString);
     REDISMODULE_GET_API(StringCompare);
     REDISMODULE_GET_API(GetContextFromIO);
+    REDISMODULE_GET_API(GetKeyNameFromIO);
     REDISMODULE_GET_API(Milliseconds);
     REDISMODULE_GET_API(DigestAddStringBuffer);
     REDISMODULE_GET_API(DigestAddLongLong);
     REDISMODULE_GET_API(DigestEndSequence);
+    REDISMODULE_GET_API(CreateDict);
+    REDISMODULE_GET_API(FreeDict);
+    REDISMODULE_GET_API(DictSize);
+    REDISMODULE_GET_API(DictSetC);
+    REDISMODULE_GET_API(DictReplaceC);
+    REDISMODULE_GET_API(DictSet);
+    REDISMODULE_GET_API(DictReplace);
+    REDISMODULE_GET_API(DictGetC);
+    REDISMODULE_GET_API(DictGet);
+    REDISMODULE_GET_API(DictDelC);
+    REDISMODULE_GET_API(DictDel);
+    REDISMODULE_GET_API(DictIteratorStartC);
+    REDISMODULE_GET_API(DictIteratorStart);
+    REDISMODULE_GET_API(DictIteratorStop);
+    REDISMODULE_GET_API(DictIteratorReseekC);
+    REDISMODULE_GET_API(DictIteratorReseek);
+    REDISMODULE_GET_API(DictNextC);
+    REDISMODULE_GET_API(DictPrevC);
+    REDISMODULE_GET_API(DictNext);
+    REDISMODULE_GET_API(DictPrev);
+    REDISMODULE_GET_API(DictCompare);
+    REDISMODULE_GET_API(DictCompareC);
 
 #ifdef REDISMODULE_EXPERIMENTAL_API
     REDISMODULE_GET_API(GetThreadSafeContext);
@@ -406,9 +530,33 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
     REDISMODULE_GET_API(IsBlockedReplyRequest);
     REDISMODULE_GET_API(IsBlockedTimeoutRequest);
     REDISMODULE_GET_API(GetBlockedClientPrivateData);
+    REDISMODULE_GET_API(GetBlockedClientHandle);
     REDISMODULE_GET_API(AbortBlock);
+    REDISMODULE_GET_API(SetDisconnectCallback);
     REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
-
+    REDISMODULE_GET_API(BlockedClientDisconnected);
+    REDISMODULE_GET_API(RegisterClusterMessageReceiver);
+    REDISMODULE_GET_API(SendClusterMessage);
+    REDISMODULE_GET_API(GetClusterNodeInfo);
+    REDISMODULE_GET_API(GetClusterNodesList);
+    REDISMODULE_GET_API(FreeClusterNodesList);
+    REDISMODULE_GET_API(CreateTimer);
+    REDISMODULE_GET_API(StopTimer);
+    REDISMODULE_GET_API(GetTimerInfo);
+    REDISMODULE_GET_API(GetMyClusterID);
+    REDISMODULE_GET_API(GetClusterSize);
+    REDISMODULE_GET_API(GetRandomBytes);
+    REDISMODULE_GET_API(GetRandomHexChars);
+    REDISMODULE_GET_API(SetClusterFlags);
+    REDISMODULE_GET_API(ExportSharedAPI);
+    REDISMODULE_GET_API(GetSharedAPI);
+    REDISMODULE_GET_API(RegisterCommandFilter);
+    REDISMODULE_GET_API(UnregisterCommandFilter);
+    REDISMODULE_GET_API(CommandFilterArgsCount);
+    REDISMODULE_GET_API(CommandFilterArgGet);
+    REDISMODULE_GET_API(CommandFilterArgInsert);
+    REDISMODULE_GET_API(CommandFilterArgReplace);
+    REDISMODULE_GET_API(CommandFilterArgDelete);
 #endif
 
     if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
index 57a6843..194095d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-./redismodule_ut
+valgrind --leak-check=full ./redismodule_ut
 if [ $? != 0 ]
 then
    exit -1
index 194edc5..c1fe8d1 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nokia.
+ * 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.
  */
 
 #include "redismodule.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
 #include <string.h>
+#include <pthread.h>
 #include <stdbool.h>
-#include "../../redismodule/include/redismodule.h"
 
 #ifdef __UT__
 #include "exstringsStub.h"
+#include "commonStub.h"
 #endif
 
+
 /* make sure the response is not NULL or an error.
 sends the error to the client and exit the current function if its */
 #define  ASSERT_NOERROR(r) \
     if (r == NULL) { \
         return RedisModule_ReplyWithError(ctx,"ERR reply is NULL"); \
     } else if (RedisModule_CallReplyType(r) == REDISMODULE_REPLY_ERROR) { \
-        RedisModule_ReplyWithCallReply(ctx,r); \
-        RedisModule_FreeCallReply(r); \
-        return REDISMODULE_ERR; \
+        return RedisModule_ReplyWithCallReply(ctx,r); \
     }
 
 #define OBJ_OP_NO 0
@@ -48,6 +45,28 @@ sends the error to the client and exit the current function if its */
 #define OBJ_OP_IE (1<<4)     /* OP if equal old value */
 #define OBJ_OP_NE (1<<5)     /* OP if not equal old value */
 
+#define DEF_COUNT     50
+#define ZERO          0
+#define MATCH_STR     "MATCH"
+#define COUNT_STR     "COUNT"
+#define SCANARGC      5
+
+RedisModuleString *def_count_str = NULL, *match_str = NULL, *count_str = NULL, *zero_str = NULL;
+
+void InitStaticVariable()
+{
+    if (def_count_str == NULL)
+        def_count_str = RedisModule_CreateStringFromLongLong(NULL, DEF_COUNT);
+    if (match_str == NULL)
+        match_str = RedisModule_CreateString(NULL, MATCH_STR, sizeof(MATCH_STR));
+    if (count_str == NULL)
+        count_str = RedisModule_CreateString(NULL, COUNT_STR, sizeof(COUNT_STR));
+    if (zero_str == NULL)
+        zero_str = RedisModule_CreateStringFromLongLong(NULL, ZERO);
+
+    return;
+}
+
 int getKeyType(RedisModuleCtx *ctx, RedisModuleString *key_str)
 {
     RedisModuleKey *key = RedisModule_OpenKey(ctx, key_str, REDISMODULE_READ);
@@ -152,11 +171,13 @@ int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
 
 int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    RedisModule_AutoMemory(ctx);
     return setStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
 }
 
 int SetNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    RedisModule_AutoMemory(ctx);
     return setStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
 }
 
@@ -215,136 +236,22 @@ int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
 
 int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    RedisModule_AutoMemory(ctx);
     return delStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
 }
 
 int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    RedisModule_AutoMemory(ctx);
     return delStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
 }
-
-int NGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
-{
-    RedisModuleCallReply *reply = NULL;
-
-    if (argc != 2)
-        return RedisModule_WrongArity(ctx);
-
-    /* Call the command to get keys with pattern. */
-    reply = RedisModule_Call(ctx, "KEYS", "s", argv[1]);
-    ASSERT_NOERROR(reply)
-
-    /* Prepare the arguments for the command. */
-    size_t items = RedisModule_CallReplyLength(reply);
-    if (items == 0) {
-        //RedisModule_ReplyWithArray(ctx, items);
-        RedisModule_ReplyWithCallReply(ctx, reply);
-        RedisModule_FreeCallReply(reply);
-    }
-    else {
-        RedisModuleString *cmdargv[items];
-        size_t i=0, j;
-        for (j = 0; j < items; j++) {
-           RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j));
-           cmdargv[i++] = rms;
-
-           /*Assume all keys via SDL is string type for sake of saving time*/
-#if 0
-           /*Check if key type is string*/
-           RedisModuleKey *key = RedisModule_OpenKey(ctx, rms ,REDISMODULE_READ);
-
-           if (key) {
-               int type = RedisModule_KeyType(key);
-               RedisModule_CloseKey(key);
-               if (type == REDISMODULE_KEYTYPE_STRING) {
-                   cmdargv[i++] = rms;
-               }
-           } else {
-               RedisModule_CloseKey(key);
-           }
-#endif
-        }
-        RedisModule_FreeCallReply(reply);
-
-        reply = RedisModule_Call(ctx, "MGET", "v", cmdargv, i);
-        ASSERT_NOERROR(reply)
-        items = RedisModule_CallReplyLength(reply);
-        RedisModule_ReplyWithArray(ctx, i*2);
-        for (j = 0; (j<items && j<i); j++) {
-           RedisModule_ReplyWithString(ctx, cmdargv[j]);
-           RedisModule_ReplyWithString(ctx, RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j)));
-        }
-
-        RedisModule_FreeCallReply(reply);
-    }
-
-    return REDISMODULE_OK;
-}
-
-int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
-{
-    RedisModuleCallReply *reply = NULL;
-
-    if (argc != 2)
-        return RedisModule_WrongArity(ctx);
-
-    /* Call the command to get keys with pattern. */
-    reply = RedisModule_Call(ctx, "KEYS", "s", argv[1]);
-    ASSERT_NOERROR(reply)
-
-    /* Prepare the arguments for the command. */
-    size_t items = RedisModule_CallReplyLength(reply);
-    if (items == 0) {
-        RedisModule_ReplyWithLongLong(ctx, 0);
-        RedisModule_FreeCallReply(reply);
-    }
-    else {
-        RedisModuleString *cmdargv[items];
-        size_t i=0, j;
-        for (j = 0; j < items; j++) {
-           RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j));
-           cmdargv[i++] = rms;
-
-           /*Assume all keys via SDL is string type for sake of saving time*/
-#if 0
-           //Check if key type is string
-           RedisModuleKey *key = RedisModule_OpenKey(ctx, rms ,REDISMODULE_READ);
-
-           if (key) {
-               int type = RedisModule_KeyType(key);
-               RedisModule_CloseKey(key);
-               if (type == REDISMODULE_KEYTYPE_STRING) {
-                   cmdargv[i++] = rms;
-               }
-           } else {
-               RedisModule_CloseKey(key);
-           }
-#endif
-        }
-        RedisModule_FreeCallReply(reply);
-
-        reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, i);
-        ASSERT_NOERROR(reply)
-        RedisModule_ReplyWithCallReply(ctx, reply);
-        RedisModule_FreeCallReply(reply);
-
-    }
-
-    return REDISMODULE_OK;
-}
-
 int setPubStringCommon(RedisModuleCtx *ctx, SetParams* setParamsPtr, PubParams* pubParamsPtr)
 {
     RedisModuleCallReply *setReply;
     setReply = RedisModule_Call(ctx, "MSET", "v!", setParamsPtr->key_val_pairs, setParamsPtr->length);
     ASSERT_NOERROR(setReply)
-    int replytype = RedisModule_CallReplyType(setReply);
-    if (replytype == REDISMODULE_REPLY_NULL) {
-        RedisModule_ReplyWithNull(ctx);
-    } else {
-        multiPubCommand(ctx, pubParamsPtr);
-        RedisModule_ReplyWithCallReply(ctx, setReply);
-    }
+    multiPubCommand(ctx, pubParamsPtr);
+    RedisModule_ReplyWithCallReply(ctx, setReply);
     RedisModule_FreeCallReply(setReply);
     return REDISMODULE_OK;
 }
@@ -354,12 +261,13 @@ int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
     if (argc < 5 || (argc % 2) == 0)
         return RedisModule_WrongArity(ctx);
 
+    RedisModule_AutoMemory(ctx);
     SetParams setParams = {
                            .key_val_pairs = argv + 1,
                            .length = argc - 3
                           };
     PubParams pubParams = {
-                           .channel_msg_pairs = argv + argc - 2,
+                           .channel_msg_pairs = argv + 1 + setParams.length,
                            .length = 2
                           };
 
@@ -371,6 +279,7 @@ int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
     if (argc < 7 || (argc % 2) == 0)
         return RedisModule_WrongArity(ctx);
 
+    RedisModule_AutoMemory(ctx);
     long long setPairsCount, pubPairsCount;
     RedisModule_StringToLongLong(argv[1], &setPairsCount);
     RedisModule_StringToLongLong(argv[2], &pubPairsCount);
@@ -380,6 +289,7 @@ int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
     long long setLen, pubLen;
     setLen = 2*setPairsCount;
     pubLen = 2*pubPairsCount;
+
     if (setLen + pubLen + 3 != argc)
         return RedisModule_ReplyWithError(ctx, "ERR SET_PAIR_COUNT or PUB_PAIR_COUNT do not match the total pair count");
 
@@ -397,9 +307,6 @@ int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
 
 int setIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
 {
-    if (argc < 6 || (argc % 2) != 0)
-        return RedisModule_WrongArity(ctx);
-
     SetParams setParams = {
                            .key_val_pairs = argv + 1,
                            .length = 2
@@ -430,21 +337,35 @@ int setIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int ar
     return setPubStringCommon(ctx, &setParams, &pubParams);
 }
 
-int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-    return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
+    if (argc != 6)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
+    return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
 }
 
-int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+int SetIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    if (argc < 6 || (argc % 2) != 0)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
     return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
 }
 
-int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
+int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-    if (argc < 5 || (argc % 2) == 0)
+    if (argc != 6)
         return RedisModule_WrongArity(ctx);
 
+    RedisModule_AutoMemory(ctx);
+    return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
+}
+
+int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
+{
     SetParams setParams = {
                            .key_val_pairs = argv + 1,
                            .length = 2
@@ -469,11 +390,28 @@ int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int ar
 
 int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    if (argc != 5)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
+    return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
+}
+
+int SetNXMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+    if (argc < 5 || (argc % 2) == 0)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
     return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
 }
 
 int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
+    if (argc != 5)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
     return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_XX);
 }
 
@@ -499,6 +437,7 @@ int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
     if (argc < 4)
         return RedisModule_WrongArity(ctx);
 
+    RedisModule_AutoMemory(ctx);
     DelParams delParams = {
                            .keys = argv + 1,
                            .length = argc - 3
@@ -516,6 +455,7 @@ int DelMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
     if (argc < 6)
         return RedisModule_WrongArity(ctx);
 
+    RedisModule_AutoMemory(ctx);
     long long delCount, pubPairsCount;
     RedisModule_StringToLongLong(argv[1], &delCount);
     RedisModule_StringToLongLong(argv[2], &pubPairsCount);
@@ -542,9 +482,6 @@ int DelMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
 
 int delIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
 {
-    if (argc < 5 || (argc % 2) == 0)
-        return RedisModule_WrongArity(ctx);
-
     DelParams delParams = {
                            .keys = argv + 1,
                            .length = 1
@@ -577,12 +514,29 @@ int delIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int ar
 
 int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-   return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
+    if (argc != 5)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
+    return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
+}
+
+int DelIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+    if (argc < 5 || (argc % 2) == 0)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
+    return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
 }
 
 int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-   return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
+    if (argc != 5)
+        return RedisModule_WrongArity(ctx);
+
+    RedisModule_AutoMemory(ctx);
+    return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
 }
 
 /* This function must be present on each Redis module. It is used in order to
@@ -610,14 +564,6 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
         DelNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
 
-    if (RedisModule_CreateCommand(ctx,"nget",
-        NGet_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
-        return REDISMODULE_ERR;
-
-    if (RedisModule_CreateCommand(ctx,"ndel",
-        NDel_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;
@@ -630,6 +576,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
         SetIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
 
+    if (RedisModule_CreateCommand(ctx,"setiempub",
+        SetIEMPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+        return REDISMODULE_ERR;
+
     if (RedisModule_CreateCommand(ctx,"setnepub",
         SetNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
@@ -642,6 +592,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
         SetNXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
 
+    if (RedisModule_CreateCommand(ctx,"setnxmpub",
+        SetNXMPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+        return REDISMODULE_ERR;
+
     if (RedisModule_CreateCommand(ctx,"delpub",
         DelPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
@@ -654,6 +608,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
         DelIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
 
+    if (RedisModule_CreateCommand(ctx,"deliempub",
+        DelIEMPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
+        return REDISMODULE_ERR;
+
     if (RedisModule_CreateCommand(ctx,"delnepub",
         DelNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
diff --git a/redismodule/tst/mock/include/commonStub.h b/redismodule/tst/mock/include/commonStub.h
new file mode 100644 (file)
index 0000000..dc87fa7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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).
+ */
+
+#ifndef COMMONSTUB_H_
+#define COMMONSTUB_H_
+
+
+#include <pthread.h>
+
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                   void *(*start_routine) (void *), void *arg);
+
+
+#endif
index 572f64c..756e5de 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nokia.
+ * 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.
@@ -28,7 +28,6 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
-#include "../../../../redismodule/tst/mock/include/redismodule.h"
 
 int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
 int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
@@ -40,15 +39,15 @@ int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+int SetNXMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 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 NGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
-int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
-
 
 #endif
index 3e9b93b..414bdc7 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nokia.
+ * 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.
 #include <stdint.h>
 #include <stdio.h>
 
-/* ---------------- Defines common between core and modules --------------- */
-
-
-
-
 /* Error status return values. */
 #define REDISMODULE_OK 0
 #define REDISMODULE_ERR 1
@@ -42,9 +37,6 @@
 #define REDISMODULE_READ (1<<0)
 #define REDISMODULE_WRITE (1<<1)
 
-#define REDISMODULE_LIST_HEAD 0
-#define REDISMODULE_LIST_TAIL 1
-
 /* Key types. */
 #define REDISMODULE_KEYTYPE_EMPTY 0
 #define REDISMODULE_KEYTYPE_STRING 1
 /* Postponed array length. */
 #define REDISMODULE_POSTPONED_ARRAY_LEN -1
 
-/* Expire */
-#define REDISMODULE_NO_EXPIRE -1
-
-/* Sorted set API flags. */
-#define REDISMODULE_ZADD_XX      (1<<0)
-#define REDISMODULE_ZADD_NX      (1<<1)
-#define REDISMODULE_ZADD_ADDED   (1<<2)
-#define REDISMODULE_ZADD_UPDATED (1<<3)
-#define REDISMODULE_ZADD_NOP     (1<<4)
-
-/* Hash API flags. */
-#define REDISMODULE_HASH_NONE       0
-#define REDISMODULE_HASH_NX         (1<<0)
-#define REDISMODULE_HASH_XX         (1<<1)
-#define REDISMODULE_HASH_CFIELDS    (1<<2)
-#define REDISMODULE_HASH_EXISTS     (1<<3)
-
-/* Context Flags: Info about the current context returned by RM_GetContextFlags */
-
-/* The command is running in the context of a Lua script */
-#define REDISMODULE_CTX_FLAGS_LUA 0x0001
-/* The command is running inside a Redis transaction */
-#define REDISMODULE_CTX_FLAGS_MULTI 0x0002
-/* The instance is a master */
-#define REDISMODULE_CTX_FLAGS_MASTER 0x0004
-/* The instance is a slave */
-#define REDISMODULE_CTX_FLAGS_SLAVE 0x0008
-/* The instance is read-only (usually meaning it's a slave as well) */
-#define REDISMODULE_CTX_FLAGS_READONLY 0x0010
-/* The instance is running in cluster mode */
-#define REDISMODULE_CTX_FLAGS_CLUSTER 0x0020
-/* The instance has AOF enabled */
-#define REDISMODULE_CTX_FLAGS_AOF 0x0040 //
-/* The instance has RDB enabled */
-#define REDISMODULE_CTX_FLAGS_RDB 0x0080 //
-/* The instance has Maxmemory set */
-#define REDISMODULE_CTX_FLAGS_MAXMEMORY 0x0100
-/* Maxmemory is set and has an eviction policy that may delete keys */
-#define REDISMODULE_CTX_FLAGS_EVICT 0x0200
-
-
-/* A special pointer that we can use between the core and the module to signal
- * field deletion, and that is impossible to be a valid pointer. */
-#define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1)
-
 /* Error messages. */
 #define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
 
-#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
-#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
-
 #define REDISMODULE_NOT_USED(V) ((void) V)
 
-/* ------------------------- End of common defines ------------------------ */
-
-
-
-
-#ifndef REDISMODULE_CORE
-
-
-
 typedef long long mstime_t;
 
-/* Incomplete structures for compiler checks but opaque access. */
-typedef struct RedisModuleCtx RedisModuleCtx;
-typedef struct RedisModuleKey RedisModuleKey;
-typedef struct RedisModuleString RedisModuleString;
-typedef struct RedisModuleCallReply RedisModuleCallReply;
-typedef struct RedisModuleIO RedisModuleIO;
-typedef struct RedisModuleType RedisModuleType;
-typedef struct RedisModuleDigest RedisModuleDigest;
-typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
-
-//typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
+/* UT dummy definitions for opaque redis types */
+typedef struct { int dummy; } RedisModuleCtx;
+typedef struct { int dummy; } RedisModuleKey;
+typedef struct { int dummy; } RedisModuleString;
+typedef struct { int dummy; } RedisModuleCallReply;
+typedef struct { int dummy; } RedisModuleIO;
+typedef struct { int dummy; } RedisModuleType;
+typedef struct { int dummy; } RedisModuleDigest;
+typedef struct { int dummy; } RedisModuleBlockedClient;
 
 typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
 typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
@@ -148,209 +81,8 @@ typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
 typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
 typedef void (*RedisModuleTypeFreeFunc)(void *value);
 
-#define REDISMODULE_TYPE_METHOD_VERSION 1
-typedef struct RedisModuleTypeMethods {
-    uint64_t version;
-    RedisModuleTypeLoadFunc rdb_load;
-    RedisModuleTypeSaveFunc rdb_save;
-    RedisModuleTypeRewriteFunc aof_rewrite;
-    RedisModuleTypeMemUsageFunc mem_usage;
-    RedisModuleTypeDigestFunc digest;
-    RedisModuleTypeFreeFunc free;
-} RedisModuleTypeMethods;
-
-#define REDISMODULE_GET_API(name) \
-    RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
-
-#define REDISMODULE_API_FUNC(x) (*x)
-
-#if 1
-
-
-typedef struct redisObject {
-    unsigned type:4;
-    unsigned encoding:4;
-    int refcount;
-    void *ptr;
-} robj;
-/* This structure represents a module inside the system. */
-struct RedisModule {
-    void *handle;   /* Module dlopen() handle. */
-    char *name;     /* Module name. */
-    int ver;        /* Module version. We use just progressive integers. */
-    int apiver;     /* Module API version as requested during initialization.*/
-    //list *types;    /* Module data types. */
-};
-typedef struct RedisModule RedisModule;
-
-//static dict *modules; /* Hash table of modules. SDS -> RedisModule ptr.*/
-
-/* Entries in the context->amqueue array, representing objects to free
- * when the callback returns. */
-struct AutoMemEntry {
-    void *ptr;
-    int type;
-};
-
-/* AutMemEntry type field values. */
-#define REDISMODULE_AM_KEY 0
-#define REDISMODULE_AM_STRING 1
-#define REDISMODULE_AM_REPLY 2
-#define REDISMODULE_AM_FREED 3 /* Explicitly freed by user already. */
-
-/* The pool allocator block. Redis Modules can allocate memory via this special
- * allocator that will automatically release it all once the callback returns.
- * This means that it can only be used for ephemeral allocations. However
- * there are two advantages for modules to use this API:
- *
- * 1) The memory is automatically released when the callback returns.
- * 2) This allocator is faster for many small allocations since whole blocks
- *    are allocated, and small pieces returned to the caller just advancing
- *    the index of the allocation.
- *
- * Allocations are always rounded to the size of the void pointer in order
- * to always return aligned memory chunks. */
-
-#define REDISMODULE_POOL_ALLOC_MIN_SIZE (1024*8)
-#define REDISMODULE_POOL_ALLOC_ALIGN (sizeof(void*))
-
-typedef struct RedisModulePoolAllocBlock {
-    uint32_t size;
-    uint32_t used;
-    struct RedisModulePoolAllocBlock *next;
-    char memory[];
-} RedisModulePoolAllocBlock;
-
-/* This structure represents the context in which Redis modules operate.
- * Most APIs module can access, get a pointer to the context, so that the API
- * implementation can hold state across calls, or remember what to free after
- * the call and so forth.
- *
- * Note that not all the context structure is always filled with actual values
- * but only the fields needed in a given context. */
-
-struct RedisModuleBlockedClient;
-
-struct RedisModuleCtx {
-    void *getapifuncptr;            /* NOTE: Must be the first field. */
-    struct RedisModule *module;     /* Module reference. */
-    //client *client;                 /* Client calling a command. */
-    struct RedisModuleBlockedClient *blocked_client; /* Blocked client for
-                                                        thread safe context. */
-    struct AutoMemEntry *amqueue;   /* Auto memory queue of objects to free. */
-    int amqueue_len;                /* Number of slots in amqueue. */
-    int amqueue_used;               /* Number of used slots in amqueue. */
-    int flags;                      /* REDISMODULE_CTX_... flags. */
-    void **postponed_arrays;        /* To set with RM_ReplySetArrayLength(). */
-    int postponed_arrays_count;     /* Number of entries in postponed_arrays. */
-    void *blocked_privdata;         /* Privdata set when unblocking a client. */
-
-    /* Used if there is the REDISMODULE_CTX_KEYS_POS_REQUEST flag set. */
-    int *keys_pos;
-    int keys_count;
-
-    struct RedisModulePoolAllocBlock *pa_head;
-};
-typedef struct RedisModuleCtx RedisModuleCtx;
-
-#define REDISMODULE_CTX_INIT {(void*)(unsigned long)&RM_GetApi, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL, NULL, 0, NULL}
-#define REDISMODULE_CTX_MULTI_EMITTED (1<<0)
-#define REDISMODULE_CTX_AUTO_MEMORY (1<<1)
-#define REDISMODULE_CTX_KEYS_POS_REQUEST (1<<2)
-#define REDISMODULE_CTX_BLOCKED_REPLY (1<<3)
-#define REDISMODULE_CTX_BLOCKED_TIMEOUT (1<<4)
-#define REDISMODULE_CTX_THREAD_SAFE (1<<5)
-
-/* This represents a Redis key opened with RM_OpenKey(). */
-struct RedisModuleKey {
-    RedisModuleCtx *ctx;
-    //redisDb *db;
-    robj *key;      /* Key name object. */
-    robj *value;    /* Value object, or NULL if the key was not found. */
-    void *iter;     /* Iterator. */
-    int mode;       /* Opening mode. */
-
-    /* Zset iterator. */
-    uint32_t ztype;         /* REDISMODULE_ZSET_RANGE_* */
-    //zrangespec zrs;         /* Score range. */
-    //zlexrangespec zlrs;     /* Lex range. */
-    uint32_t zstart;        /* Start pos for positional ranges. */
-    uint32_t zend;          /* End pos for positional ranges. */
-    void *zcurrent;         /* Zset iterator current node. */
-    int zer;                /* Zset iterator end reached flag
-                               (true if end was reached). */
-};
-typedef struct RedisModuleKey RedisModuleKey;
-
-/* RedisModuleKey 'ztype' values. */
-#define REDISMODULE_ZSET_RANGE_NONE 0       /* This must always be 0. */
-#define REDISMODULE_ZSET_RANGE_LEX 1
-#define REDISMODULE_ZSET_RANGE_SCORE 2
-#define REDISMODULE_ZSET_RANGE_POS 3
-
-/* Function pointer type of a function representing a command inside
- * a Redis module. */
-
 typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 
-
-/* This struct holds the information about a command registered by a module.*/
-struct RedisModuleCommandProxy {
-    struct RedisModule *module;
-    RedisModuleCmdFunc func;
-    struct redisCommand *rediscmd;
-};
-typedef struct RedisModuleCommandProxy RedisModuleCommandProxy;
-
-#define REDISMODULE_REPLYFLAG_NONE 0
-#define REDISMODULE_REPLYFLAG_TOPARSE (1<<0) /* Protocol must be parsed. */
-#define REDISMODULE_REPLYFLAG_NESTED (1<<1)  /* Nested reply object. No proto
-                                                or struct free. */
-
-/* Reply of RM_Call() function. The function is filled in a lazy
- * way depending on the function called on the reply structure. By default
- * only the type, proto and protolen are filled. */
-typedef struct RedisModuleCallReply {
-    RedisModuleCtx *ctx;
-    int type;       /* REDISMODULE_REPLY_... */
-    int flags;      /* REDISMODULE_REPLYFLAG_...  */
-    size_t len;     /* Len of strings or num of elements of arrays. */
-    char *proto;    /* Raw reply protocol. An SDS string at top-level object. */
-    size_t protolen;/* Length of protocol. */
-    union {
-        const char *str; /* String pointer for string and error replies. This
-                            does not need to be freed, always points inside
-                            a reply->proto buffer of the reply object or, in
-                            case of array elements, of parent reply objects. */
-        long long ll;    /* Reply value for integer reply. */
-        struct RedisModuleCallReply *array; /* Array of sub-reply elements. */
-    } val;
-} RedisModuleCallReply;
-
-/* Structure representing a blocked client. We get a pointer to such
- * an object when blocking from modules. */
-typedef struct RedisModuleBlockedClient {
-    //client *client;  /* Pointer to the blocked client. or NULL if the client
-     //                   was destroyed during the life of this object. */
-    RedisModule *module;    /* Module blocking the client. */
-    RedisModuleCmdFunc reply_callback; /* Reply callback on normal completion.*/
-    RedisModuleCmdFunc timeout_callback; /* Reply callback on timeout. */
-    void (*free_privdata)(void *);       /* privdata cleanup callback. */
-    void *privdata;     /* Module private data that may be used by the reply
-                           or timeout callback. It is set via the
-                           RedisModule_UnblockClient() API. */
-    //client *reply_client;           /* Fake client used to accumulate replies
-   //                                    in thread safe contexts. */
-    int dbid;           /* Database number selected by the original client. */
-} RedisModuleBlockedClient;
-
-#define RedisModuleString robj
-
-#endif
-
-
-
-
 int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
 int RedisModule_WrongArity(RedisModuleCtx *ctx);
 int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll);
@@ -366,27 +98,29 @@ int RedisModule_ReplyWithNull(RedisModuleCtx *ctx);
 int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
 const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len);
 RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply);
-int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll);
 
 int RedisModule_KeyType(RedisModuleKey *kp);
 void RedisModule_CloseKey(RedisModuleKey *kp);
 
-/* This is included inline inside each Redis module. */
 int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
 
 size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply);
 RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx);
 int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len);
-
-
-/* Things only defined for the modules core, not exported to modules
- * including this file. */
-
-#else
-
-/* Things only defined for the modules core, not exported to modules
- * including this file. */
-#define RedisModuleString robj
-
-#endif /* REDISMODULE_CORE */
-#endif /* REDISMOUDLE_H */
+void RedisModule_FreeString(RedisModuleCtx *ctx, RedisModuleString *str);
+RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms);
+int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata);
+int RedisModule_AbortBlock(RedisModuleBlockedClient *bc);
+RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len);
+void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx);
+int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll);
+void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx);
+void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx);
+void RedisModule_ReplySetArrayLength(RedisModuleCtx *ctx, long len);
+RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc);
+RedisModuleString *RedisModule_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll);
+void RedisModule_AutoMemory(RedisModuleCtx *ctx);
+void *RedisModule_Alloc(size_t bytes);
+void RedisModule_Free(void *ptr);
+
+#endif /* REDISMODULE_H */
diff --git a/redismodule/tst/mock/src/commonStub.cpp b/redismodule/tst/mock/src/commonStub.cpp
new file mode 100644 (file)
index 0000000..2df1df9
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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).
+ */
+
+
+#include <unistd.h>
+#include <string.h>
+
+extern "C" {
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "redismodule.h"
+#include "commonStub.h"
+}
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include <CppUTest/MemoryLeakDetectorMallocMacros.h>
+
+typedef struct RedisModuleBlockedClientArgs {
+    RedisModuleBlockedClient *bc;
+    RedisModuleString **argv;
+    int argc;
+} RedisModuleBlockedClientArgs;
+
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                   void *(*start_routine) (void *), void *arg)
+{
+    (void)thread;
+    (void)attr;
+    (void)start_routine;
+    if (mock().getData("pthread_create_free_block_client_args").getIntValue()) {
+        RedisModuleBlockedClientArgs* bca = (RedisModuleBlockedClientArgs*)arg;
+        free(bca->bc);
+        free(bca);
+    }
+
+    return mock()
+        .actualCall("pthread_create")
+        .returnIntValueOrDefault(0);
+}
index 029c48b..bfcdb22 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nokia.
+ * 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.
  */
 
 
-#include <CppUTest/TestHarness.h>
-#include <CppUTestExt/MockSupport.h>
 #include <unistd.h>
 #include <string.h>
 
-
-
-
 extern "C" {
 #include "redismodule.h"
 #include <stdio.h>
@@ -35,6 +30,9 @@ extern "C" {
 #include <ctype.h>
 }
 
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
 
 int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep)
 {
@@ -52,6 +50,7 @@ int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModule
 int RedisModule_WrongArity(RedisModuleCtx *ctx)
 {
     (void)ctx;
+    mock().setData("RedisModule_WrongArity", 1);
     return REDISMODULE_ERR;
 }
 
@@ -105,6 +104,8 @@ RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname,
         mock().setData("KEYS", 1);
     else if (!strcmp(cmdname, "MGET"))
         mock().setData("MGET", 1);
+    else if (!strcmp(cmdname, "SCAN"))
+        mock().setData("SCAN", 1);
 
     if (mock().hasData("RedisModule_Call_Return_Null"))
         return NULL;
@@ -157,7 +158,7 @@ const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len)
 {
 
     (void)str;
-    *len = 5;
+    if (len) *len = 5;
     if (mock().hasData("RedisModule_String_same"))
     {
         return "11111";
@@ -168,6 +169,17 @@ const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len)
         return "22222";
     }
 
+    if (mock().hasData("RedisModule_String_count"))
+    {
+        return "COUNT";
+    }
+
+    if (mock().hasData("RedisModule_String_count1"))
+    {
+        if (len) *len = 6;
+        return "COUNT1";
+    }
+
     return "11111";
 }
 
@@ -207,17 +219,17 @@ const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *
 {
     (void)reply;
 
-    *len = 5;
-
     if (mock().hasData("RedisModule_String_same"))
     {
+        if (len)
+            *len = 5;
         return "11111";
     }
 
-
     if (mock().hasData("RedisModule_String_nosame"))
     {
-        *len = 6;
+        if (len)
+            *len = 6;
         return "333333";
     }
 
@@ -294,9 +306,62 @@ int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len)
     return REDISMODULE_OK;
 }
 
+void RedisModule_FreeString(RedisModuleCtx *ctx, RedisModuleString *str)
+{
+    (void)ctx;
+    (void)str;
+    mock().setData("RedisModule_FreeString", mock().getData("RedisModule_FreeString").getIntValue()+1);
+    return;
+}
+
+RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms)
+{
+    (void)ctx;
+    (void)reply_callback;
+    (void)timeout_callback;
+    (void)free_privdata;
+    (void)timeout_ms;
+    RedisModuleBlockedClient *bc = (RedisModuleBlockedClient*)malloc(sizeof(RedisModuleBlockedClient));
+    mock().setData("RedisModule_BlockClient", 1);
+    return bc;
+}
+
+int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata)
+{
+    (void)privdata;
+    free(bc);
+    mock().setData("RedisModule_UnblockClient", mock().getData("RedisModule_UnblockClient").getIntValue()+1);
+    return REDISMODULE_OK;
+}
+
+int RedisModule_AbortBlock(RedisModuleBlockedClient *bc)
+{
+    free(bc);
+    mock().setData("RedisModule_AbortBlock", 1);
+    return REDISMODULE_OK;
+}
+
+RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len)
+{
+    (void)ctx;
+    (void)ptr;
+    (void)len;
+    RedisModuleString *rms = (RedisModuleString*)malloc(sizeof(RedisModuleString));
+    mock().setData("RedisModule_CreateString", mock().getData("RedisModule_CreateString").getIntValue()+1);
+    return rms;
+}
+
+void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx)
+{
+    (void)ctx;
+    mock().setData("RedisModule_FreeThreadSafeContext", 1);
+    return;
+}
+
 int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll)
 {
-    (void) str;
+    (void)str;
+
     int call_no = mock().getData("RedisModule_StringToLongLongCallCount").getIntValue();
     switch(call_no) {
         case 0:
@@ -311,3 +376,62 @@ int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll)
     mock().setData("RedisModule_StringToLongLongCallCount", call_no + 1);
     return REDISMODULE_OK;
 }
+
+void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx)
+{
+    (void)ctx;
+    mock().setData("RedisModule_ThreadSafeContextLock", 1);
+    return;
+}
+
+void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx)
+{
+    (void)ctx;
+    mock().setData("RedisModule_ThreadSafeContextUnlock", 1);
+    return;
+}
+
+void RedisModule_ReplySetArrayLength(RedisModuleCtx *ctx, long len)
+{
+    (void)ctx;
+    mock().setData("RedisModule_ReplySetArrayLength", (int)len);
+    return;
+}
+
+RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc)
+{
+    (void) bc;
+    mock().setData("RedisModule_GetThreadSafeContext", 1);
+    return NULL;
+}
+
+RedisModuleString *RedisModule_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll)
+{
+    (void)ctx;
+    (void)ll;
+    RedisModuleString *rms = (RedisModuleString*)malloc(sizeof(RedisModuleString));
+    mock().setData("RedisModule_CreateStringFromLongLong", mock().getData("RedisModule_CreateStringFromLongLong").getIntValue()+1);
+    return rms;
+}
+
+void RedisModule_AutoMemory(RedisModuleCtx *ctx)
+{
+    (void)ctx;
+    int old = mock().getData("RedisModule_AutoMemory").getIntValue();
+    mock().setData("RedisModule_AutoMemory", old + 1);
+    return;
+}
+
+void *RedisModule_Alloc(size_t bytes)
+{
+    mock()
+        .actualCall("RedisModule_Alloc");
+    return malloc(bytes);
+}
+
+void RedisModule_Free(void *ptr)
+{
+    mock()
+        .actualCall("RedisModule_Free");
+    free(ptr);
+}
index 4816de5..d239eea 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nokia.
+ * 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.
  * platform project (RICP).
  */
 
-#include <string>
-#include <map>
-#include <list>
-#include <set>
-#include <vector>
-#include <syslog.h>
-
-
-//#include <stdio.h>
-//#include <stdlib.h>
-//#include <ctype.h>
-
 
 extern "C" {
 #include "exstringsStub.h"
@@ -46,6 +34,11 @@ extern "C" {
 #define OBJ_OP_IE (1<<4)     /* OP if equal old value */
 #define OBJ_OP_NE (1<<5)     /* OP if not equal old value */
 
+typedef struct RedisModuleBlockedClientArgs {
+    RedisModuleBlockedClient *bc;
+    RedisModuleString **argv;
+    int argc;
+} RedisModuleBlockedClientArgs;
 
 TEST_GROUP(exstring)
 {
@@ -88,6 +81,7 @@ TEST(exstring, setie)
 
     int ret = SetIE_RedisCommand(&ctx, redisStrVec,  4);
     CHECK_EQUAL(ret, 0);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
     delete []redisStrVec;
 }
 
@@ -106,6 +100,7 @@ TEST(exstring, setne)
     mock().setData("RedisModule_String_same", 1);
     int ret = SetNE_RedisCommand(&ctx,redisStrVec, 4);
     CHECK_EQUAL(ret, 0);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
     delete []redisStrVec;
 }
 
@@ -266,6 +261,7 @@ TEST(exstring, delie)
     int ret = DelIE_RedisCommand(&ctx, redisStrVec,  3);
     CHECK_EQUAL(ret, 0);
     mock().checkExpectations();
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
     delete []redisStrVec;
 }
 
@@ -285,6 +281,7 @@ TEST(exstring, delne)
     int ret = DelNE_RedisCommand(&ctx,redisStrVec, 3);
     CHECK_EQUAL(ret, 0);
     mock().checkExpectations();
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
     delete []redisStrVec;
 }
 
@@ -446,144 +443,6 @@ TEST(exstring, delne_command_key_string_nosame_reply)
 
 }
 
-TEST(exstring, setpub)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
-
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)1;
-    redisStrVec[3] = (RedisModuleString *)1;
-    redisStrVec[4] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_OpenKey_have", 1);
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    int ret = SetPub_RedisCommand(&ctx, redisStrVec,  5);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    delete []redisStrVec;
-}
-
-TEST(exstring, setmpub)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[11]);
-
-    for (int i = 0 ; i < 11 ; ++i)
-        redisStrVec[i] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_OpenKey_have", 1);
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-    mock().setData("RedisModule_StringToLongLongCallCount", 0);
-    mock().setData("RedisModule_StringToLongLongCall_1", 2);
-    mock().setData("RedisModule_StringToLongLongCall_2", 2);
-
-    int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 11);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    delete []redisStrVec;
-}
-
-TEST(exstring, setxxpub)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
-
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)1;
-    redisStrVec[3] = (RedisModuleString *)1;
-    redisStrVec[4] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_OpenKey_have", 1);
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = SetXXPub_RedisCommand(&ctx, redisStrVec,  5);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    delete []redisStrVec;
-}
-
-TEST(exstring, setnxpub)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
-
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)1;
-    redisStrVec[3] = (RedisModuleString *)1;
-    redisStrVec[4] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_OpenKey_have", 1);
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = SetNXPub_RedisCommand(&ctx, redisStrVec,  5);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    delete []redisStrVec;
-}
-
-TEST(exstring, setiepub)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
-
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)1;
-    redisStrVec[3] = (RedisModuleString *)1;
-    redisStrVec[4] = (RedisModuleString *)1;
-    redisStrVec[5] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_OpenKey_have", 1);
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = SetIEPub_RedisCommand(&ctx, redisStrVec,  6);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    delete []redisStrVec;
-}
-
-TEST(exstring, setnepub)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
-
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)1;
-    redisStrVec[3] = (RedisModuleString *)1;
-    redisStrVec[4] = (RedisModuleString *)1;
-    redisStrVec[5] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_OpenKey_have", 1);
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = SetNEPub_RedisCommand(&ctx, redisStrVec,  6);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    delete []redisStrVec;
-}
-
 TEST(exstring, setpub_command_parameter_number_incorrect)
 {
     RedisModuleCtx ctx;
@@ -616,6 +475,10 @@ TEST(exstring, setpub_command_parameter_number_incorrect)
     ret = SetNXPub_RedisCommand(&ctx, 0, 3);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
+    ret = 0;
+    ret = SetNXMPub_RedisCommand(&ctx, 0, 3);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
     ret = 0;
     ret = SetNXPub_RedisCommand(&ctx, 0, 6);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
@@ -624,6 +487,10 @@ TEST(exstring, setpub_command_parameter_number_incorrect)
     ret = SetIEPub_RedisCommand(&ctx, 0, 4);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
+    ret = 0;
+    ret = SetIEMPub_RedisCommand(&ctx, 0, 4);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
     ret = 0;
     ret = SetIEPub_RedisCommand(&ctx, 0, 9);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
@@ -637,32 +504,6 @@ TEST(exstring, setpub_command_parameter_number_incorrect)
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 }
 
-TEST(exstring, setpub_command_no_key_replynull)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
-
-    redisStrVec[0] = (RedisModuleString *)0;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)2;
-    redisStrVec[3] = (RedisModuleString *)3;
-    redisStrVec[4] = (RedisModuleString *)4;
-
-    mock().setData("RedisModule_KeyType_empty", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
-    CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
-
-    delete []redisStrVec;
-
-}
-
 TEST(exstring, setpub_command_no_key_replystr)
 {
     RedisModuleCtx ctx;
@@ -684,38 +525,7 @@ TEST(exstring, setpub_command_no_key_replystr)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
-
-    delete []redisStrVec;
-
-}
-
-TEST(exstring, setmpub_command_no_key_replynull)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[9]);
-
-    redisStrVec[0] = (RedisModuleString *)0;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)2;
-    redisStrVec[3] = (RedisModuleString *)3;
-    redisStrVec[4] = (RedisModuleString *)4;
-    redisStrVec[5] = (RedisModuleString *)5;
-    redisStrVec[6] = (RedisModuleString *)6;
-    redisStrVec[7] = (RedisModuleString *)7;
-    redisStrVec[8] = (RedisModuleString *)8;
-
-    mock().setData("RedisModule_KeyType_empty", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-    mock().setData("RedisModule_StringToLongLongCall_1", 1);
-    mock().setData("RedisModule_StringToLongLongCall_2", 2);
-
-    int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 9);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
-    CHECK_EQUAL(1, mock().getData("MSET").getIntValue());
-    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
-    CHECK_EQUAL(1, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -747,6 +557,7 @@ TEST(exstring, setmpub_command_negative_key_val_count)
     CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
     CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
     CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -778,6 +589,7 @@ TEST(exstring, setmpub_command_negative_chan_msg_count)
     CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
     CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
     CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -809,6 +621,7 @@ TEST(exstring, setmpub_command_invalid_total_count)
     CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
     CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
     CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -839,6 +652,7 @@ TEST(exstring, setmpub_command_set)
     CHECK_EQUAL(1, mock().getData("MSET").getIntValue());
     CHECK_EQUAL(1, mock().getData("PUBLISH").getIntValue());
     CHECK_EQUAL(2, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -871,6 +685,7 @@ TEST(exstring, setmpub_command_set_multipub)
     CHECK_EQUAL(1, mock().getData("MSET").getIntValue());
     CHECK_EQUAL(2, mock().getData("PUBLISH").getIntValue());
     CHECK_EQUAL(3, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -900,6 +715,7 @@ TEST(exstring, setxxpub_command_has_no_key)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -928,6 +744,7 @@ TEST(exstring, setxxpub_command_parameter_has_key_set)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -957,6 +774,7 @@ TEST(exstring, setxxpub_command_has_key_string)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -987,6 +805,7 @@ TEST(exstring, setnxpub_command_has_key_string)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -1016,6 +835,7 @@ TEST(exstring, setnxpub_command_has_no_key)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -1048,6 +868,7 @@ TEST(exstring, setiepub_command_has_no_key)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -1080,37 +901,7 @@ TEST(exstring, setiepub_command_key_string_nosame)
     CHECK_EQUAL(mock().getData("MSET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
-
-    delete []redisStrVec;
-
-}
-
-TEST(exstring, setiepub_command_key_same_string_replynull)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[6]);
-
-    redisStrVec[0] = (RedisModuleString *)0;
-    redisStrVec[1] = (RedisModuleString *)1;
-    redisStrVec[2] = (RedisModuleString *)2;
-    redisStrVec[3] = (RedisModuleString *)3;
-    redisStrVec[4] = (RedisModuleString *)4;
-    redisStrVec[5] = (RedisModuleString *)5;
-
-    mock().setData("RedisModule_KeyType_str", 1);
-    mock().setData("RedisModule_String_same", 1);
-    mock().setData("RedisModule_CallReplyType_null", 1);
-
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
-
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    mock().checkExpectations();
-    CHECK_EQUAL(mock().getData("GET").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("MSET").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_ReplyWithNull").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -1142,6 +933,7 @@ TEST(exstring, setiepub_command_key_same_string_reply)
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -1173,6 +965,7 @@ TEST(exstring, setnepub_command_has_no_key)
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 3);
+    CHECK_EQUAL(mock().getData("RedisModule_AutoMemory").getIntValue(),1);
 
     delete []redisStrVec;
 
@@ -1313,6 +1106,29 @@ TEST(exstring, deliepub)
     delete []redisStrVec;
 }
 
+TEST(exstring, deliempub)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString ** redisStrVec = new (RedisModuleString*[5]);
+
+    redisStrVec[0] = (RedisModuleString *)1;
+    redisStrVec[1] = (RedisModuleString *)1;
+    redisStrVec[2] = (RedisModuleString *)1;
+    redisStrVec[3] = (RedisModuleString *)1;
+    redisStrVec[4] = (RedisModuleString *)1;
+
+    mock().setData("RedisModule_OpenKey_have", 1);
+    mock().setData("RedisModule_KeyType_str", 1);
+    mock().setData("RedisModule_String_same", 1);
+    mock().setData("RedisModule_CallReplyType_null", 1);
+
+    mock().expectOneCall("RedisModule_CloseKey");
+    int ret = DelIEMPub_RedisCommand(&ctx, redisStrVec,  5);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
+    mock().checkExpectations();
+    delete []redisStrVec;
+}
+
 TEST(exstring, delnepub)
 {
     RedisModuleCtx ctx;
@@ -1351,6 +1167,10 @@ TEST(exstring, delpub_command_parameter_number_incorrect)
     ret = DelIEPub_RedisCommand(&ctx, 0, 4);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
+    ret = 0;
+    ret = DelIEMPub_RedisCommand(&ctx, 0, 4);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
     ret = 0;
     ret = DelNEPub_RedisCommand(&ctx, 0, 8);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
@@ -1396,12 +1216,12 @@ TEST(exstring, delpub_command_reply_error)
     mock().setData("RedisModule_CallReplyType_err", 1);
 
     int ret = DelPub_RedisCommand(&ctx, redisStrVec, 5);
-    CHECK_EQUAL(ret, REDISMODULE_ERR);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
     delete []redisStrVec;
 
@@ -1479,12 +1299,12 @@ TEST(exstring, delmpub_command_reply_error)
     mock().setData("RedisModule_StringToLongLongCall_2", 1);
 
     int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
-    CHECK_EQUAL(ret, REDISMODULE_ERR);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
     CHECK_EQUAL(mock().getData("PUBLISH").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
+    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
     delete []redisStrVec;
 
@@ -1869,100 +1689,3 @@ TEST(exstring, delnepub_command_nosame_string_reply)
 
     delete []redisStrVec;
 }
-
-TEST(exstring, nget_command_parameter_number_incorrect)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-
-    int ret = NGet_RedisCommand(&ctx, redisStrVec,  3);
-    CHECK_EQUAL(ret, REDISMODULE_ERR);
-
-    delete []redisStrVec;
-}
-
-TEST(exstring, nget_command_zero_item)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_CallReplyLength", 0);
-    int ret = NGet_RedisCommand(&ctx, redisStrVec,  2);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
-
-    delete []redisStrVec;
-}
-
-TEST(exstring, nget_command_none_zero_items)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_CallReplyLength", 3);
-    int ret = NGet_RedisCommand(&ctx, redisStrVec,  2);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("MGET").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_ReplyWithArray").getIntValue(), 3*2);
-    CHECK_EQUAL(mock().getData("RedisModule_ReplyWithString").getIntValue(), 3*2);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
-
-    delete []redisStrVec;
-}
-
-TEST(exstring, ndel_command_parameter_parameter_number_incorrect)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-
-    int ret = NDel_RedisCommand(&ctx, redisStrVec,  3);
-    CHECK_EQUAL(ret, REDISMODULE_ERR);
-
-    delete []redisStrVec;
-}
-
-TEST(exstring, ndel_command_zero_item)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_CallReplyLength", 0);
-    int ret = NDel_RedisCommand(&ctx, redisStrVec,  2);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 1);
-
-    delete []redisStrVec;
-}
-
-TEST(exstring, ndel_command_none_zero_items)
-{
-    RedisModuleCtx ctx;
-    RedisModuleString ** redisStrVec = new (RedisModuleString*[2]);
-    redisStrVec[0] = (RedisModuleString *)1;
-    redisStrVec[1] = (RedisModuleString *)1;
-
-    mock().setData("RedisModule_CallReplyLength", 3);
-    int ret = NDel_RedisCommand(&ctx, redisStrVec,  2);
-    CHECK_EQUAL(ret, REDISMODULE_OK);
-    CHECK_EQUAL(mock().getData("KEYS").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_ReplyWithCallReply").getIntValue(), 1);
-    CHECK_EQUAL(mock().getData("RedisModule_FreeCallReply").getIntValue(), 2);
-
-    delete []redisStrVec;
-}