aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/tests/modules/basics.c
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
commitdcacc00e3750300617ba6e16eb346713f91a783a (patch)
tree38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/tests/modules/basics.c
parent58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff)
downloadcrep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz
Remove testing data
Diffstat (limited to 'examples/redis-unstable/tests/modules/basics.c')
-rw-r--r--examples/redis-unstable/tests/modules/basics.c1051
1 files changed, 0 insertions, 1051 deletions
diff --git a/examples/redis-unstable/tests/modules/basics.c b/examples/redis-unstable/tests/modules/basics.c
deleted file mode 100644
index 85c6196..0000000
--- a/examples/redis-unstable/tests/modules/basics.c
+++ /dev/null
@@ -1,1051 +0,0 @@
1/* Module designed to test the Redis modules subsystem.
2 *
3 * -----------------------------------------------------------------------------
4 *
5 * Copyright (c) 2016-Present, Redis Ltd.
6 * All rights reserved.
7 *
8 * Licensed under your choice of (a) the Redis Source Available License 2.0
9 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
10 * GNU Affero General Public License v3 (AGPLv3).
11 */
12
13#include "redismodule.h"
14#include <string.h>
15#include <stdlib.h>
16
17/* --------------------------------- Helpers -------------------------------- */
18
19/* Return true if the reply and the C null term string matches. */
20int TestMatchReply(RedisModuleCallReply *reply, char *str) {
21 RedisModuleString *mystr;
22 mystr = RedisModule_CreateStringFromCallReply(reply);
23 if (!mystr) return 0;
24 const char *ptr = RedisModule_StringPtrLen(mystr,NULL);
25 return strcmp(ptr,str) == 0;
26}
27
28/* ------------------------------- Test units ------------------------------- */
29
30/* TEST.CALL -- Test Call() API. */
31int TestCall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
32 REDISMODULE_NOT_USED(argv);
33 REDISMODULE_NOT_USED(argc);
34
35 RedisModule_AutoMemory(ctx);
36 RedisModuleCallReply *reply;
37
38 RedisModule_Call(ctx,"DEL","c","mylist");
39 RedisModuleString *mystr = RedisModule_CreateString(ctx,"foo",3);
40 RedisModule_Call(ctx,"RPUSH","csl","mylist",mystr,(long long)1234);
41 reply = RedisModule_Call(ctx,"LRANGE","ccc","mylist","0","-1");
42 long long items = RedisModule_CallReplyLength(reply);
43 if (items != 2) goto fail;
44
45 RedisModuleCallReply *item0, *item1;
46
47 item0 = RedisModule_CallReplyArrayElement(reply,0);
48 item1 = RedisModule_CallReplyArrayElement(reply,1);
49 if (!TestMatchReply(item0,"foo")) goto fail;
50 if (!TestMatchReply(item1,"1234")) goto fail;
51
52 RedisModule_ReplyWithSimpleString(ctx,"OK");
53 return REDISMODULE_OK;
54
55fail:
56 RedisModule_ReplyWithSimpleString(ctx,"ERR");
57 return REDISMODULE_OK;
58}
59
60int TestCallResp3Attribute(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
61 REDISMODULE_NOT_USED(argv);
62 REDISMODULE_NOT_USED(argc);
63
64 RedisModule_AutoMemory(ctx);
65 RedisModuleCallReply *reply;
66
67 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "attrib"); /* 3 stands for resp 3 reply */
68 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_STRING) goto fail;
69
70 /* make sure we can not reply to resp2 client with resp3 (it might be a string but it contains attribute) */
71 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
72
73 if (!TestMatchReply(reply,"Some real reply following the attribute")) goto fail;
74
75 reply = RedisModule_CallReplyAttribute(reply);
76 if (!reply || RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_ATTRIBUTE) goto fail;
77 /* make sure we can not reply to resp2 client with resp3 attribute */
78 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
79 if (RedisModule_CallReplyLength(reply) != 1) goto fail;
80
81 RedisModuleCallReply *key, *val;
82 if (RedisModule_CallReplyAttributeElement(reply,0,&key,&val) != REDISMODULE_OK) goto fail;
83 if (!TestMatchReply(key,"key-popularity")) goto fail;
84 if (RedisModule_CallReplyType(val) != REDISMODULE_REPLY_ARRAY) goto fail;
85 if (RedisModule_CallReplyLength(val) != 2) goto fail;
86 if (!TestMatchReply(RedisModule_CallReplyArrayElement(val, 0),"key:123")) goto fail;
87 if (!TestMatchReply(RedisModule_CallReplyArrayElement(val, 1),"90")) goto fail;
88
89 RedisModule_ReplyWithSimpleString(ctx,"OK");
90 return REDISMODULE_OK;
91
92fail:
93 RedisModule_ReplyWithSimpleString(ctx,"ERR");
94 return REDISMODULE_OK;
95}
96
97int TestGetResp(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
98 REDISMODULE_NOT_USED(argv);
99 REDISMODULE_NOT_USED(argc);
100
101 int flags = RedisModule_GetContextFlags(ctx);
102
103 if (flags & REDISMODULE_CTX_FLAGS_RESP3) {
104 RedisModule_ReplyWithLongLong(ctx, 3);
105 } else {
106 RedisModule_ReplyWithLongLong(ctx, 2);
107 }
108
109 return REDISMODULE_OK;
110}
111
112int TestCallRespAutoMode(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
113 REDISMODULE_NOT_USED(argv);
114 REDISMODULE_NOT_USED(argc);
115
116 RedisModule_AutoMemory(ctx);
117 RedisModuleCallReply *reply;
118
119 RedisModule_Call(ctx,"DEL","c","myhash");
120 RedisModule_Call(ctx,"HSET","ccccc","myhash", "f1", "v1", "f2", "v2");
121 /* 0 stands for auto mode, we will get the reply in the same format as the client */
122 reply = RedisModule_Call(ctx,"HGETALL","0c" ,"myhash");
123 RedisModule_ReplyWithCallReply(ctx, reply);
124 return REDISMODULE_OK;
125}
126
127int TestCallResp3Map(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
128 REDISMODULE_NOT_USED(argv);
129 REDISMODULE_NOT_USED(argc);
130
131 RedisModule_AutoMemory(ctx);
132 RedisModuleCallReply *reply;
133
134 RedisModule_Call(ctx,"DEL","c","myhash");
135 RedisModule_Call(ctx,"HSET","ccccc","myhash", "f1", "v1", "f2", "v2");
136 reply = RedisModule_Call(ctx,"HGETALL","3c" ,"myhash"); /* 3 stands for resp 3 reply */
137 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_MAP) goto fail;
138
139 /* make sure we can not reply to resp2 client with resp3 map */
140 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
141
142 long long items = RedisModule_CallReplyLength(reply);
143 if (items != 2) goto fail;
144
145 RedisModuleCallReply *key0, *key1;
146 RedisModuleCallReply *val0, *val1;
147 if (RedisModule_CallReplyMapElement(reply,0,&key0,&val0) != REDISMODULE_OK) goto fail;
148 if (RedisModule_CallReplyMapElement(reply,1,&key1,&val1) != REDISMODULE_OK) goto fail;
149 if (!TestMatchReply(key0,"f1")) goto fail;
150 if (!TestMatchReply(key1,"f2")) goto fail;
151 if (!TestMatchReply(val0,"v1")) goto fail;
152 if (!TestMatchReply(val1,"v2")) goto fail;
153
154 RedisModule_ReplyWithSimpleString(ctx,"OK");
155 return REDISMODULE_OK;
156
157fail:
158 RedisModule_ReplyWithSimpleString(ctx,"ERR");
159 return REDISMODULE_OK;
160}
161
162int TestCallResp3Bool(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
163 REDISMODULE_NOT_USED(argv);
164 REDISMODULE_NOT_USED(argc);
165
166 RedisModule_AutoMemory(ctx);
167 RedisModuleCallReply *reply;
168
169 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "true"); /* 3 stands for resp 3 reply */
170 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_BOOL) goto fail;
171 /* make sure we can not reply to resp2 client with resp3 bool */
172 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
173
174 if (!RedisModule_CallReplyBool(reply)) goto fail;
175 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "false"); /* 3 stands for resp 3 reply */
176 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_BOOL) goto fail;
177 if (RedisModule_CallReplyBool(reply)) goto fail;
178
179 RedisModule_ReplyWithSimpleString(ctx,"OK");
180 return REDISMODULE_OK;
181
182fail:
183 RedisModule_ReplyWithSimpleString(ctx,"ERR");
184 return REDISMODULE_OK;
185}
186
187int TestCallResp3Null(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
188 REDISMODULE_NOT_USED(argv);
189 REDISMODULE_NOT_USED(argc);
190
191 RedisModule_AutoMemory(ctx);
192 RedisModuleCallReply *reply;
193
194 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "null"); /* 3 stands for resp 3 reply */
195 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_NULL) goto fail;
196
197 /* make sure we can not reply to resp2 client with resp3 null */
198 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
199
200 RedisModule_ReplyWithSimpleString(ctx,"OK");
201 return REDISMODULE_OK;
202
203fail:
204 RedisModule_ReplyWithSimpleString(ctx,"ERR");
205 return REDISMODULE_OK;
206}
207
208int TestCallReplyWithNestedReply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
209 REDISMODULE_NOT_USED(argv);
210 REDISMODULE_NOT_USED(argc);
211
212 RedisModule_AutoMemory(ctx);
213 RedisModuleCallReply *reply;
214
215 RedisModule_Call(ctx,"DEL","c","mylist");
216 RedisModule_Call(ctx,"RPUSH","ccl","mylist","test",(long long)1234);
217 reply = RedisModule_Call(ctx,"LRANGE","ccc","mylist","0","-1");
218 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_ARRAY) goto fail;
219 if (RedisModule_CallReplyLength(reply) < 1) goto fail;
220 RedisModuleCallReply *nestedReply = RedisModule_CallReplyArrayElement(reply, 0);
221
222 RedisModule_ReplyWithCallReply(ctx,nestedReply);
223 return REDISMODULE_OK;
224
225fail:
226 RedisModule_ReplyWithSimpleString(ctx,"ERR");
227 return REDISMODULE_OK;
228}
229
230int TestCallReplyWithArrayReply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
231 REDISMODULE_NOT_USED(argv);
232 REDISMODULE_NOT_USED(argc);
233
234 RedisModule_AutoMemory(ctx);
235 RedisModuleCallReply *reply;
236
237 RedisModule_Call(ctx,"DEL","c","mylist");
238 RedisModule_Call(ctx,"RPUSH","ccl","mylist","test",(long long)1234);
239 reply = RedisModule_Call(ctx,"LRANGE","ccc","mylist","0","-1");
240 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_ARRAY) goto fail;
241
242 RedisModule_ReplyWithCallReply(ctx,reply);
243 return REDISMODULE_OK;
244
245fail:
246 RedisModule_ReplyWithSimpleString(ctx,"ERR");
247 return REDISMODULE_OK;
248}
249
250int TestCallResp3Double(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
251 REDISMODULE_NOT_USED(argv);
252 REDISMODULE_NOT_USED(argc);
253
254 RedisModule_AutoMemory(ctx);
255 RedisModuleCallReply *reply;
256
257 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "double"); /* 3 stands for resp 3 reply */
258 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_DOUBLE) goto fail;
259
260 /* make sure we can not reply to resp2 client with resp3 double*/
261 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
262
263 double d = RedisModule_CallReplyDouble(reply);
264 /* we compare strings, since comparing doubles directly can fail in various architectures, e.g. 32bit */
265 char got[30], expected[30];
266 snprintf(got, sizeof(got), "%.17g", d);
267 snprintf(expected, sizeof(expected), "%.17g", 3.141);
268 if (strcmp(got, expected) != 0) goto fail;
269 RedisModule_ReplyWithSimpleString(ctx,"OK");
270 return REDISMODULE_OK;
271
272fail:
273 RedisModule_ReplyWithSimpleString(ctx,"ERR");
274 return REDISMODULE_OK;
275}
276
277int TestCallResp3BigNumber(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
278 REDISMODULE_NOT_USED(argv);
279 REDISMODULE_NOT_USED(argc);
280
281 RedisModule_AutoMemory(ctx);
282 RedisModuleCallReply *reply;
283
284 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "bignum"); /* 3 stands for resp 3 reply */
285 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_BIG_NUMBER) goto fail;
286
287 /* make sure we can not reply to resp2 client with resp3 big number */
288 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
289
290 size_t len;
291 const char* big_num = RedisModule_CallReplyBigNumber(reply, &len);
292 RedisModule_ReplyWithStringBuffer(ctx,big_num,len);
293 return REDISMODULE_OK;
294
295fail:
296 RedisModule_ReplyWithSimpleString(ctx,"ERR");
297 return REDISMODULE_OK;
298}
299
300int TestCallResp3Verbatim(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
301 REDISMODULE_NOT_USED(argv);
302 REDISMODULE_NOT_USED(argc);
303
304 RedisModule_AutoMemory(ctx);
305 RedisModuleCallReply *reply;
306
307 reply = RedisModule_Call(ctx,"DEBUG","3cc" ,"PROTOCOL", "verbatim"); /* 3 stands for resp 3 reply */
308 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_VERBATIM_STRING) goto fail;
309
310 /* make sure we can not reply to resp2 client with resp3 verbatim string */
311 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
312
313 const char* format;
314 size_t len;
315 const char* str = RedisModule_CallReplyVerbatim(reply, &len, &format);
316 RedisModuleString *s = RedisModule_CreateStringPrintf(ctx, "%.*s:%.*s", 3, format, (int)len, str);
317 RedisModule_ReplyWithString(ctx,s);
318 return REDISMODULE_OK;
319
320fail:
321 RedisModule_ReplyWithSimpleString(ctx,"ERR");
322 return REDISMODULE_OK;
323}
324
325int TestCallResp3Set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
326 REDISMODULE_NOT_USED(argv);
327 REDISMODULE_NOT_USED(argc);
328
329 RedisModule_AutoMemory(ctx);
330 RedisModuleCallReply *reply;
331
332 RedisModule_Call(ctx,"DEL","c","myset");
333 RedisModule_Call(ctx,"sadd","ccc","myset", "v1", "v2");
334 reply = RedisModule_Call(ctx,"smembers","3c" ,"myset"); // N stands for resp 3 reply
335 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_SET) goto fail;
336
337 /* make sure we can not reply to resp2 client with resp3 set */
338 if (RedisModule_ReplyWithCallReply(ctx, reply) != REDISMODULE_ERR) goto fail;
339
340 long long items = RedisModule_CallReplyLength(reply);
341 if (items != 2) goto fail;
342
343 RedisModuleCallReply *val0, *val1;
344
345 val0 = RedisModule_CallReplySetElement(reply,0);
346 val1 = RedisModule_CallReplySetElement(reply,1);
347
348 /*
349 * The order of elements on sets are not promised so we just
350 * veridy that the reply matches one of the elements.
351 */
352 if (!TestMatchReply(val0,"v1") && !TestMatchReply(val0,"v2")) goto fail;
353 if (!TestMatchReply(val1,"v1") && !TestMatchReply(val1,"v2")) goto fail;
354
355 RedisModule_ReplyWithSimpleString(ctx,"OK");
356 return REDISMODULE_OK;
357
358fail:
359 RedisModule_ReplyWithSimpleString(ctx,"ERR");
360 return REDISMODULE_OK;
361}
362
363/* TEST.STRING.APPEND -- Test appending to an existing string object. */
364int TestStringAppend(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
365 REDISMODULE_NOT_USED(argv);
366 REDISMODULE_NOT_USED(argc);
367
368 RedisModuleString *s = RedisModule_CreateString(ctx,"foo",3);
369 RedisModule_StringAppendBuffer(ctx,s,"bar",3);
370 RedisModule_ReplyWithString(ctx,s);
371 RedisModule_FreeString(ctx,s);
372 return REDISMODULE_OK;
373}
374
375/* TEST.STRING.APPEND.AM -- Test append with retain when auto memory is on. */
376int TestStringAppendAM(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
377 REDISMODULE_NOT_USED(argv);
378 REDISMODULE_NOT_USED(argc);
379
380 RedisModule_AutoMemory(ctx);
381 RedisModuleString *s = RedisModule_CreateString(ctx,"foo",3);
382 RedisModule_RetainString(ctx,s);
383 RedisModule_TrimStringAllocation(s); /* Mostly NOP, but exercises the API function */
384 RedisModule_StringAppendBuffer(ctx,s,"bar",3);
385 RedisModule_ReplyWithString(ctx,s);
386 RedisModule_FreeString(ctx,s);
387 return REDISMODULE_OK;
388}
389
390/* TEST.STRING.TRIM -- Test we trim a string with free space. */
391int TestTrimString(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
392 REDISMODULE_NOT_USED(argv);
393 REDISMODULE_NOT_USED(argc);
394 RedisModuleString *s = RedisModule_CreateString(ctx,"foo",3);
395 char *tmp = RedisModule_Alloc(1024);
396 RedisModule_StringAppendBuffer(ctx,s,tmp,1024);
397 size_t string_len = RedisModule_MallocSizeString(s);
398 RedisModule_TrimStringAllocation(s);
399 size_t len_after_trim = RedisModule_MallocSizeString(s);
400
401 /* Determine if using jemalloc memory allocator. */
402 RedisModuleServerInfoData *info = RedisModule_GetServerInfo(ctx, "memory");
403 const char *field = RedisModule_ServerInfoGetFieldC(info, "mem_allocator");
404 int use_jemalloc = !strncmp(field, "jemalloc", 8);
405
406 /* Jemalloc will reallocate `s` from 2k to 1k after RedisModule_TrimStringAllocation(),
407 * but non-jemalloc memory allocators may keep the old size. */
408 if ((use_jemalloc && len_after_trim < string_len) ||
409 (!use_jemalloc && len_after_trim <= string_len))
410 {
411 RedisModule_ReplyWithSimpleString(ctx, "OK");
412 } else {
413 RedisModule_ReplyWithError(ctx, "String was not trimmed as expected.");
414 }
415 RedisModule_FreeServerInfo(ctx, info);
416 RedisModule_Free(tmp);
417 RedisModule_FreeString(ctx,s);
418 return REDISMODULE_OK;
419}
420
421/* TEST.STRING.PRINTF -- Test string formatting. */
422int TestStringPrintf(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
423 RedisModule_AutoMemory(ctx);
424 if (argc < 3) {
425 return RedisModule_WrongArity(ctx);
426 }
427 RedisModuleString *s = RedisModule_CreateStringPrintf(ctx,
428 "Got %d args. argv[1]: %s, argv[2]: %s",
429 argc,
430 RedisModule_StringPtrLen(argv[1], NULL),
431 RedisModule_StringPtrLen(argv[2], NULL)
432 );
433
434 RedisModule_ReplyWithString(ctx,s);
435
436 return REDISMODULE_OK;
437}
438
439int failTest(RedisModuleCtx *ctx, const char *msg) {
440 RedisModule_ReplyWithError(ctx, msg);
441 return REDISMODULE_ERR;
442}
443
444int TestUnlink(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
445 RedisModule_AutoMemory(ctx);
446 REDISMODULE_NOT_USED(argv);
447 REDISMODULE_NOT_USED(argc);
448
449 RedisModuleKey *k = RedisModule_OpenKey(ctx, RedisModule_CreateStringPrintf(ctx, "unlinked"), REDISMODULE_WRITE | REDISMODULE_READ);
450 if (!k) return failTest(ctx, "Could not create key");
451
452 if (REDISMODULE_ERR == RedisModule_StringSet(k, RedisModule_CreateStringPrintf(ctx, "Foobar"))) {
453 return failTest(ctx, "Could not set string value");
454 }
455
456 RedisModuleCallReply *rep = RedisModule_Call(ctx, "EXISTS", "c", "unlinked");
457 if (!rep || RedisModule_CallReplyInteger(rep) != 1) {
458 return failTest(ctx, "Key does not exist before unlink");
459 }
460
461 if (REDISMODULE_ERR == RedisModule_UnlinkKey(k)) {
462 return failTest(ctx, "Could not unlink key");
463 }
464
465 rep = RedisModule_Call(ctx, "EXISTS", "c", "unlinked");
466 if (!rep || RedisModule_CallReplyInteger(rep) != 0) {
467 return failTest(ctx, "Could not verify key to be unlinked");
468 }
469 return RedisModule_ReplyWithSimpleString(ctx, "OK");
470}
471
472int TestNestedCallReplyArrayElement(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
473 RedisModule_AutoMemory(ctx);
474 REDISMODULE_NOT_USED(argv);
475 REDISMODULE_NOT_USED(argc);
476
477 RedisModuleString *expect_key = RedisModule_CreateString(ctx, "mykey", strlen("mykey"));
478 RedisModule_SelectDb(ctx, 1);
479 RedisModule_Call(ctx, "LPUSH", "sc", expect_key, "myvalue");
480
481 RedisModuleCallReply *scan_reply = RedisModule_Call(ctx, "SCAN", "l", (long long)0);
482 RedisModule_Assert(scan_reply != NULL && RedisModule_CallReplyType(scan_reply) == REDISMODULE_REPLY_ARRAY);
483 RedisModule_Assert(RedisModule_CallReplyLength(scan_reply) == 2);
484
485 long long scan_cursor;
486 RedisModuleCallReply *cursor_reply = RedisModule_CallReplyArrayElement(scan_reply, 0);
487 RedisModule_Assert(RedisModule_CallReplyType(cursor_reply) == REDISMODULE_REPLY_STRING);
488 RedisModule_Assert(RedisModule_StringToLongLong(RedisModule_CreateStringFromCallReply(cursor_reply), &scan_cursor) == REDISMODULE_OK);
489 RedisModule_Assert(scan_cursor == 0);
490
491 RedisModuleCallReply *keys_reply = RedisModule_CallReplyArrayElement(scan_reply, 1);
492 RedisModule_Assert(RedisModule_CallReplyType(keys_reply) == REDISMODULE_REPLY_ARRAY);
493 RedisModule_Assert( RedisModule_CallReplyLength(keys_reply) == 1);
494
495 RedisModuleCallReply *key_reply = RedisModule_CallReplyArrayElement(keys_reply, 0);
496 RedisModule_Assert(RedisModule_CallReplyType(key_reply) == REDISMODULE_REPLY_STRING);
497 RedisModuleString *key = RedisModule_CreateStringFromCallReply(key_reply);
498 RedisModule_Assert(RedisModule_StringCompare(key, expect_key) == 0);
499
500 RedisModule_ReplyWithSimpleString(ctx, "OK");
501 return REDISMODULE_OK;
502}
503
504/* TEST.STRING.TRUNCATE -- Test truncating an existing string object. */
505int TestStringTruncate(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
506 RedisModule_AutoMemory(ctx);
507 REDISMODULE_NOT_USED(argv);
508 REDISMODULE_NOT_USED(argc);
509
510 RedisModule_Call(ctx, "SET", "cc", "foo", "abcde");
511 RedisModuleKey *k = RedisModule_OpenKey(ctx, RedisModule_CreateStringPrintf(ctx, "foo"), REDISMODULE_READ | REDISMODULE_WRITE);
512 if (!k) return failTest(ctx, "Could not create key");
513
514 size_t len = 0;
515 char* s;
516
517 /* expand from 5 to 8 and check null pad */
518 if (REDISMODULE_ERR == RedisModule_StringTruncate(k, 8)) {
519 return failTest(ctx, "Could not truncate string value (8)");
520 }
521 s = RedisModule_StringDMA(k, &len, REDISMODULE_READ);
522 if (!s) {
523 return failTest(ctx, "Failed to read truncated string (8)");
524 } else if (len != 8) {
525 return failTest(ctx, "Failed to expand string value (8)");
526 } else if (0 != strncmp(s, "abcde\0\0\0", 8)) {
527 return failTest(ctx, "Failed to null pad string value (8)");
528 }
529
530 /* shrink from 8 to 4 */
531 if (REDISMODULE_ERR == RedisModule_StringTruncate(k, 4)) {
532 return failTest(ctx, "Could not truncate string value (4)");
533 }
534 s = RedisModule_StringDMA(k, &len, REDISMODULE_READ);
535 if (!s) {
536 return failTest(ctx, "Failed to read truncated string (4)");
537 } else if (len != 4) {
538 return failTest(ctx, "Failed to shrink string value (4)");
539 } else if (0 != strncmp(s, "abcd", 4)) {
540 return failTest(ctx, "Failed to truncate string value (4)");
541 }
542
543 /* shrink to 0 */
544 if (REDISMODULE_ERR == RedisModule_StringTruncate(k, 0)) {
545 return failTest(ctx, "Could not truncate string value (0)");
546 }
547 s = RedisModule_StringDMA(k, &len, REDISMODULE_READ);
548 if (!s) {
549 return failTest(ctx, "Failed to read truncated string (0)");
550 } else if (len != 0) {
551 return failTest(ctx, "Failed to shrink string value to (0)");
552 }
553
554 return RedisModule_ReplyWithSimpleString(ctx, "OK");
555}
556
557int NotifyCallback(RedisModuleCtx *ctx, int type, const char *event,
558 RedisModuleString *key) {
559 RedisModule_AutoMemory(ctx);
560 /* Increment a counter on the notifications: for each key notified we
561 * increment a counter */
562 RedisModule_Log(ctx, "notice", "Got event type %d, event %s, key %s", type,
563 event, RedisModule_StringPtrLen(key, NULL));
564
565 RedisModule_Call(ctx, "HINCRBY", "csc", "notifications", key, "1");
566 return REDISMODULE_OK;
567}
568
569/* TEST.NOTIFICATIONS -- Test Keyspace Notifications. */
570int TestNotifications(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
571 RedisModule_AutoMemory(ctx);
572 REDISMODULE_NOT_USED(argv);
573 REDISMODULE_NOT_USED(argc);
574
575#define FAIL(msg, ...) \
576 { \
577 RedisModule_Log(ctx, "warning", "Failed NOTIFY Test. Reason: " #msg, ##__VA_ARGS__); \
578 goto err; \
579 }
580 RedisModule_Call(ctx, "FLUSHDB", "");
581
582 RedisModule_Call(ctx, "SET", "cc", "foo", "bar");
583 RedisModule_Call(ctx, "SET", "cc", "foo", "baz");
584 RedisModule_Call(ctx, "SADD", "cc", "bar", "x");
585 RedisModule_Call(ctx, "SADD", "cc", "bar", "y");
586
587 RedisModule_Call(ctx, "HSET", "ccc", "baz", "x", "y");
588 /* LPUSH should be ignored and not increment any counters */
589 RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
590 RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
591
592 /* Miss some keys intentionally so we will get a "keymiss" notification. */
593 RedisModule_Call(ctx, "GET", "c", "nosuchkey");
594 RedisModule_Call(ctx, "SMEMBERS", "c", "nosuchkey");
595
596 size_t sz;
597 const char *rep;
598 RedisModuleCallReply *r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "foo");
599 if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_STRING) {
600 FAIL("Wrong or no reply for foo");
601 } else {
602 rep = RedisModule_CallReplyStringPtr(r, &sz);
603 if (sz != 1 || *rep != '2') {
604 FAIL("Got reply '%s'. expected '2'", RedisModule_CallReplyStringPtr(r, NULL));
605 }
606 }
607
608 r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "bar");
609 if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_STRING) {
610 FAIL("Wrong or no reply for bar");
611 } else {
612 rep = RedisModule_CallReplyStringPtr(r, &sz);
613 if (sz != 1 || *rep != '2') {
614 FAIL("Got reply '%s'. expected '2'", rep);
615 }
616 }
617
618 r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "baz");
619 if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_STRING) {
620 FAIL("Wrong or no reply for baz");
621 } else {
622 rep = RedisModule_CallReplyStringPtr(r, &sz);
623 if (sz != 1 || *rep != '1') {
624 FAIL("Got reply '%.*s'. expected '1'", (int)sz, rep);
625 }
626 }
627 /* For l we expect nothing since we didn't subscribe to list events */
628 r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "l");
629 if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_NULL) {
630 FAIL("Wrong reply for l");
631 }
632
633 r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "nosuchkey");
634 if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_STRING) {
635 FAIL("Wrong or no reply for nosuchkey");
636 } else {
637 rep = RedisModule_CallReplyStringPtr(r, &sz);
638 if (sz != 1 || *rep != '2') {
639 FAIL("Got reply '%.*s'. expected '2'", (int)sz, rep);
640 }
641 }
642
643 RedisModule_Call(ctx, "FLUSHDB", "");
644
645 return RedisModule_ReplyWithSimpleString(ctx, "OK");
646err:
647 RedisModule_Call(ctx, "FLUSHDB", "");
648
649 return RedisModule_ReplyWithSimpleString(ctx, "ERR");
650}
651
652/* TEST.CTXFLAGS -- Test GetContextFlags. */
653int TestCtxFlags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
654 REDISMODULE_NOT_USED(argc);
655 REDISMODULE_NOT_USED(argv);
656
657 RedisModule_AutoMemory(ctx);
658
659 int ok = 1;
660 const char *errString = NULL;
661#undef FAIL
662#define FAIL(msg) \
663 { \
664 ok = 0; \
665 errString = msg; \
666 goto end; \
667 }
668
669 int flags = RedisModule_GetContextFlags(ctx);
670 if (flags == 0) {
671 FAIL("Got no flags");
672 }
673
674 if (flags & REDISMODULE_CTX_FLAGS_LUA) FAIL("Lua flag was set");
675 if (flags & REDISMODULE_CTX_FLAGS_MULTI) FAIL("Multi flag was set");
676
677 if (flags & REDISMODULE_CTX_FLAGS_AOF) FAIL("AOF Flag was set")
678 /* Enable AOF to test AOF flags */
679 RedisModule_Call(ctx, "config", "ccc", "set", "appendonly", "yes");
680 flags = RedisModule_GetContextFlags(ctx);
681 if (!(flags & REDISMODULE_CTX_FLAGS_AOF)) FAIL("AOF Flag not set after config set");
682
683 /* Disable RDB saving and test the flag. */
684 RedisModule_Call(ctx, "config", "ccc", "set", "save", "");
685 flags = RedisModule_GetContextFlags(ctx);
686 if (flags & REDISMODULE_CTX_FLAGS_RDB) FAIL("RDB Flag was set");
687 /* Enable RDB to test RDB flags */
688 RedisModule_Call(ctx, "config", "ccc", "set", "save", "900 1");
689 flags = RedisModule_GetContextFlags(ctx);
690 if (!(flags & REDISMODULE_CTX_FLAGS_RDB)) FAIL("RDB Flag was not set after config set");
691
692 if (!(flags & REDISMODULE_CTX_FLAGS_MASTER)) FAIL("Master flag was not set");
693 if (flags & REDISMODULE_CTX_FLAGS_SLAVE) FAIL("Slave flag was set");
694 if (flags & REDISMODULE_CTX_FLAGS_READONLY) FAIL("Read-only flag was set");
695 if (flags & REDISMODULE_CTX_FLAGS_CLUSTER) FAIL("Cluster flag was set");
696
697 /* Disable maxmemory and test the flag. (it is implicitly set in 32bit builds. */
698 RedisModule_Call(ctx, "config", "ccc", "set", "maxmemory", "0");
699 flags = RedisModule_GetContextFlags(ctx);
700 if (flags & REDISMODULE_CTX_FLAGS_MAXMEMORY) FAIL("Maxmemory flag was set");
701
702 /* Enable maxmemory and test the flag. */
703 RedisModule_Call(ctx, "config", "ccc", "set", "maxmemory", "100000000");
704 flags = RedisModule_GetContextFlags(ctx);
705 if (!(flags & REDISMODULE_CTX_FLAGS_MAXMEMORY))
706 FAIL("Maxmemory flag was not set after config set");
707
708 if (flags & REDISMODULE_CTX_FLAGS_EVICT) FAIL("Eviction flag was set");
709 RedisModule_Call(ctx, "config", "ccc", "set", "maxmemory-policy", "allkeys-lru");
710 flags = RedisModule_GetContextFlags(ctx);
711 if (!(flags & REDISMODULE_CTX_FLAGS_EVICT)) FAIL("Eviction flag was not set after config set");
712
713end:
714 /* Revert config changes */
715 RedisModule_Call(ctx, "config", "ccc", "set", "appendonly", "no");
716 RedisModule_Call(ctx, "config", "ccc", "set", "save", "");
717 RedisModule_Call(ctx, "config", "ccc", "set", "maxmemory", "0");
718 RedisModule_Call(ctx, "config", "ccc", "set", "maxmemory-policy", "noeviction");
719
720 if (!ok) {
721 RedisModule_Log(ctx, "warning", "Failed CTXFLAGS Test. Reason: %s", errString);
722 return RedisModule_ReplyWithSimpleString(ctx, "ERR");
723 }
724
725 return RedisModule_ReplyWithSimpleString(ctx, "OK");
726}
727
728/* ----------------------------- Test framework ----------------------------- */
729
730/* Return 1 if the reply matches the specified string, otherwise log errors
731 * in the server log and return 0. */
732int TestAssertErrorReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply, char *str, size_t len) {
733 RedisModuleString *mystr, *expected;
734 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_ERROR) {
735 return 0;
736 }
737
738 mystr = RedisModule_CreateStringFromCallReply(reply);
739 expected = RedisModule_CreateString(ctx,str,len);
740 if (RedisModule_StringCompare(mystr,expected) != 0) {
741 const char *mystr_ptr = RedisModule_StringPtrLen(mystr,NULL);
742 const char *expected_ptr = RedisModule_StringPtrLen(expected,NULL);
743 RedisModule_Log(ctx,"warning",
744 "Unexpected Error reply reply '%s' (instead of '%s')",
745 mystr_ptr, expected_ptr);
746 return 0;
747 }
748 return 1;
749}
750
751int TestAssertStringReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply, char *str, size_t len) {
752 RedisModuleString *mystr, *expected;
753
754 if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_ERROR) {
755 RedisModule_Log(ctx,"warning","Test error reply: %s",
756 RedisModule_CallReplyStringPtr(reply, NULL));
757 return 0;
758 } else if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_STRING) {
759 RedisModule_Log(ctx,"warning","Unexpected reply type %d",
760 RedisModule_CallReplyType(reply));
761 return 0;
762 }
763 mystr = RedisModule_CreateStringFromCallReply(reply);
764 expected = RedisModule_CreateString(ctx,str,len);
765 if (RedisModule_StringCompare(mystr,expected) != 0) {
766 const char *mystr_ptr = RedisModule_StringPtrLen(mystr,NULL);
767 const char *expected_ptr = RedisModule_StringPtrLen(expected,NULL);
768 RedisModule_Log(ctx,"warning",
769 "Unexpected string reply '%s' (instead of '%s')",
770 mystr_ptr, expected_ptr);
771 return 0;
772 }
773 return 1;
774}
775
776/* Return 1 if the reply matches the specified integer, otherwise log errors
777 * in the server log and return 0. */
778int TestAssertIntegerReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply, long long expected) {
779 if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_ERROR) {
780 RedisModule_Log(ctx,"warning","Test error reply: %s",
781 RedisModule_CallReplyStringPtr(reply, NULL));
782 return 0;
783 } else if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_INTEGER) {
784 RedisModule_Log(ctx,"warning","Unexpected reply type %d",
785 RedisModule_CallReplyType(reply));
786 return 0;
787 }
788 long long val = RedisModule_CallReplyInteger(reply);
789 if (val != expected) {
790 RedisModule_Log(ctx,"warning",
791 "Unexpected integer reply '%lld' (instead of '%lld')",
792 val, expected);
793 return 0;
794 }
795 return 1;
796}
797
798/* Replies "yes", "no" otherwise if the context may execute debug commands */
799int TestCanDebug(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
800 REDISMODULE_NOT_USED(argv);
801 REDISMODULE_NOT_USED(argc);
802 int flags = RedisModule_GetContextFlags(ctx);
803 int allFlags = RedisModule_GetContextFlagsAll();
804 if ((allFlags & REDISMODULE_CTX_FLAGS_DEBUG_ENABLED) &&
805 (flags & REDISMODULE_CTX_FLAGS_DEBUG_ENABLED)) {
806 RedisModule_ReplyWithSimpleString(ctx, "yes");
807 } else {
808 RedisModule_ReplyWithSimpleString(ctx, "no");
809 }
810 return REDISMODULE_OK;
811}
812
813#define T(name,...) \
814 do { \
815 RedisModule_Log(ctx,"warning","Testing %s", name); \
816 reply = RedisModule_Call(ctx,name,__VA_ARGS__); \
817 } while (0)
818
819/* TEST.BASICS -- Run all the tests.
820 * Note: it is useful to run these tests from the module rather than TCL
821 * since it's easier to check the reply types like that make a distinction
822 * between 0 and "0", etc. */
823int TestBasics(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
824 REDISMODULE_NOT_USED(argv);
825 REDISMODULE_NOT_USED(argc);
826
827 RedisModule_AutoMemory(ctx);
828 RedisModuleCallReply *reply;
829
830 /* Make sure the DB is empty before to proceed. */
831 T("dbsize","");
832 if (!TestAssertIntegerReply(ctx,reply,0)) goto fail;
833
834 T("ping","");
835 if (!TestAssertStringReply(ctx,reply,"PONG",4)) goto fail;
836
837 T("test.call","");
838 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
839
840 T("test.callresp3map","");
841 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
842
843 T("test.callresp3set","");
844 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
845
846 T("test.callresp3double","");
847 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
848
849 T("test.callresp3bool","");
850 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
851
852 T("test.callresp3null","");
853 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
854
855 T("test.callreplywithnestedreply","");
856 if (!TestAssertStringReply(ctx,reply,"test",4)) goto fail;
857
858 T("test.callreplywithbignumberreply","");
859 if (!TestAssertStringReply(ctx,reply,"1234567999999999999999999999999999999",37)) goto fail;
860
861 T("test.callreplywithverbatimstringreply","");
862 if (!TestAssertStringReply(ctx,reply,"txt:This is a verbatim\nstring",29)) goto fail;
863
864 T("test.ctxflags","");
865 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
866
867 T("test.string.append","");
868 if (!TestAssertStringReply(ctx,reply,"foobar",6)) goto fail;
869
870 T("test.string.truncate","");
871 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
872
873 T("test.unlink","");
874 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
875
876 T("test.nestedcallreplyarray","");
877 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
878
879 T("test.string.append.am","");
880 if (!TestAssertStringReply(ctx,reply,"foobar",6)) goto fail;
881
882 T("test.string.trim","");
883 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
884
885 T("test.string.printf", "cc", "foo", "bar");
886 if (!TestAssertStringReply(ctx,reply,"Got 3 args. argv[1]: foo, argv[2]: bar",38)) goto fail;
887
888 T("test.notify", "");
889 if (!TestAssertStringReply(ctx,reply,"OK",2)) goto fail;
890
891 T("test.callreplywitharrayreply", "");
892 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_ARRAY) goto fail;
893 if (RedisModule_CallReplyLength(reply) != 2) goto fail;
894 if (!TestAssertStringReply(ctx,RedisModule_CallReplyArrayElement(reply, 0),"test",4)) goto fail;
895 if (!TestAssertStringReply(ctx,RedisModule_CallReplyArrayElement(reply, 1),"1234",4)) goto fail;
896
897 T("foo", "E");
898 if (!TestAssertErrorReply(ctx,reply,"ERR unknown command 'foo'",25)) goto fail;
899
900 T("set", "Ec", "x");
901 if (!TestAssertErrorReply(ctx,reply,"ERR wrong number of arguments for 'set' command",47)) goto fail;
902
903 T("shutdown", "SE");
904 if (!TestAssertErrorReply(ctx,reply,"ERR command 'shutdown' is not allowed on script mode",52)) goto fail;
905
906 T("set", "WEcc", "x", "1");
907 if (!TestAssertErrorReply(ctx,reply,"ERR Write command 'set' was called while write is not allowed.",62)) goto fail;
908
909 RedisModule_ReplyWithSimpleString(ctx,"ALL TESTS PASSED");
910 return REDISMODULE_OK;
911
912fail:
913 RedisModule_ReplyWithSimpleString(ctx,
914 "SOME TEST DID NOT PASS! Check server logs");
915 return REDISMODULE_OK;
916}
917
918int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
919 REDISMODULE_NOT_USED(argv);
920 REDISMODULE_NOT_USED(argc);
921
922 if (RedisModule_Init(ctx,"test",1,REDISMODULE_APIVER_1)
923 == REDISMODULE_ERR) return REDISMODULE_ERR;
924
925 /* Perform RM_Call inside the RedisModule_OnLoad
926 * to verify that it works as expected without crashing.
927 * The tests will verify it on different configurations
928 * options (cluster/no cluster). A simple ping command
929 * is enough for this test. */
930 RedisModuleCallReply *reply = RedisModule_Call(ctx, "ping", "");
931 if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_STRING) {
932 RedisModule_FreeCallReply(reply);
933 return REDISMODULE_ERR;
934 }
935 size_t len;
936 const char *reply_str = RedisModule_CallReplyStringPtr(reply, &len);
937 if (len != 4) {
938 RedisModule_FreeCallReply(reply);
939 return REDISMODULE_ERR;
940 }
941 if (memcmp(reply_str, "PONG", 4) != 0) {
942 RedisModule_FreeCallReply(reply);
943 return REDISMODULE_ERR;
944 }
945 RedisModule_FreeCallReply(reply);
946
947 if (RedisModule_CreateCommand(ctx,"test.call",
948 TestCall,"write deny-oom",1,1,1) == REDISMODULE_ERR)
949 return REDISMODULE_ERR;
950
951 if (RedisModule_CreateCommand(ctx,"test.callresp3map",
952 TestCallResp3Map,"write deny-oom",1,1,1) == REDISMODULE_ERR)
953 return REDISMODULE_ERR;
954
955 if (RedisModule_CreateCommand(ctx,"test.callresp3attribute",
956 TestCallResp3Attribute,"write deny-oom",1,1,1) == REDISMODULE_ERR)
957 return REDISMODULE_ERR;
958
959 if (RedisModule_CreateCommand(ctx,"test.callresp3set",
960 TestCallResp3Set,"write deny-oom",1,1,1) == REDISMODULE_ERR)
961 return REDISMODULE_ERR;
962
963 if (RedisModule_CreateCommand(ctx,"test.callresp3double",
964 TestCallResp3Double,"write deny-oom",1,1,1) == REDISMODULE_ERR)
965 return REDISMODULE_ERR;
966
967 if (RedisModule_CreateCommand(ctx,"test.callresp3bool",
968 TestCallResp3Bool,"write deny-oom",1,1,1) == REDISMODULE_ERR)
969 return REDISMODULE_ERR;
970
971 if (RedisModule_CreateCommand(ctx,"test.callresp3null",
972 TestCallResp3Null,"write deny-oom",1,1,1) == REDISMODULE_ERR)
973 return REDISMODULE_ERR;
974
975 if (RedisModule_CreateCommand(ctx,"test.callreplywitharrayreply",
976 TestCallReplyWithArrayReply,"write deny-oom",1,1,1) == REDISMODULE_ERR)
977 return REDISMODULE_ERR;
978
979 if (RedisModule_CreateCommand(ctx,"test.callreplywithnestedreply",
980 TestCallReplyWithNestedReply,"write deny-oom",1,1,1) == REDISMODULE_ERR)
981 return REDISMODULE_ERR;
982
983 if (RedisModule_CreateCommand(ctx,"test.callreplywithbignumberreply",
984 TestCallResp3BigNumber,"write deny-oom",1,1,1) == REDISMODULE_ERR)
985 return REDISMODULE_ERR;
986
987 if (RedisModule_CreateCommand(ctx,"test.callreplywithverbatimstringreply",
988 TestCallResp3Verbatim,"write deny-oom",1,1,1) == REDISMODULE_ERR)
989 return REDISMODULE_ERR;
990
991 if (RedisModule_CreateCommand(ctx,"test.string.append",
992 TestStringAppend,"write deny-oom",1,1,1) == REDISMODULE_ERR)
993 return REDISMODULE_ERR;
994
995 if (RedisModule_CreateCommand(ctx,"test.string.trim",
996 TestTrimString,"write deny-oom",1,1,1) == REDISMODULE_ERR)
997 return REDISMODULE_ERR;
998
999 if (RedisModule_CreateCommand(ctx,"test.string.append.am",
1000 TestStringAppendAM,"write deny-oom",1,1,1) == REDISMODULE_ERR)
1001 return REDISMODULE_ERR;
1002
1003 if (RedisModule_CreateCommand(ctx,"test.string.truncate",
1004 TestStringTruncate,"write deny-oom",1,1,1) == REDISMODULE_ERR)
1005 return REDISMODULE_ERR;
1006
1007 if (RedisModule_CreateCommand(ctx,"test.string.printf",
1008 TestStringPrintf,"write deny-oom",1,1,1) == REDISMODULE_ERR)
1009 return REDISMODULE_ERR;
1010
1011 if (RedisModule_CreateCommand(ctx,"test.ctxflags",
1012 TestCtxFlags,"readonly",1,1,1) == REDISMODULE_ERR)
1013 return REDISMODULE_ERR;
1014
1015 if (RedisModule_CreateCommand(ctx,"test.unlink",
1016 TestUnlink,"write deny-oom",1,1,1) == REDISMODULE_ERR)
1017 return REDISMODULE_ERR;
1018
1019 if (RedisModule_CreateCommand(ctx,"test.nestedcallreplyarray",
1020 TestNestedCallReplyArrayElement,"write deny-oom",1,1,1) == REDISMODULE_ERR)
1021 return REDISMODULE_ERR;
1022
1023 if (RedisModule_CreateCommand(ctx,"test.basics",
1024 TestBasics,"write",1,1,1) == REDISMODULE_ERR)
1025 return REDISMODULE_ERR;
1026
1027 /* the following commands are used by an external test and should not be added to TestBasics */
1028 if (RedisModule_CreateCommand(ctx,"test.rmcallautomode",
1029 TestCallRespAutoMode,"write",1,1,1) == REDISMODULE_ERR)
1030 return REDISMODULE_ERR;
1031
1032 if (RedisModule_CreateCommand(ctx,"test.getresp",
1033 TestGetResp,"readonly",1,1,1) == REDISMODULE_ERR)
1034 return REDISMODULE_ERR;
1035
1036 if (RedisModule_CreateCommand(ctx,"test.candebug",
1037 TestCanDebug,"readonly",1,1,1) == REDISMODULE_ERR)
1038 return REDISMODULE_ERR;
1039
1040 RedisModule_SubscribeToKeyspaceEvents(ctx,
1041 REDISMODULE_NOTIFY_HASH |
1042 REDISMODULE_NOTIFY_SET |
1043 REDISMODULE_NOTIFY_STRING |
1044 REDISMODULE_NOTIFY_KEY_MISS,
1045 NotifyCallback);
1046 if (RedisModule_CreateCommand(ctx,"test.notify",
1047 TestNotifications,"write deny-oom",1,1,1) == REDISMODULE_ERR)
1048 return REDISMODULE_ERR;
1049
1050 return REDISMODULE_OK;
1051}