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