How does the Redis test infrastructure works?
Published on: 02 December 2025
As I mentioned in my blog post about the git test infrastructure I am always curious how large C projects handle testing, so I also investigated the Redis project since it's another project that is very well organized and documented.
Running the tests is very simple.
$ make
for dir in src; do /Applications/Xcode.app/Contents/Developer/usr/bin/make -C $dir all; done
CC Makefile.dep
rm -rf redis-server redis-sentinel redis-cli redis-benchmark redis-check-rdb redis-check-aof *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep *.so
[...]
cc -I../../src -W -Wall -Wno-missing-field-initializers -dynamic -fno-common -g -ggdb -std=gnu11 -O2 -fPIC -c internalsecret.c -o internalsecret.xo
ld -o internalsecret.so internalsecret.xo -bundle -undefined dynamic_lookup -L/opt/homebrew/opt/openssl@1.1/lib -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lsystem
cc -I../../src -W -Wall -Wno-missing-field-initializers -dynamic -fno-common -g -ggdb -std=gnu11 -O2 -fPIC -c configaccess.c -o configaccess.xo
ld -o configaccess.so configaccess.xo -bundle -undefined dynamic_lookup -L/opt/homebrew/opt/openssl@1.1/lib -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lsystem
cc -I../../src -W -Wall -Wno-missing-field-initializers -dynamic -fno-common -g -ggdb -std=gnu11 -O2 -fPIC -c atomicslotmigration.c -o atomicslotmigration.xo
ld -o atomicslotmigration.so atomicslotmigration.xo -bundle -undefined dynamic_lookup -L/opt/homebrew/opt/openssl@1.1/lib -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lsystem
rm moduleauthtwo.xo blockedclient.xo fork.xo datatype2.xo auth.xo publish.xo subcommands.xo keyspace_events.xo getkeys.xo datatype.xo list.xo blockonkeys.xo reply.xo cmdintrospection.xo hash.xo hooks.xo timer.xo rdbloadsave.xo infotest.xo eventloop.xo moduleconfigs.xo testrdb.xo configaccess.xo commandfilter.xo getchannels.xo keyspecs.xo postnotifications.xo usercall.xo defragtest.xo stream.xo internalsecret.xo basics.xo scan.xo test_lazyfree.xo atomicslotmigration.xo crash.xo zset.xo mallocsize.xo moduleconfigstwo.xo blockonbackground.xo misc.xo propagate.xo aclcheck.xo
Hint: It's a good idea to run 'make test' ;)
$ make test
for dir in src; do /Applications/Xcode.app/Contents/Developer/usr/bin/make -C $dir test; done
CC Makefile.dep
CC release.o
LINK redis-server
INSTALL redis-check-aof
LINK redis-cli
LINK redis-benchmark
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C ../tests/modules
make[2]: Nothing to be done for `all'.
Cleanup: may take some time... OK
[...]
446 seconds - integration/replication
2 seconds - bitops-large-memory
33 seconds - defrag
8 seconds - violations
1 seconds - list-large-memory
1 seconds - set-large-memory
\o/ All tests passed without errors!
Cleanup: may take some time... OK
There are a lot of tests in various categories, and it takes a while
to run the full test suite, which is great news, it means a lot of
corner cases are covered. What I also find interesting is that they
call "unit" tests the ones that are targeting a single type or
command, while in other contexts these are still called "integration"
tests. This is different in other projects, where a "unit" is
considered a single function. It's also interesting that they make it
so easy to test it (and hint about it once make is complete), which
is also a good sign.
But where are all these tests residing? There is a folder called
tests/ that contains various folders, and here we can find various
folders and a lot of files, with are essentially various group of
tests.
The most interesting thing for me is that they are not using C or bash (like git), but instead they use Tcl for all the tests and utilities arount the test framework. This doesn't come as an extreme surprise since the author of Redis has already written multiple times about how he likes Tcl, and there is even this article from 2006 where he shows some of the powerful features of Tcl and he even wrote the Jim interpreter for Tcl.
But I was not expecting it as the programming language used to write the tests for Redis.
I was happily surprised at how simple and clear all these tests are. Even though I am not too familiar with Tcl the Redis developers have already developed all the helpers and utility functions that you need to write a test, and there are not too many lines of code about it.
On top of this, Redis also includes a nice benchmark.
$ ./src/redis-server &
$ ./src/redis-benchmark
====== PING_INLINE ======
100000 requests completed in 1.24 seconds
50 parallel clients
3 bytes payload
keep alive: 1
host configuration "save": 3600 1 300 100 60 10000
host configuration "appendonly": no
multi-thread: no
Latency by percentile distribution:
0.000% <= 0.095 milliseconds (cumulative count 1)
50.000% <= 0.391 milliseconds (cumulative count 50608)
75.000% <= 0.487 milliseconds (cumulative count 75967)
[...]
99.961% <= 2.103 milliseconds (cumulative count 99961)
99.995% <= 3.103 milliseconds (cumulative count 99995)
100.000% <= 4.103 milliseconds (cumulative count 100000)
Summary:
throughput summary: 74906.37 requests per second
latency summary (msec):
avg min p50 p95 p99 max
0.439 0.096 0.423 0.839 1.015 3.223
This code contains various benchmarks that you can run on a Redis server (in this case localhost, but you can run it on any host). By default it runs various tests, but you can specify various options as arguments of the command line to test specific commands.
Overall I really like the Redis codebase and interfaces because they are really well designed and easy to use.