Merge "Add tag file to support CI-based build of DBaaS" 0.1.0
authorMarco Tallskog <marco.tallskog@nokia.com>
Mon, 17 Jun 2019 05:42:51 +0000 (05:42 +0000)
committerGerrit Code Review <gerrit@o-ran-sc.org>
Mon, 17 Jun 2019 05:42:51 +0000 (05:42 +0000)
redismodule/README.md
redismodule/src/exstrings.c
redismodule/tst/mock/include/exstringsStub.h
redismodule/tst/mock/include/redismodule.h
redismodule/tst/mock/src/redismoduleStub.cpp
redismodule/tst/src/exstrings_test.cpp

index 04012ea..7add0a6 100755 (executable)
@@ -123,29 +123,35 @@ Time complexity: O(N) where N is the number of keys to set + O(N+M) where N is t
 
 Set the given keys to their respective values and post a message to the given channel
 
-## SETXXPUB key value channel message
+## MSETMPUB number_of_key_value_pairs number_of_channel_message_pairs key value [ key value ... ] channel message [ channel message ... ]
 
-Time complexity: O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(N) where N is the number of keys to set + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the corresponding receiving channel and M is the total number of subscribed patterns (by any client)
 
-Set key to hold string value if key already exist and post a message to the given channel if set key value successfully
+Set the given keys to their respective values and post messages to their respective channels
 
-## SETNXPUB key value channel message
+## SETXXPUB key value channel message [channel message...]
 
-Time complexity: O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
 
-Set key to hold string value if key does not exist and post a message to the given channel if set key value successfully
+Set key to hold string value if key already exists and post given messages to the corresponding channels if key value was set successfully
 
-## SETIEPUB key value oldvalue channel message
+## SETNXPUB key value channel message [channel message...]
 
-Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
 
-Checks a String 'key' for 'oldvalue' equality and set key for 'value'  and post a message to the given channel if set key value successfully
+Set key to hold string value if key does not exist and post given messages to the corresponding channels if key value was set successfully
 
-## SETNEPUB key value oldvalue channel message
+## SETIEPUB key value oldvalue channel message [channel message...]
 
-Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
 
-Checks a String 'key' for 'oldvalue' not equality and set key for 'value'  and post a message to the given channel if set key value successfully
+If the string corresponding to 'key' is equal to 'oldvalue' then set key for 'value' and post given messages to the corresponding channels if key value was set successfully
+
+## SETNEPUB key value oldvalue channel message [channel message...]
+
+Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
+
+If the string corresponding to 'key' is not equal to 'oldvalue' then set key for 'value' and post given messages to the corresponding channels if key value was set successfully
 
 ## DELPUB key [key...] channel message
 
@@ -153,17 +159,23 @@ Time complexity: O(N) where N is the number of keys that will be removed + O(N+M
 
 Removes the specified keys and post a message to the given channel if delete key successfully(return >0)
 
-## DELIEPUB key oldvalue channel message
+## DELMPUB number_of_keys number_of_channel_message_pairs key [ key ... ] channel message [ channel message ... ]
+
+Time complexity: O(N) where N is the number of keys that will be removed + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+
+Remove the specified keys. If any of the keys was deleted succesfully (delete return value > 0) then post given messages to the corresponding channels.
+
+## DELIEPUB key oldvalue channel message [channel message...]
 
-ime complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ...] where N_i are the number of clients subscribed to the corrensponding receiving channel and M is the total number of subscribed patterns (by any client)
 
-Checks a String 'key' for 'oldvalue' equality and delete the key and post a message to the given channel if delete key successfully(return 1)
+If the string corresponding to 'key' is equal to 'oldvalue' then delete the key. If deletion was succesful (delete return value was 1) then post given messages to the corresponding channels.
 
-## DELNEPUB key oldvalue channel message
+## DELNEPUB key oldvalue channel message [channel message...]
 
-Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ...] where N_i are the number of clients subscribed to the corrensponding receiving channel and M is the total number of subscribed patterns (by any client)
 
-Checks a String 'key' for 'oldvalue' not equality and delete the key and post a message to the given channel if delete key successfully(return 1)
+If the string corresponding to 'key' is not equal to 'oldvalue' then delete the key. If deletion was succesful (delete return value was 1) then post given messages to the corresponding channels.
 
 ## NGET pattern
 
index 66f31c2..cec45ab 100755 (executable)
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdbool.h>
 #include "../../redismodule/include/redismodule.h"
 
 #ifdef __UT__
@@ -42,6 +43,47 @@ 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 */
 
