Open-Source Wikis

/

Redis

/

How to contribute

/

Testing

redis/redis

Testing

Redis has three layers of tests:

  1. Embedded C unit tests compiled into redis-server itself.
  2. Tcl integration tests under tests/ driven by runtest, runtest-cluster, runtest-sentinel, and runtest-moduleapi.
  3. CI matrix runs orchestrated by .github/workflows/ci.yml and .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 --verbose

The 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-moduleapi

For the sanitiser lanes, build with the corresponding flags:

make distclean
make CFLAGS="-fsanitize=address -fno-omit-frame-pointer" \
     LDFLAGS="-fsanitize=address" \
     OPTIMIZATION="-O0"
./runtest

Valgrind:

make distclean && make valgrind   # Makefile target; sets the right flags
./runtest --valgrind --no-latency

Test-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.

Testing – Redis wiki | Factory