Add refactored ndel command and UT
[ric-plt/dbaas.git] / redismodule / tst / src / exstrings_nget_test.cpp
1 /*
2  * Copyright (c) 2018-2020 Nokia.
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16
17 /*
18  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19  * platform project (RICP).
20  */
21
22 extern "C" {
23 #include "exstringsStub.h"
24 #include "redismodule.h"
25 }
26
27 #include <string.h>
28
29 #include "CppUTest/TestHarness.h"
30 #include "CppUTestExt/MockSupport.h"
31
32 #include "ut_helpers.hpp"
33
34 TEST_GROUP(exstrings_nget)
35 {
36     void setup()
37     {
38         mock().enable();
39         mock().ignoreOtherCalls();
40     }
41
42     void teardown()
43     {
44         mock().clear();
45         mock().disable();
46     }
47
48 };
49
50 void nKeysFoundMget(long keys)
51 {
52     for (long i = 0 ; i < keys ; i++) {
53         mock().expectOneCall("RedisModule_CreateStringFromCallReply")
54               .andReturnValue(malloc(UT_DUMMY_BUFFER_SIZE));
55         mock().expectNCalls(2, "RedisModule_ReplyWithString");
56     }
57 }
58
59 void nKeysNotFoundMget(long keys)
60 {
61     void* ptr = NULL;
62     mock().expectNCalls(keys, "RedisModule_CreateStringFromCallReply")
63           .andReturnValue(ptr);
64     mock().expectNoCall("RedisModule_ReplyWithString");
65 }
66
67 void expectNReplies(long count)
68 {
69     mock().expectOneCall("RedisModule_ReplySetArrayLength")
70           .withParameter("len", 2*count);
71 }
72
73 void threadSafeContextLockedAndUnlockedEqualTimes()
74 {
75     int locked = mock().getData("TimesThreadSafeContextWasLocked").getIntValue();
76     int unlocked = mock().getData("TimesThreadSafeContextWasUnlocked").getIntValue();
77     CHECK_EQUAL(locked, unlocked);
78 }
79
80 TEST(exstrings_nget, nget_atomic_automemory_enabled)
81 {
82     RedisModuleCtx ctx;
83     RedisModuleString ** redisStrVec = createRedisStrVec(2);
84     long keys_found_with_scan = 0;
85
86     mock().expectOneCall("RedisModule_AutoMemory");
87     mock().expectOneCall("RedisModule_CallReplyLength")
88           .andReturnValue((int)keys_found_with_scan);
89     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  2);
90     mock().checkExpectations();
91     CHECK_EQUAL(ret, REDISMODULE_OK);
92
93     delete []redisStrVec;
94 }
95
96 TEST(exstrings_nget, nget_atomic_command_parameter_number_incorrect)
97 {
98     RedisModuleCtx ctx;
99     RedisModuleString ** redisStrVec = createRedisStrVec(2);
100
101     mock().expectOneCall("RedisModule_WrongArity");
102     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  3);
103     CHECK_EQUAL(ret, REDISMODULE_ERR);
104     mock().checkExpectations();
105
106     delete []redisStrVec;
107 }
108
109 TEST(exstrings_nget, nget_atomic_command_3rd_parameter_was_not_equal_to_COUNT)
110 {
111     RedisModuleCtx ctx;
112     RedisModuleString ** redisStrVec = createRedisStrVec(4);
113     const char * not_count_literal = "NOT_COUNT";
114     size_t not_count_len = strlen(not_count_literal);
115
116     mock().expectOneCall("RedisModule_StringPtrLen")
117           .withOutputParameterReturning("len", &not_count_len, sizeof(size_t))
118           .andReturnValue((void*)not_count_literal);
119     mock().expectOneCall("RedisModule_ReplyWithError");
120     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  4);
121     CHECK_EQUAL(ret, REDISMODULE_ERR);
122     mock().checkExpectations();
123
124     delete []redisStrVec;
125 }
126
127 TEST(exstrings_nget, nget_atomic_command_4th_parameter_was_not_integer)
128 {
129     RedisModuleCtx ctx;
130     RedisModuleString ** redisStrVec = createRedisStrVec(4);
131     const char * count_literal = "COUNT";
132     size_t count_len = strlen(count_literal);
133     size_t count_number = 123;
134
135     mock().expectOneCall("RedisModule_StringPtrLen")
136           .withOutputParameterReturning("len", &count_len, sizeof(size_t))
137           .andReturnValue((void*)count_literal);
138     mock().expectOneCall("RedisModule_StringToLongLong")
139           .withOutputParameterReturning("ll", &count_number, sizeof(size_t))
140           .andReturnValue(REDISMODULE_ERR);
141     mock().expectOneCall("RedisModule_ReplyWithError");
142     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  4);
143     CHECK_EQUAL(ret, REDISMODULE_ERR);
144     mock().checkExpectations();
145
146     delete []redisStrVec;
147 }
148
149 TEST(exstrings_nget, nget_atomic_command_4th_parameter_was_negative)
150 {
151     RedisModuleCtx ctx;
152     RedisModuleString ** redisStrVec = createRedisStrVec(4);
153     const char * count_literal = "COUNT";
154     size_t count_len = strlen(count_literal);
155     size_t count_number = -123;
156
157     mock().expectOneCall("RedisModule_StringPtrLen")
158           .withOutputParameterReturning("len", &count_len, sizeof(size_t))
159           .andReturnValue((void*)count_literal);
160     mock().expectOneCall("RedisModule_StringToLongLong")
161           .withOutputParameterReturning("ll", &count_number, sizeof(size_t))
162           .andReturnValue(REDISMODULE_OK);
163     mock().expectOneCall("RedisModule_ReplyWithError");
164     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  4);
165     CHECK_EQUAL(ret, REDISMODULE_ERR);
166     mock().checkExpectations();
167
168     delete []redisStrVec;
169 }
170
171 TEST(exstrings_nget, nget_atomic_command_scan_returned_zero_keys)
172 {
173     RedisModuleCtx ctx;
174     RedisModuleString ** redisStrVec = createRedisStrVec(2);
175
176     mock().expectOneCall("RedisModule_ReplyWithArray")
177           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
178     mock().expectOneCall("RedisModule_Call")
179           .withParameter("cmdname", "SCAN");
180     returnNKeysFromScanSome(0);
181     expectNReplies(0);
182     mock().expectNoCall("RedisModule_Call");
183
184     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  2);
185     CHECK_EQUAL(ret, REDISMODULE_OK);
186     mock().checkExpectations();
187
188     delete []redisStrVec;
189 }
190
191 TEST(exstrings_nget, nget_atomic_command_3_keys_scanned_0_keys_mget)
192 {
193     RedisModuleCtx ctx;
194     RedisModuleString ** redisStrVec = createRedisStrVec(2);
195
196     mock().ignoreOtherCalls();
197     mock().expectOneCall("RedisModule_ReplyWithArray")
198           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
199
200     mock().expectOneCall("RedisModule_Call")
201           .withParameter("cmdname", "SCAN");
202     returnNKeysFromScanSome(3);
203     mock().expectOneCall("RedisModule_FreeCallReply");
204     mock().expectOneCall("RedisModule_Call")
205           .withParameter("cmdname", "MGET");
206     nKeysNotFoundMget(3);
207     mock().expectOneCall("RedisModule_FreeCallReply");
208     expectNReplies(0);
209     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  2);
210     CHECK_EQUAL(ret, REDISMODULE_OK);
211     mock().checkExpectations();
212
213     delete []redisStrVec;
214 }
215
216 TEST(exstrings_nget, nget_atomic_command_3_keys_scanned_3_keys_mget)
217 {
218     RedisModuleCtx ctx;
219     RedisModuleString ** redisStrVec = createRedisStrVec(2);
220
221     mock().ignoreOtherCalls();
222     mock().expectOneCall("RedisModule_ReplyWithArray")
223           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
224     mock().expectOneCall("RedisModule_Call")
225           .withParameter("cmdname", "SCAN");
226     returnNKeysFromScanSome(3);
227     mock().expectOneCall("RedisModule_FreeCallReply");
228     mock().expectOneCall("RedisModule_Call")
229           .withParameter("cmdname", "MGET");
230     nKeysFoundMget(3);
231     mock().expectOneCall("RedisModule_FreeCallReply");
232     expectNReplies(3);
233     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  2);
234     CHECK_EQUAL(ret, REDISMODULE_OK);
235     mock().checkExpectations();
236
237     delete []redisStrVec;
238 }
239
240 TEST(exstrings_nget, nget_atomic_command_3_keys_scanned_2_keys_mget)
241 {
242     RedisModuleCtx ctx;
243     RedisModuleString ** redisStrVec = createRedisStrVec(2);
244
245     mock().ignoreOtherCalls();
246     mock().expectOneCall("RedisModule_ReplyWithArray")
247           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
248     mock().expectOneCall("RedisModule_Call")
249           .withParameter("cmdname", "SCAN");
250     returnNKeysFromScanSome(3);
251     mock().expectOneCall("RedisModule_FreeCallReply");
252     mock().expectOneCall("RedisModule_Call")
253           .withParameter("cmdname", "MGET");
254     nKeysFoundMget(2);
255     nKeysNotFoundMget(1);
256     mock().expectOneCall("RedisModule_FreeCallReply");
257     expectNReplies(2);
258     int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec,  2);
259     CHECK_EQUAL(ret, REDISMODULE_OK);
260     mock().checkExpectations();
261
262     delete []redisStrVec;
263 }
264
265 TEST(exstrings_nget, nget_noatomic_automemory_enabled)
266 {
267     RedisModuleCtx ctx;
268     RedisModuleString ** redisStrVec = createRedisStrVec(2);
269
270     mock().setData("pthread_create_free_block_client_args", 1);
271
272     mock().ignoreOtherCalls();
273     mock().expectOneCall("RedisModule_AutoMemory");
274
275     int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec,  2);
276     CHECK_EQUAL(ret, REDISMODULE_OK);
277     mock().checkExpectations();
278
279     delete []redisStrVec;
280 }
281
282 TEST(exstrings_nget, nget_noatomic_thread_create_success)
283 {
284     RedisModuleCtx ctx;
285     RedisModuleString ** redisStrVec = createRedisStrVec(2);
286
287     mock().setData("pthread_create_free_block_client_args", 1);
288
289     mock().ignoreOtherCalls();
290     mock().expectOneCall("RedisModule_BlockClient");
291     mock().expectOneCall("pthread_create");
292     mock().expectNoCall("RedisModule_AbortBlock");
293
294     int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec,  2);
295     CHECK_EQUAL(ret, REDISMODULE_OK);
296     mock().checkExpectations();
297
298     delete []redisStrVec;
299 }
300
301 TEST(exstrings_nget, nget_noatomic_thread_create_fail)
302 {
303     RedisModuleCtx ctx;
304     RedisModuleString ** redisStrVec = createRedisStrVec(2);
305
306     mock().ignoreOtherCalls();
307     mock().expectOneCall("RedisModule_BlockClient");
308     mock().expectOneCall("pthread_create")
309           .andReturnValue(1);
310     mock().expectOneCall("RedisModule_AbortBlock");
311
312     int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec,  2);
313     CHECK_EQUAL(ret, REDISMODULE_OK);
314     mock().checkExpectations();
315
316     delete []redisStrVec;
317 }
318
319 TEST(exstrings_nget, nget_noatomic_parameter_number_incorrect)
320 {
321     RedisModuleCtx ctx;
322     RedisModuleString ** redisStrVec = createRedisStrVec(4);
323
324     mock().expectOneCall("RedisModule_WrongArity");
325     mock().expectNoCall("RedisModule_BlockClient");
326
327     int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec,  3);
328
329     CHECK_EQUAL(ret, REDISMODULE_ERR);
330     mock().checkExpectations();
331
332     delete []redisStrVec;
333 }
334
335 TEST(exstrings_nget, nget_noatomic_threadmain_3rd_parameter_was_not_equal_to_COUNT)
336 {
337     RedisModuleCtx ctx;
338     RedisModuleString ** redisStrVec = createRedisStrVec(4);
339     const char * not_count_literal = "NOT_COUNT";
340     size_t not_count_len = strlen(not_count_literal);
341
342     mock().expectOneCall("RedisModule_StringPtrLen")
343           .withOutputParameterReturning("len", &not_count_len, sizeof(size_t))
344           .andReturnValue((void*)not_count_literal);
345     mock().expectOneCall("RedisModule_ReplyWithError");
346     mock().expectNoCall("RedisModule_BlockClient");
347
348     int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec,  4);
349
350     CHECK_EQUAL(ret, REDISMODULE_ERR);
351
352     mock().checkExpectations();
353     threadSafeContextLockedAndUnlockedEqualTimes();
354
355     delete []redisStrVec;
356 }
357
358 TEST(exstrings_nget, nget_noatomic_4th_parameter_was_not_integer)
359 {
360     RedisModuleCtx ctx;
361     const char * count_literal = "COUNT";
362     size_t count_len = strlen(count_literal);
363     size_t count_number = -123;
364     RedisModuleString ** redisStrVec = createRedisStrVec(4);
365
366     mock().expectOneCall("RedisModule_StringPtrLen")
367           .withOutputParameterReturning("len", &count_len, sizeof(size_t))
368           .andReturnValue((void*)count_literal);
369     mock().expectOneCall("RedisModule_StringToLongLong")
370           .withOutputParameterReturning("ll", &count_number, sizeof(size_t))
371           .andReturnValue(REDISMODULE_OK);
372     mock().expectOneCall("RedisModule_ReplyWithError");
373
374     int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec,  4);
375
376     CHECK_EQUAL(ret, REDISMODULE_ERR);
377     mock().checkExpectations();
378     threadSafeContextLockedAndUnlockedEqualTimes();
379
380     delete []redisStrVec;
381 }
382
383 typedef struct RedisModuleBlockedClientArgs {
384     RedisModuleBlockedClient *bc;
385     RedisModuleString **argv;
386     int argc;
387 } RedisModuleBlockedClientArgs;
388
389 TEST(exstrings_nget, nget_noatomic_threadmain_3_keys_scanned_3_keys_mget)
390 {
391     RedisModuleCtx ctx;
392     RedisModuleBlockedClientArgs *bca =
393         (RedisModuleBlockedClientArgs*)RedisModule_Alloc(sizeof(RedisModuleBlockedClientArgs));
394     RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
395     RedisModuleString ** redisStrVec = createRedisStrVec(2);
396
397     bca->bc = bc;
398     bca->argv = redisStrVec;
399     bca->argc = 2;
400
401     mock().ignoreOtherCalls();
402     mock().expectOneCall("RedisModule_ReplyWithArray")
403           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
404     mock().expectOneCall("RedisModule_Call")
405           .withParameter("cmdname", "SCAN");
406     returnNKeysFromScanSome(3);
407     mock().expectOneCall("RedisModule_FreeCallReply");
408     mock().expectOneCall("RedisModule_Call")
409           .withParameter("cmdname", "MGET");
410     nKeysFoundMget(3);
411     mock().expectOneCall("RedisModule_FreeCallReply");
412     expectNReplies(3);
413     mock().expectOneCall("RedisModule_FreeThreadSafeContext");
414     mock().expectOneCall("RedisModule_UnblockClient");
415
416     NGet_NoAtomic_ThreadMain((void*)bca);
417
418     mock().checkExpectations();
419     threadSafeContextLockedAndUnlockedEqualTimes();
420
421     delete []redisStrVec;
422 }
423
424 TEST(exstrings_nget, nget_noatomic_threadmain_3_keys_scanned_0_keys_mget)
425 {
426     RedisModuleCtx ctx;
427     RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
428     RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
429     RedisModuleString ** redisStrVec = createRedisStrVec(2);
430
431     bca->bc = bc;
432     bca->argv = redisStrVec;
433     bca->argc = 2;
434
435     mock().ignoreOtherCalls();
436     mock().expectOneCall("RedisModule_ReplyWithArray")
437           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
438     mock().expectOneCall("RedisModule_Call")
439           .withParameter("cmdname", "SCAN");
440     returnNKeysFromScanSome(3);
441     mock().expectOneCall("RedisModule_FreeCallReply");
442     mock().expectOneCall("RedisModule_Call")
443           .withParameter("cmdname", "MGET");
444     nKeysNotFoundMget(3);
445     mock().expectOneCall("RedisModule_FreeCallReply");
446     expectNReplies(0);
447     mock().expectOneCall("RedisModule_FreeThreadSafeContext");
448     mock().expectOneCall("RedisModule_UnblockClient");
449
450     NGet_NoAtomic_ThreadMain((void*)bca);
451
452     mock().checkExpectations();
453     threadSafeContextLockedAndUnlockedEqualTimes();
454
455     delete []redisStrVec;
456 }
457
458 TEST(exstrings_nget, nget_noatomic_threadmain_3_keys_scanned_2_keys_mget)
459 {
460     RedisModuleCtx ctx;
461     RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
462     RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
463     RedisModuleString ** redisStrVec = createRedisStrVec(2);
464
465     bca->bc = bc;
466     bca->argv = redisStrVec;
467     bca->argc = 2;
468
469     mock().ignoreOtherCalls();
470     mock().expectOneCall("RedisModule_ReplyWithArray")
471           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
472     mock().expectOneCall("RedisModule_Call")
473           .withParameter("cmdname", "SCAN");
474     returnNKeysFromScanSome(3);
475     mock().expectOneCall("RedisModule_FreeCallReply");
476     mock().expectOneCall("RedisModule_Call")
477           .withParameter("cmdname", "MGET");
478     nKeysNotFoundMget(1);
479     nKeysFoundMget(2);
480     mock().expectOneCall("RedisModule_FreeCallReply");
481     expectNReplies(2);
482     mock().expectOneCall("RedisModule_FreeThreadSafeContext");
483     mock().expectOneCall("RedisModule_UnblockClient");
484
485     NGet_NoAtomic_ThreadMain((void*)bca);
486
487     mock().checkExpectations();
488     threadSafeContextLockedAndUnlockedEqualTimes();
489
490     delete []redisStrVec;
491 }
492
493 TEST(exstrings_nget, nget_noatomic_threadmain_scan_returned_zero_keys)
494 {
495     RedisModuleCtx ctx;
496     RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
497     RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
498     RedisModuleString ** redisStrVec = createRedisStrVec(2);
499
500     bca->bc = bc;
501     bca->argv = redisStrVec;
502     bca->argc = 2;
503
504     mock().ignoreOtherCalls();
505     mock().expectOneCall("RedisModule_ReplyWithArray")
506           .withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
507     mock().expectOneCall("RedisModule_Call")
508           .withParameter("cmdname", "SCAN");
509     returnNKeysFromScanSome(0);
510     mock().expectOneCall("RedisModule_FreeCallReply");
511     mock().expectNoCall("RedisModule_Call");
512     mock().expectOneCall("RedisModule_FreeThreadSafeContext");
513     mock().expectOneCall("RedisModule_UnblockClient");
514
515     NGet_NoAtomic_ThreadMain((void*)bca);
516
517     mock().checkExpectations();
518     threadSafeContextLockedAndUnlockedEqualTimes();
519
520     delete []redisStrVec;
521 }