+int getKeyType(RedisModuleCtx *ctx, RedisModuleString *key_str)
+{
+    RedisModuleKey *key = RedisModule_OpenKey(ctx, key_str, REDISMODULE_READ);
+    int type = RedisModule_KeyType(key);
+    RedisModule_CloseKey(key);
+    return type;
+}
+
+bool replyContentsEqualString(RedisModuleCallReply *reply, RedisModuleString *expected_value)
+{
+    size_t replylen = 0, expectedlen = 0;
+    const char *expectedval = RedisModule_StringPtrLen(expected_value, &expectedlen);
+    const char *replyval = RedisModule_CallReplyStringPtr(reply, &replylen);
+    return replyval &&
+           expectedlen == replylen &&
+           !strncmp(expectedval, replyval, replylen);
+}
+
+typedef struct _SetParams {
+    RedisModuleString **key_val_pairs;
+    size_t length;
+} SetParams;
+
+typedef struct _PubParams {
+    RedisModuleString **channel_msg_pairs;
+    size_t length;
+} PubParams;
+
+typedef struct _DelParams {
+    RedisModuleString **keys;
+    size_t length;
+} DelParams;
+
+void multiPubCommand(RedisModuleCtx *ctx, PubParams* pubParams)
+{
+    RedisModuleCallReply *reply = NULL;
+    for (unsigned int i = 0 ; i < pubParams->length ; i += 2) {
+        reply = RedisModule_Call(ctx, "PUBLISH", "v", pubParams->channel_msg_pairs + i, 2);
+        RedisModule_FreeCallReply(reply);
+    }
+}
 
 int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
                                        int argc, const int flag)
@@ -286,227 +328,256 @@ int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
     return REDISMODULE_OK;
 }
 
-int setPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
-                                       int argc, const int flag)
+int setPubStringCommon(RedisModuleCtx *ctx, SetParams* setParamsPtr, PubParams* pubParamsPtr)
 {
-    RedisModuleString *oldvalstr = NULL, *channel = NULL, *message = NULL;
-    RedisModuleCallReply *reply = NULL;
-
-    if (flag == OBJ_OP_NO) {
-        if (argc < 5 || (argc % 2) == 0)
-            return RedisModule_WrongArity(ctx);
-        else {
-            channel = argv[argc-2];
-            message = argv[argc-1];
-        }
-    } else if (flag == OBJ_OP_XX || flag == OBJ_OP_NX) {
-        if (argc != 5)
-            return RedisModule_WrongArity(ctx);
-        else {
-            channel = argv[3];
-            message = argv[4];
-        }
+    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 {
-        if (argc != 6)
-            return RedisModule_WrongArity(ctx);
-        else {
-            oldvalstr = argv[3];
-            channel = argv[4];
-            message = argv[5];
-        }
+        multiPubCommand(ctx, pubParamsPtr);
+        RedisModule_ReplyWithCallReply(ctx, setReply);
     }
+    RedisModule_FreeCallReply(setReply);
+    return REDISMODULE_OK;
+}
 
-    /*Check if key type is string*/
-    RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
-        REDISMODULE_READ);
-    int type = RedisModule_KeyType(key);
-    RedisModule_CloseKey(key);
+int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+    if (argc < 5 || (argc % 2) == 0)
+        return RedisModule_WrongArity(ctx);
 
-    if (flag != OBJ_OP_NO) {
-        if (type == REDISMODULE_KEYTYPE_EMPTY) {
-            if (flag == OBJ_OP_IE || flag == OBJ_OP_XX){
-                return RedisModule_ReplyWithNull(ctx);
-            }
-        } else if (flag == OBJ_OP_NX) {
-            return RedisModule_ReplyWithNull(ctx);
-        } else if (type != REDISMODULE_KEYTYPE_STRING) {
-            return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
-        }
-    }
+    SetParams setParams = {
+                           .key_val_pairs = argv + 1,
+                           .length = argc - 3
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + argc - 2,
+                           .length = 2
+                          };
 
-    if (flag == OBJ_OP_IE || flag == OBJ_OP_NE) {
-        /*Get the value*/
-        reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
-        ASSERT_NOERROR(reply)
-        size_t curlen = 0, oldvallen = 0;
-        const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
-        const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
-        if (((flag == OBJ_OP_IE) &&
-            (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
-            ||
-            ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
-              !strncmp(oldval, curval, curlen))) {
-            RedisModule_FreeCallReply(reply);
-            return RedisModule_ReplyWithNull(ctx);
-        }
-        RedisModule_FreeCallReply(reply);
-    }
+    return setPubStringCommon(ctx, &setParams, &pubParams);
+}
 
