This document outlines the set up of a development environment for Redis Modules.
- A Linux server (e.g. Ubuntu Gnome 16.10)
- Packages:
sudo apt install build-essential git
- Redis unstable:
git clone [email protected]:antirez/redis.git; cd redis; make
-
Create the project's directory:
mkdir example; cd example
-
Get the API's header file:
cp ../redis/src/redismodule.h .
-
Edit
example.c
:#include "redismodule.h" int Echo(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) return RedisModule_WrongArity(ctx); return RedisModule_ReplyWithString(ctx, argv[1]); } int RedisModule_OnLoad(RedisModuleCtx *ctx) { if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "example.echo", Echo, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; }
-
Compile it:
gcc -fPIC -std=gnu99 -c -o example.o example.c
-
Link it:
ld -o example.so example.o -shared -Bsymbolic -lc
-
Load it:
../redis/src/redis-server --loadmodule ./example.so
-
Test it:
../redis/src/redis-cli example.echo tango
-
Edit
Makefile
:SHOBJ_CFLAGS ?= -fno-common -g -ggdb SHOBJ_LDFLAGS ?= -shared -Bsymbolic CFLAGS = -Wall -g -fPIC -lc -lm -Og -std=gnu99 CC=gcc all: example.so example.so: example.o $(LD) -o $@ example.o $(SHOBJ_LDFLAGS) $(LIBS) -lc clean: rm -rf *.xo *.so *.o
Tools, utilities and scripts to help you write Redis modules!
git clone [email protected]:RedisLabs/RedisModulesSDK.git
Includes:
- A ready-to-use
example
module - The API's documentation
- String, memory management and testing utilties
- Vector, heap and priority queue implementations
- More... (and accepting pull requests)
The a simple approach is to have the module expose an entry point for running basic sanity tests:
-
Register a
test
command for the module by adding this toRedisModule_OnLoad
:if (RedisModule_CreateCommand(ctx, "example.test", Test, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR;
-
Implement the
Test
function:int Test(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); RedisModule_AutoMemory(ctx); RedisModuleString *str = RedisModule_CreateString(ctx, "test", 4); RedisModuleCallReply *reply = RedisModule_Call(ctx, "example.echo", "s", str); if (REDISMODULE_REPLY_STRING != RedisModule_CallReplyType(reply)) { RedisModule_ReplyWithError(ctx, "Unexpected reply type"); return REDISMODULE_ERR; } RedisModuleString *rstr = RedisModule_CreateStringFromCallReply(reply); if (RedisModule_StringCompare(str, rstr) != 0) { RedisModule_ReplyWithError(ctx, "Unexpected reply"); return REDISMODULE_ERR; } RedisModule_ReplyWithSimpleString(ctx, "OK"); return REDISMODULE_OK; }
Some notes:
- Refer to
redis/src/modules/testmodule.c
and the SDK for a more implementation examples. - Test execution requires a running server, the module loaded and a client -> extra effort needed to automate unit tests.
- Can be extended/augmented/replaced with other testing frameworks. For example, RediSearch uses pytest and a disposable Redis class.
-
You'll also need
clang
:sudo apt install clang
-
Run it and open the project's folder
-
Install extensions (
Ctrl+Shift+X
):- C/++ (
ms-vscode.cpptools
) - C/C++ Clang (
mitaki28.vscode-clang
)
- C/++ (
-
Configure the launcher's run task:
- Hit
F5
- Select "C++ (GDB/LLDB)"
- Edit
launch.json
to:
{ "version": "0.2.0", "configurations": [ { "name": "Launch Redis with module", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/../redis/src/redis-server", "args": ["--loadmodule ${workspaceRoot}/example.so"], "stopAtEntry": false, "cwd": "${workspaceRoot}", "environment": [], "internalConsoleOptions": "openOnSessionStart", "linux": { "MIMode": "gdb" } } ] }
- Hit
-
Configure the build task:
Ctrl+Shift+B
-> Configure Task Runner- Select "Others"
- Edit
tasks.json
to:
{ "version": "0.1.0", "command": "make", "isShellCommand": true, "tasks": [ { "taskName": "all", "isBuildCommand": true } ] }