CodeVetter · Repo Unpack · Testing signals
redis/redis
Testing is a Tcl integration suite: `tests/test_helper.tcl` globs `tests/{unit,unit/type,unit/moduleapi,unit/cluster,integration}/*.tcl` into `::all_tests` and runs them against real spawned `redis-server` processes on ports from 21111. There are no C-level unit test files, but the binary embeds a `REDIS_TEST` mode invoked as `redis-server test <name>|all` for data-structure self-tests. Module API coverage is unusually deep — 48 C test modules under `tests/modules/` paired with 48 `unit/moduleapi/*.tcl` suites. CI runs eight build matrices plus an ASAN build and a commands.def drift check, with lcov/Codecov, CodeQL, Coverity, and a reply-schema linter on separate workflows.
- Test discovery is directory-glob based, not a manifest: `test_helper.tcl` iterates `set test_dirs {unit unit/type unit/moduleapi unit/cluster integration}` and lsorts `*.tcl` into `::all_tests`, so a new `.tcl` file in those dirs is picked up automatically.
- The harness is a client/server fan-out: `test_server_main`, `accept_test_clients`, `read_from_test_client` and `signal_idle_client` distribute test files across parallel Tcl clients, with `run_solo` for tests that must not run concurrently.
- Support libraries sourced by every suite live in `tests/support/`: `server.tcl` (start_server), `util.tcl`, `cluster_util.tcl`, `aofmanifest.tcl`, `redis.tcl` (the Tcl RESP client), `response_transformers.tcl` (RESP2/RESP3 normalisation), and `cli.tcl`.
- Module API is the most thoroughly covered subsystem: `runtest-moduleapi` enumerates 48 suites explicitly by `--single`, and `tests/modules/` holds 48 matching C test modules built by `$MAKE -C tests/modules` before the run.
- The C code carries an embedded self-test harness rather than a separate unit-test binary: `main()` under `#ifdef REDIS_TEST` accepts `redis-server test <name>|all` with flags `--accurate --large-memory --valgrind --verbose`, iterates a `redisTests[]` table, and prints a pass/fail summary.
- Cluster coverage includes 23 dedicated suites under `tests/unit/cluster/`, notably `atomic-slot-migration.tcl`, `internal-secret.tcl`, `packet-validation.tcl`, `tls-peer-impersonation.tcl` and `cluster-bus-port-protected-mode.tcl` — the security-sensitive cluster paths are explicitly exercised.
- Integration coverage focuses on durability and replication edge cases: `aof-multi-part.tcl`, `aof-race.tcl`, `corrupt-dump-fuzzer.tcl`, `corrupt-dump.tcl`, `psync2*.tcl` (four files), `replication-rdbchannel.tcl`, `replication-iothreads.tcl`, `failover.tcl`, `shutdown.tcl`.
- The primary CI job `test-ubuntu-latest` builds with `make REDIS_CFLAGS='-Werror' BUILD_TLS=yes` and runs `./runtest --verbose --tags -slow --dump-logs` — meaning slow-tagged tests do not gate PRs.
- CI enforces codegen freshness: the `validate commands.def up to date` step touches `src/commands/ping.json`, runs `make commands.def`, and fails if `git diff` is non-empty — a hand-edited commands.def will break the build.
- A dedicated `test-sanitizer-address` job builds `SANITIZER=address REDIS_CFLAGS='-Werror -DDEBUG_ASSERTIONS -DREDIS_TEST' BUILD_TLS=module` and reruns the suite, so debug assertions and the embedded C tests are compiled in on that path only.
- The build matrix covers portability rather than behaviour: `build-debian-old` (debian:buster container), `build-macos-latest`, `build-32bit` (via gcc-multilib), `build-libc-malloc`, `build-centos-jemalloc` (centos:stream9) and `build-old-chain-jemalloc` — all compile-only, no test step.
- Coverage is reported but non-gating: `codecov.yml` sets both `patch` and `project` statuses to `informational: true`, and the workflow runs `make lcov` and uploads `./src/redis.info`, gated on `github.repository == 'redis/redis'` so forks skip it.
- Static analysis runs on separate cadences: CodeQL on every PR plus a weekly `cron: '0 0 * * 0'`, and Coverity daily (`cron: '0 0 * * *'`) with a comment noting the sub-500k-LOC quota of 21 builds/week.
- Command JSON specs have their own path-filtered lint gate: `reply-schemas-linter.yml` triggers only on changes to `src/commands/*.json` and runs `node ./utils/reply_schema_linter.js` after `npm install ajv`.
- Heavy/long-running coverage is deferred to `daily.yml`, which runs nightly and on PRs targeting release branches matching `'[0-9].[0-9]'` — so a PR into `unstable` never exercises it.
- The GCRA rate-limiter test file is entirely inert: `tests/unit/gcra.tcl` wraps its body in `if 0 { ... }`, matching the fact that `src/gcra.c` is compiled out unless `-DENABLE_GCRA` is passed — so that feature has zero effective coverage.