+int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+    if (argc < 7 || (argc % 2) == 0)
+        return RedisModule_WrongArity(ctx);
 
-    /* Prepare the arguments for the command. */
-    int i, j=0, cmdargc=argc-3;
-    RedisModuleString *cmdargv[cmdargc];
-    for (i = 1; i < argc-2; i++) {
-        if ((flag == OBJ_OP_IE || flag == OBJ_OP_NE) && (i == 3))
-            continue;
-        cmdargv[j++] = argv[i];
+    long long setPairsCount, pubPairsCount;
+    RedisModule_StringToLongLong(argv[1], &setPairsCount);
+    RedisModule_StringToLongLong(argv[2], &pubPairsCount);
+    if (setPairsCount < 1 || pubPairsCount < 1)
+        return RedisModule_ReplyWithError(ctx, "ERR SET_PAIR_COUNT and PUB_PAIR_COUNT must be greater than zero");
+
+    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");
+
+    SetParams setParams = {
+                           .key_val_pairs = argv + 3,
+                           .length = setLen
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + 3 + setParams.length,
+                           .length = pubLen
+                          };
+
+    return setPubStringCommon(ctx, &setParams, &pubParams);
+}
+
+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
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + 4,
+                           .length = argc - 4
+                          };
+    RedisModuleString *key = setParams.key_val_pairs[0];
+    RedisModuleString *oldvalstr = argv[3];
+
+    int type = getKeyType(ctx, key);
+    if (flag == OBJ_OP_IE && type == REDISMODULE_KEYTYPE_EMPTY) {
+        return RedisModule_ReplyWithNull(ctx);
+    } else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
+        return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
     }
 
-    /* Call the command and pass back the reply. */
-    reply = RedisModule_Call(ctx, "MSET", "v!", cmdargv, j);
+    RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key);
     ASSERT_NOERROR(reply)
-    int replytype = RedisModule_CallReplyType(reply);
-    if (replytype == REDISMODULE_REPLY_NULL) {
-        RedisModule_ReplyWithNull(ctx);
-    }
-    else {
-        cmdargc = 2;
-        cmdargv[0] = channel;
-        cmdargv[1] = message;
-        RedisModuleCallReply *pubreply = RedisModule_Call(ctx, "PUBLISH", "v", cmdargv, cmdargc);
-        RedisModule_FreeCallReply(pubreply);
-        RedisModule_ReplyWithCallReply(ctx, reply);
+    bool is_equal = replyContentsEqualString(reply, oldvalstr);
+    RedisModule_FreeCallReply(reply);
+    if ((flag == OBJ_OP_IE && !is_equal) ||
+        (flag == OBJ_OP_NE && is_equal)) {
+        return RedisModule_ReplyWithNull(ctx);
     }
 
-    RedisModule_FreeCallReply(reply);
-    return REDISMODULE_OK;
+    return setPubStringCommon(ctx, &setParams, &pubParams);
 }
 
-int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-    return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NO);
+    return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
 }
 
 int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-    return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+    return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
 }
 
-int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
 {
-    return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+    if (argc < 5 || (argc % 2) == 0)
+        return RedisModule_WrongArity(ctx);
+
+    SetParams setParams = {
+                           .key_val_pairs = argv + 1,
+                           .length = 2
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + 3,
+                           .length = argc - 3
+                          };
+    RedisModuleString *key = setParams.key_val_pairs[0];
+
+    int type = getKeyType(ctx, key);
+    if ((flag == OBJ_OP_XX && type == REDISMODULE_KEYTYPE_EMPTY) ||
+        (flag == OBJ_OP_NX && type == REDISMODULE_KEYTYPE_STRING)) {
+        return RedisModule_ReplyWithNull(ctx);
+    } else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
+        RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
+        return REDISMODULE_OK;
+    }
+
+    return setPubStringCommon(ctx, &setParams, &pubParams);
 }
 
 int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-    return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NX);
+    return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
 }
 
 int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-    return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_XX);
+    return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_XX);
 }
 
