redis/redis
Testing
Redis has three layers of tests:
- Embedded C unit tests compiled into
redis-serveritself. - Tcl integration tests under
tests/driven byruntest,runtest-cluster,runtest-sentinel, andruntest-moduleapi. - CI matrix runs orchestrated by
.github/workflows/ci.ymland.github/workflows/daily.yml.
Layer 1: Embedded C unit tests
When redis-server is compiled with REDIS_CFLAGS=-DREDIS_TEST, it grows a test mode:
make REDIS_CFLAGS="-DREDIS_TEST"
./src/redis-server test all
./src/redis-server test dict --accurate
./src/redis-server test ziplist --large-memory --verboseThe dispatcher is at the bottom of src/server.c: a redisTests[] table maps a name to a redisTestProc function pointer. Tests currently registered:
adlist, kvstore, quicklist, ziplist, intset, zipmap, sha1test, util, endianconv, crc64, zmalloc, sds, dict, listpack, hyperloglog, bloom, cms, tdigest, topk, fastfloat, plus the bundled vset and gcra tests.
These tests live alongside the implementation (#ifdef REDIS_TEST blocks in src/dict.c, src/sds.c, etc.). They use a tiny test framework defined in src/testhelp.h (test_cond, test_report, etc.).
Flags that the dispatcher honours:
--accurate— run more iterations of probabilistic tests.--large-memory— allow tests that allocate hundreds of MB.--valgrind— skip slow/flaky cases when valgrind is detected.--verbose— print every assertion.
Layer 2: Tcl integration tests
The orchestrator is tests/test_helper.tcl (~30 KB of Tcl). It is invoked through one of four shell wrappers in the repo root:
| Wrapper | Suite |
|---|---|
./runtest |
tests/unit/ and most of tests/integration/. The default suite. |
./runtest-cluster |
tests/cluster/ — multi-node cluster scenarios. |
./runtest-sentinel |
tests/sentinel/ — Sentinel orchestration scenarios. |
./runtest-moduleapi |
tests/unit/moduleapi/ — module API tests. Builds the helper modules from tests/modules/*.c first. |
Anatomy of a Tcl test
A typical file (tests/unit/type/string.tcl, abridged):
start_server {tags {"string"}} {
test {SET and GET an item} {
r set x foobar
r get x
} {foobar}
test {SET with EX option sets a TTL} {
r set x foo EX 60
r ttl x
} {60}
}start_server spins up an actual redis-server subprocess on a random port; r <command> issues a RESP command; the trailing {foobar} is the expected reply. Tags on start_server and test allow filtering with --tags.
Useful command-line options
./runtest --single unit/type/string # one test file
./runtest --tags slow # only the "slow" tag
./runtest --tags -slow # exclude the "slow" tag
./runtest --skipfile <file> # comma-separated list to skip
./runtest --tls # enable TLS in the harness
./runtest --io-threads # enable IO threads
./runtest --port 11211 # base port for spawned servers
./runtest --dump-logs # print the server log on failure
./runtest --stop # stop on first failure
./runtest --accurate # also pass --accurate to the server
./runtest --clients 16 # parallelism (number of slave runners)Most tests can run in parallel across "slaves" — the test harness fans out work to N child processes. The default is 16 on a typical CI runner.
Where the test infrastructure lives
| Path | Role |
|---|---|
tests/test_helper.tcl |
Top-level orchestrator: parses CLI flags, manages slave runners, aggregates results. |
tests/support/util.tcl |
Common helpers (wait_for_condition, assert_equal, populate, dict_subset). |
tests/support/server.tcl |
Spawns redis-server instances, waits for the port, captures logs. |
tests/support/redis.tcl |
A pure-Tcl Redis client (RESP2 and RESP3 aware). |
tests/support/cluster_util.tcl, tests/support/aofmanifest.tcl, tests/support/cli.tcl, … |
Subsystem-specific helpers. |
tests/instances.tcl |
Used by Sentinel/cluster tests to manage a topology of instances. |
tests/helpers/ |
Small driver scripts (e.g. fake replicas) used by some tests. |
tests/assets/ |
Static fixtures — RDB files, ACL configs, scripts, certs. |
Layer 3: CI
.github/workflows/ci.yml is the per-PR gate. It runs the unit + moduleapi suites on Ubuntu with default flags, plus clang-tidy and the reply-schema linter.
.github/workflows/daily.yml is the nightly matrix. Lanes include:
make-32bit,make-malloc-libc,make-debug,make-c99,make-centos7,make-redhat,make-fedora.- ASAN, UBSAN, MSAN, ThreadSanitizer.
- Valgrind on Ubuntu and Debian.
- macOS Sonoma/Sequoia and FreeBSD via cross-build.
- TLS-enabled Tcl runs.
- Cluster and Sentinel suites.
- Reply-log validation (
utils/req-res-log-validator.py). - IO-threads-enabled runs.
.github/workflows/external.yml lets the CI hit a user-provided external Redis instance — useful for verifying upgrades against a live deployment.
Reproducing CI locally
The simplest local approximation of "what CI runs":
make distclean
make BUILD_TLS=yes
./runtest # main suite
./runtest --tls # TLS lane
./runtest-cluster
./runtest-sentinel
./runtest-moduleapiFor the sanitiser lanes, build with the corresponding flags:
make distclean
make CFLAGS="-fsanitize=address -fno-omit-frame-pointer" \
LDFLAGS="-fsanitize=address" \
OPTIMIZATION="-O0"
./runtestValgrind:
make distclean && make valgrind # Makefile target; sets the right flags
./runtest --valgrind --no-latencyTest-only modules
Module API tests live in tests/unit/moduleapi/*.tcl and load helpers compiled from tests/modules/*.c. The runtest-moduleapi script handles building the .so files first by running make in tests/modules/. If you add a new module API surface, you usually add both a helper module and a Tcl test.
Debugging a flaky test
The harness writes per-server logs into tests/tmp/<random>/server.log. The --dump-logs flag prints them to stdout on failure. Adding a puts ... in the Tcl file is the easiest way to add ad-hoc tracing. For C-side bugs, attaching gdb to the spawned redis-server (the PID is printed by the harness) is the standard approach — see Debugging.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.