-int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
-                                       int argc, const int flag)
+int delPubStringCommon(RedisModuleCtx *ctx, DelParams *delParamsPtr, PubParams *pubParamsPtr)
 {
-    RedisModuleString *oldvalstr = NULL, *channel = NULL, *message = NULL;
-    RedisModuleCallReply *reply = NULL;
-
-    if (flag == OBJ_OP_NO) {
-        if (argc < 4)
-            return RedisModule_WrongArity(ctx);
-        else {
-            channel = argv[argc-2];
-            message = argv[argc-1];
-        }
-    } else {
-        if (argc != 5)
-            return RedisModule_WrongArity(ctx);
-        else {
-            oldvalstr = argv[2];
-            channel = argv[3];
-            message = argv[4];
-        }
-    }
-
-    if (flag != OBJ_OP_NO) {
-        /*Check if key type is string*/
-        RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
-            REDISMODULE_READ);
-        int type = RedisModule_KeyType(key);
-        RedisModule_CloseKey(key);
-
-        if (type == REDISMODULE_KEYTYPE_EMPTY) {
-            return RedisModule_ReplyWithLongLong(ctx, 0);
-        } else if (type != REDISMODULE_KEYTYPE_STRING) {
-            return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
-        }
-    }
-
-    if (flag == OBJ_OP_IE || flag == OBJ_OP_NE) {
-        /*Get the value*/
-        reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
-        ASSERT_NOERROR(reply)
-        size_t curlen = 0, oldvallen = 0;
-        const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
-        const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
-        if (((flag == OBJ_OP_IE) &&
-            (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
-            ||
-            ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
-              !strncmp(oldval, curval, curlen))) {
-            RedisModule_FreeCallReply(reply);
-            return RedisModule_ReplyWithLongLong(ctx, 0);
-        }
-        RedisModule_FreeCallReply(reply);
-    }
-
-
-    /* Prepare the arguments for the command. */
-    int i, j=0, cmdargc=argc-3;
-    RedisModuleString *cmdargv[cmdargc];
-    for (i = 1; i < argc-2; i++) {
-        if ((flag == OBJ_OP_IE || flag == OBJ_OP_NE) && (i == 2))
-            continue;
-        cmdargv[j++] = argv[i];
-    }
-
-    /* Call the command and pass back the reply. */
-    reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, j);
+    RedisModuleCallReply *reply = RedisModule_Call(ctx, "UNLINK", "v!", delParamsPtr->keys, delParamsPtr->length);
     ASSERT_NOERROR(reply)
     int replytype = RedisModule_CallReplyType(reply);
     if (replytype == REDISMODULE_REPLY_NULL) {
         RedisModule_ReplyWithNull(ctx);
-    }
-    else if (RedisModule_CallReplyInteger(reply) == 0) {
+    } else if (RedisModule_CallReplyInteger(reply) == 0) {
         RedisModule_ReplyWithCallReply(ctx, reply);
     } else {
-        cmdargc = 2;
-        cmdargv[0] = channel;
-        cmdargv[1] = message;
-        RedisModuleCallReply *pubreply = RedisModule_Call(ctx, "PUBLISH", "v", cmdargv, cmdargc);
-        RedisModule_FreeCallReply(pubreply);
         RedisModule_ReplyWithCallReply(ctx, reply);
+        multiPubCommand(ctx, pubParamsPtr);
     }
-
     RedisModule_FreeCallReply(reply);
     return REDISMODULE_OK;
 }
 
 int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-   return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NO);
+    if (argc < 4)
+        return RedisModule_WrongArity(ctx);
+
+    DelParams delParams = {
+                           .keys = argv + 1,
+                           .length = argc - 3
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + 1 + delParams.length,
+                           .length = 2
+                          };
+
+    return delPubStringCommon(ctx, &delParams, &pubParams);
+}
+
+int DelMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+    if (argc < 6)
+        return RedisModule_WrongArity(ctx);
+
+    long long delCount, pubPairsCount;
+    RedisModule_StringToLongLong(argv[1], &delCount);
+    RedisModule_StringToLongLong(argv[2], &pubPairsCount);
+    if (delCount < 1 || pubPairsCount < 1)
+        return RedisModule_ReplyWithError(ctx, "ERR DEL_COUNT and PUB_PAIR_COUNT must be greater than zero");
+
+    long long delLen, pubLen;
+    delLen = delCount;
+    pubLen = 2*pubPairsCount;
+    if (delLen + pubLen + 3 != argc)
+        return RedisModule_ReplyWithError(ctx, "ERR DEL_COUNT or PUB_PAIR_COUNT do not match the total pair count");
+
+    DelParams delParams = {
+                           .keys = argv + 3,
+                           .length = delLen
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + 3 + delParams.length,
+                           .length = pubLen
+                          };
+
+    return delPubStringCommon(ctx, &delParams, &pubParams);
+}
+
+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
+                          };
+    PubParams pubParams = {
+                           .channel_msg_pairs = argv + 3,
+                           .length = argc - 3
+                          };
+    RedisModuleString *key = argv[1];
+    RedisModuleString *oldvalstr = argv[2];
+
+    int type = getKeyType(ctx, key);
+    if (type == REDISMODULE_KEYTYPE_EMPTY) {
+        return RedisModule_ReplyWithLongLong(ctx, 0);
+    } else if (type != REDISMODULE_KEYTYPE_STRING) {
+        return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
+    }
+
+    RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key);
+    ASSERT_NOERROR(reply)
+    bool is_equal = replyContentsEqualString(reply, oldvalstr);
+    RedisModule_FreeCallReply(reply);
+    if ((flag == OBJ_OP_IE && !is_equal) ||
+        (flag == OBJ_OP_NE && is_equal)) {
+        return RedisModule_ReplyWithLongLong(ctx, 0);
+    }
+
+    return delPubStringCommon(ctx, &delParams, &pubParams);
 }
 
 int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-   return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+   return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
 }
 
 int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
 {
-   return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+   return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
 }
 
 /* This function must be present on each Redis module. It is used in order to
@@ -546,6 +617,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
         SetPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
 
+    if (RedisModule_CreateCommand(ctx,"msetmpub",
+        SetMPub_RedisCommand,"write deny-oom pubsub",1,1,1) == REDISMODULE_ERR)
+        return REDISMODULE_ERR;
+
     if (RedisModule_CreateCommand(ctx,"setiepub",
         SetIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
@@ -566,6 +641,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
         DelPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
 
+    if (RedisModule_CreateCommand(ctx,"delmpub",
+        DelMPub_RedisCommand,"write deny-oom pubsub",1,1,1) == REDISMODULE_ERR)
+        return REDISMODULE_ERR;
+
     if (RedisModule_CreateCommand(ctx,"deliepub",
         DelIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
         return REDISMODULE_ERR;
index dc426cd..d61a31b 100755 (executable)
@@ -33,17 +33,17 @@ int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a
 int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 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 SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
 int SetNXPub_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 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);
-int setPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,          int argc, const int flag);
-int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,          int argc, const int flag);
 
 
 #endif
index df79c72..1e97588 100755 (executable)
@@ -361,6 +361,7 @@ 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);
index b08fd21..2e401b7 100755 (executable)
@@ -95,7 +95,7 @@ RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname,
     else if (!strcmp(cmdname, "UNLINK"))
         mock().setData("UNLINK", 1);
     else if (!strcmp(cmdname, "PUBLISH"))
-        mock().setData("PUBLISH", 1);
+        mock().setData("PUBLISH", mock().getData("PUBLISH").getIntValue() + 1);
     else if (!strcmp(cmdname, "KEYS"))
         mock().setData("KEYS", 1);
     else if (!strcmp(cmdname, "MGET"))
@@ -289,3 +289,20 @@ int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len)
     return REDISMODULE_OK;
 }
 
+int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll)
+{
+    (void) str;
+    int call_no = mock().getData("RedisModule_StringToLongLongCallCount").getIntValue();
+    switch(call_no) {
+        case 0:
+            *ll = mock().getData("RedisModule_StringToLongLongCall_1").getIntValue();
+            break;
+        case 1:
+            *ll = mock().getData("RedisModule_StringToLongLongCall_2").getIntValue();
+            break;
+        default:
+            *ll = mock().getData("RedisModule_StringToLongLongCallDefault").getIntValue();
+    }
+    mock().setData("RedisModule_StringToLongLongCallCount", call_no + 1);
+    return REDISMODULE_OK;
+}
index 2d540d5..e051e41 100755 (executable)
@@ -457,13 +457,34 @@ TEST(exstring, setpub)
     mock().setData("RedisModule_String_same", 1);
     mock().setData("RedisModule_CallReplyType_null", 1);
 
-    mock().expectOneCall("RedisModule_CloseKey");
     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;
@@ -562,27 +583,52 @@ TEST(exstring, setpub_command_parameter_number_incorrect)
 {
     RedisModuleCtx ctx;
     int ret = 0;
-    ret = setPubStringGenericCommand(&ctx, 0, 2, OBJ_OP_NO);
+
+    ret = SetPub_RedisCommand(&ctx, 0, 2);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = setPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NO);
+    ret = SetPub_RedisCommand(&ctx, 0, 8);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = setPubStringGenericCommand(&ctx, 0, 3, OBJ_OP_XX);
+    ret = SetMPub_RedisCommand(&ctx, 0, 2);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = setPubStringGenericCommand(&ctx, 0, 6, OBJ_OP_NX);
+    ret = SetMPub_RedisCommand(&ctx, 0, 8);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = setPubStringGenericCommand(&ctx, 0, 4, OBJ_OP_IE);
+    ret = SetXXPub_RedisCommand(&ctx, 0, 3);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = setPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NE);
+    ret = SetXXPub_RedisCommand(&ctx, 0, 6);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = SetNXPub_RedisCommand(&ctx, 0, 3);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = SetNXPub_RedisCommand(&ctx, 0, 6);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = SetIEPub_RedisCommand(&ctx, 0, 4);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = SetIEPub_RedisCommand(&ctx, 0, 9);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = SetNEPub_RedisCommand(&ctx, 0, 4);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = SetNEPub_RedisCommand(&ctx, 0, 9);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 }
 
@@ -600,8 +646,7 @@ TEST(exstring, setpub_command_no_key_replynull)
     mock().setData("RedisModule_KeyType_empty", 1);
     mock().setData("RedisModule_CallReplyType_null", 1);
 
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+    int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
@@ -627,8 +672,7 @@ TEST(exstring, setpub_command_no_key_replystr)
     mock().setData("RedisModule_KeyType_empty", 1);
     mock().setData("RedisModule_CallReplyType_str", 1);
 
-    mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+    int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
@@ -640,6 +684,193 @@ TEST(exstring, setpub_command_no_key_replystr)
 
 }
 
+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());
+
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, setmpub_command_negative_key_val_count)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString ** redisStrVec = new (RedisModuleString*[7]);
+
+    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;
+
+    mock().setData("RedisModule_KeyType_empty", 1);
+    mock().setData("RedisModule_CallReplyType_str", 1);
+    mock().setData("RedisModule_StringToLongLongCall_1", -1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
+    mock().checkExpectations();
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("MSET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, setmpub_command_negative_chan_msg_count)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString ** redisStrVec = new (RedisModuleString*[7]);
+
+    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;
+
+    mock().setData("RedisModule_KeyType_empty", 1);
+    mock().setData("RedisModule_CallReplyType_str", 1);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", -1);
+
+    int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
+    mock().checkExpectations();
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("MSET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, setmpub_command_invalid_total_count)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString ** redisStrVec = new (RedisModuleString*[7]);
+
+    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;
+
+    mock().setData("RedisModule_KeyType_empty", 1);
+    mock().setData("RedisModule_CallReplyType_str", 1);
+    mock().setData("RedisModule_StringToLongLongCall_1", 100);
+    mock().setData("RedisModule_StringToLongLongCall_2", 100);
+
+    int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
+    mock().checkExpectations();
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("MSET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, setmpub_command_set)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString ** redisStrVec = new (RedisModuleString*[7]);
+
+    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;
+
+    mock().setData("RedisModule_KeyType_empty", 1);
+    mock().setData("RedisModule_CallReplyType_str", 1);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
+    mock().checkExpectations();
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(1, mock().getData("MSET").getIntValue());
+    CHECK_EQUAL(1, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(2, mock().getData("RedisModule_FreeCallReply").getIntValue());
+
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, setmpub_command_set_multipub)
+{
+    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_str", 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(2, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(3, mock().getData("RedisModule_FreeCallReply").getIntValue());
+
+    delete []redisStrVec;
+
+}
+
 TEST(exstring, setxxpub_command_has_no_key)
 {
     RedisModuleCtx ctx;
@@ -655,7 +886,7 @@ TEST(exstring, setxxpub_command_has_no_key)
     mock().setData("RedisModule_CallReplyType_null", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+    int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -683,7 +914,7 @@ TEST(exstring, setxxpub_command_parameter_has_key_set)
     mock().setData("RedisModule_KeyType_set", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+    int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -712,7 +943,7 @@ TEST(exstring, setxxpub_command_has_key_string)
     mock().setData("RedisModule_CallReplyType_str", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+    int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -742,7 +973,7 @@ TEST(exstring, setnxpub_command_has_key_string)
     mock().setData("RedisModule_CallReplyType_null", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NX);
+    int ret = SetNXPub_RedisCommand(&ctx, redisStrVec, 5);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -771,7 +1002,7 @@ TEST(exstring, setnxpub_command_has_no_key)
     mock().setData("RedisModule_CallReplyType_str", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NX);
+    int ret = SetNXPub_RedisCommand(&ctx, redisStrVec, 5);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -803,7 +1034,7 @@ TEST(exstring, setiepub_command_has_no_key)
     mock().setData("RedisModule_CallReplyType_str", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+    int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -835,7 +1066,7 @@ TEST(exstring, setiepub_command_key_string_nosame)
     mock().setData("RedisModule_String_nosame", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+    int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -866,7 +1097,7 @@ TEST(exstring, setiepub_command_key_same_string_replynull)
     mock().setData("RedisModule_CallReplyType_null", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+    int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -897,7 +1128,7 @@ TEST(exstring, setiepub_command_key_same_string_reply)
     mock().setData("RedisModule_CallReplyType_str", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+    int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -928,7 +1159,7 @@ TEST(exstring, setnepub_command_has_no_key)
     mock().setData("RedisModule_String_nosame", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+    int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -959,7 +1190,7 @@ TEST(exstring, setnepub_command_key_string_same_reply)
     mock().setData("RedisModule_CallReplyType_str", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+    int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -991,7 +1222,7 @@ TEST(exstring, setnepub_command_key_string_nosame_reply)
     mock().setData("RedisModule_String_nosame", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+    int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
 
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
@@ -1026,6 +1257,34 @@ TEST(exstring, delpub)
     delete []redisStrVec;
 }
 
+TEST(exstring, delmpub)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString ** redisStrVec = new (RedisModuleString*[8]);
+
+    redisStrVec[0] = (RedisModuleString *)1;
+    redisStrVec[1] = (RedisModuleString *)1;
+    redisStrVec[2] = (RedisModuleString *)1;
+    redisStrVec[3] = (RedisModuleString *)1;
+    redisStrVec[4] = (RedisModuleString *)1;
+    redisStrVec[5] = (RedisModuleString *)1;
+    redisStrVec[6] = (RedisModuleString *)1;
+    redisStrVec[7] = (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", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 2);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec,  8);
+    CHECK_EQUAL(ret, REDISMODULE_OK);
+
+    delete []redisStrVec;
+}
+
 TEST(exstring, deliepub)
 {
     RedisModuleCtx ctx;
@@ -1076,15 +1335,19 @@ TEST(exstring, delpub_command_parameter_number_incorrect)
 {
     RedisModuleCtx ctx;
     int ret = 0;
-    ret = delPubStringGenericCommand(&ctx, 0, 2, OBJ_OP_NO);
+    ret = DelPub_RedisCommand(&ctx, 0, 2);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+    ret = 0;
+    ret = DelMPub_RedisCommand(&ctx, 0, 5);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = delPubStringGenericCommand(&ctx, 0, 4, OBJ_OP_IE);
+    ret = DelIEPub_RedisCommand(&ctx, 0, 4);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 
     ret = 0;
-    ret = delPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NE);
+    ret = DelNEPub_RedisCommand(&ctx, 0, 8);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
 }
 
@@ -1102,7 +1365,7 @@ TEST(exstring, delpub_command_reply_null)
     mock().setData("RedisModule_CallReplyType_inter", 1);
     mock().setData("RedisModule_Call_Return_Null", 0);
 
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+    int ret = DelPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, 0);
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
@@ -1127,7 +1390,7 @@ TEST(exstring, delpub_command_reply_error)
     mock().setData("RedisModule_CallReplyInteger", 0);
     mock().setData("RedisModule_CallReplyType_err", 1);
 
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+    int ret = DelPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_ERR);
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
@@ -1152,7 +1415,7 @@ TEST(exstring, delpub_command_has_no_key)
     mock().setData("RedisModule_CallReplyInteger", 0);
     mock().setData("RedisModule_CallReplyType_inter", 1);
 
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+    int ret = DelPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, 0);
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("UNLINK").getIntValue(), 1);
@@ -1163,6 +1426,243 @@ TEST(exstring, delpub_command_has_no_key)
 
 }
 
+TEST(exstring, delmpub_command_reply_null)
+{
+    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_Call_Return_Null", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(ret, 0);
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(1, mock().getData("UNLINK").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_ReplyWithCallReply").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_reply_error)
+{
+    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[4] = (RedisModuleString *)1;
+
+    mock().setData("RedisModule_CallReplyInteger", 0);
+    mock().setData("RedisModule_CallReplyType_err", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(ret, REDISMODULE_ERR);
+    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_ReplyWithError").getIntValue(), 0);
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_has_no_key)
+{
+    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_CallReplyInteger", 0);
+    mock().setData("RedisModule_CallReplyType_inter", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(ret, 0);
+    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);
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_key_deleted)
+{
+    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_CallReplyInteger", 1);
+    mock().setData("RedisModule_CallReplyType_inter", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(ret, 0);
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(1, mock().getData("UNLINK").getIntValue());
+    CHECK_EQUAL(1, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithCallReply").getIntValue());
+    CHECK_EQUAL(2, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_key_deleted_multi_pub)
+{
+    RedisModuleCtx ctx;
+    RedisModuleString **redisStrVec = new (RedisModuleString*[10]);
+
+    redisStrVec[0] = (RedisModuleString *)1;
+    redisStrVec[1] = (RedisModuleString *)1;
+    redisStrVec[2] = (RedisModuleString *)1;
+    redisStrVec[3] = (RedisModuleString *)1;
+    redisStrVec[4] = (RedisModuleString *)1;
+    redisStrVec[5] = (RedisModuleString *)1;
+    redisStrVec[6] = (RedisModuleString *)1;
+    redisStrVec[7] = (RedisModuleString *)1;
+    redisStrVec[8] = (RedisModuleString *)1;
+    redisStrVec[9] = (RedisModuleString *)1;
+
+    mock().setData("RedisModule_CallReplyInteger", 1);
+    mock().setData("RedisModule_CallReplyType_inter", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 3);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 10);
+    CHECK_EQUAL(0, ret);
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(1, mock().getData("UNLINK").getIntValue());
+    CHECK_EQUAL(3, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithCallReply").getIntValue());
+    CHECK_EQUAL(4, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_negative_del_count)
+{
+    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_CallReplyInteger", 1);
+    mock().setData("RedisModule_CallReplyType_inter", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", -1);
+    mock().setData("RedisModule_StringToLongLongCall_2", 1);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(0, ret);
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("UNLINK").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_negative_chan_msg_count)
+{
+    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_CallReplyInteger", 1);
+    mock().setData("RedisModule_CallReplyType_inter", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 1);
+    mock().setData("RedisModule_StringToLongLongCall_2", -1);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(0, ret);
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("UNLINK").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    delete []redisStrVec;
+
+}
+
+TEST(exstring, delmpub_command_invalid_total_count)
+{
+    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_CallReplyInteger", 1);
+    mock().setData("RedisModule_CallReplyType_inter", 1);
+    mock().setData("RedisModule_StringToLongLongCallCount", 0);
+    mock().setData("RedisModule_StringToLongLongCall_1", 100);
+    mock().setData("RedisModule_StringToLongLongCall_2", 100);
+
+    int ret = DelMPub_RedisCommand(&ctx, redisStrVec, 6);
+    CHECK_EQUAL(0, ret);
+    CHECK_EQUAL(0, mock().getData("GET").getIntValue());
+    CHECK_EQUAL(0, mock().getData("UNLINK").getIntValue());
+    CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue());
+    CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue());
+    CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue());
+    delete []redisStrVec;
+
+}
+
 TEST(exstring, deliepub_command_has_no_key)
 {
     RedisModuleCtx ctx;
@@ -1176,7 +1676,7 @@ TEST(exstring, deliepub_command_has_no_key)
     mock().setData("RedisModule_KeyType_empty", 1);
 
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+    int ret = DelIEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, 0);
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithLongLong").getIntValue(), 0);
     CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
@@ -1202,7 +1702,7 @@ TEST(exstring, deliepub_command_has_key_set)
     mock().setData("RedisModule_OpenKey_have", 1);
     mock().setData("RedisModule_KeyType_set", 1);
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+    int ret = DelIEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 1);
@@ -1230,7 +1730,7 @@ TEST(exstring, deliepub_command_key_string_nosame)
     mock().setData("RedisModule_KeyType_str", 1);
     mock().setData("RedisModule_String_nosame", 1);
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+    int ret = DelIEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
@@ -1260,7 +1760,7 @@ TEST(exstring, deliepub_command_same_string_replynull)
     mock().setData("RedisModule_String_same", 1);
     mock().setData("RedisModule_CallReplyType_null", 1);
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+    int ret = DelIEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
@@ -1291,7 +1791,7 @@ TEST(exstring, deliepub_command_same_string_reply)
     mock().setData("RedisModule_CallReplyType_str", 1);
     mock().setData("RedisModule_CallReplyInteger", 1);
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_IE);
+    int ret = DelIEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
@@ -1321,7 +1821,7 @@ TEST(exstring, delnepub_command_same_string_reply)
     mock().setData("RedisModule_String_same", 1);
     mock().setData("RedisModule_CallReplyType_str", 1);
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NE);
+    int ret = DelNEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);
@@ -1352,7 +1852,7 @@ TEST(exstring, delnepub_command_nosame_string_reply)
     mock().setData("RedisModule_CallReplyType_str", 1);
     mock().setData("RedisModule_CallReplyInteger", 1);
     mock().expectOneCall("RedisModule_CloseKey");
-    int ret = delPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NE);
+    int ret = DelNEPub_RedisCommand(&ctx, redisStrVec, 5);
     CHECK_EQUAL(ret, REDISMODULE_OK);
     mock().checkExpectations();
     CHECK_EQUAL(mock().getData("RedisModule_ReplyWithError").getIntValue(), 0);