Skip to content

Latest commit

 

History

History
177 lines (120 loc) · 5.31 KB

File metadata and controls

177 lines (120 loc) · 5.31 KB

Test

Test Runner

The test suite uses scripts/test.sh as the unified test runner. It provides consistent behavior across different commands with support for gotestsum (recommended) or plain go test.

Runner Behavior

By default, the script auto-detects the available runner:

  1. If RUNNER env var is set, use that explicitly
  2. If gotestsum is installed, use it (with automatic retries for flaky tests)
  3. Otherwise, fall back to go test

To install gotestsum (recommended):

go install gotest.tools/gotestsum@latest

To force a specific runner:

RUNNER=go ./scripts/test.sh test    # Force go test
RUNNER=gotestsum ./scripts/test.sh test  # Force gotestsum

Commands

Using the Test Script

# Run all tests (unit + integration)
./scripts/test.sh test

# Run unit tests only (uses -short flag)
./scripts/test.sh unit

# Run end-to-end tests
./scripts/test.sh e2e

# Run full suite with all backend combinations
./scripts/test.sh full

Using Make

The Makefile targets delegate to scripts/test.sh:

make test        # ./scripts/test.sh test
make test/unit   # ./scripts/test.sh unit
make test/e2e    # ./scripts/test.sh e2e
make test/full   # ./scripts/test.sh full

Using go test Directly

go test ./...           # All tests
go test ./... -short    # Unit tests only
go test ./... -run "Integration"  # Integration tests

Environment Variables

Variable Description Default
TEST Package(s) to test ./internal/...
RUN Filter tests by name pattern (none)
TESTARGS Additional arguments to pass to test command (none)
TESTINFRA Set to 1 to use persistent test infrastructure (none)
TESTCOMPAT Set to 1 to run full backend compatibility suite (none)
TESTREDISCLUSTER Set to 1 to enable Redis cluster tests (none)
RUNNER Force test runner: gotestsum or go auto-detect

Examples

# Test specific package
TEST='./internal/services/api' make test

# Run specific tests
RUN='TestJWT' make test

# Pass additional options
TESTARGS='-v' make test

# Combine options
RUN='TestListTenant' TEST='./internal/models' TESTINFRA=1 make test

Coverage

  1. Run test coverage
make test/coverage

# or with go test directly
go test ./... -coverprofile=coverage.out

# or to test specific package
TEST='./internal/services/api' make test/coverage
  1. Visualize test coverage

Running the coverage test command above will generate the coverage.out file. You can visually inspect the test coverage with this command to see which statements are covered and more.

$ make test/coverage/html
# go tool cover -html=coverage.out

Compatibility Testing

By default, the test suite runs only the primary backends (Miniredis + Dragonfly + Postgres) to keep feedback loops fast. To run the full suite including compatibility tests for alternative backends (Redis Stack, Redis Cluster), set the TESTCOMPAT environment variable:

# Run full test suite including all backend combinations
TESTCOMPAT=1 make test

This is useful for release testing or when making changes that might affect Redis compatibility.

Integration & E2E Tests

Integration and e2e tests require external services like ClickHouse, LocalStack, RabbitMQ, etc. The test suite supports two modes for running these:

Persistent infrastructure (recommended): Run make up/test once, then use TESTINFRA=1 for all test runs. This is the recommended approach for local development.

Testcontainers (fallback): Without TESTINFRA=1, tests automatically spawn containers via Testcontainers. This is convenient for CI or one-off runs but adds startup overhead.

Why persistent infrastructure?

Redis and Dragonfly always use testcontainers (one container per test) since they start quickly. Heavier dependencies like LocalStack (AWS) or GCP emulators can take 15-30 seconds to initialize. With persistent infrastructure, you pay this cost once and get fast iteration from then on.

To run the test infrastructure:

$ make up/test

## to take the test infra down
# $ make down/test

It will run a Docker compose stack called outpost-test which runs the necessary services at ports ":30000 + port". For example, ClickHouse usually runs on port :9000, so in the test infra it will run on port :39000.

From here, you can provide env variable TESTINFRA=1 to tell the test suite to use these services instead of spawning testcontainers.

$ TESTINFRA=1 make test

Tip: You can $ export TESTINFRA=1 to use the test infra for the whole terminal session.

Integration Test Template

Here's a short template for how you can write integration tests that require an external test infra:

// Integration test should always start with "TestIntegration...() {}"
func TestIntegrationMyIntegrationTest(t *testing.T) {
  t.Parallel()

  // call testinfra.Start(t) to signal that you require the test infra.
  // This helps the test runner properly terminate resources at the end.
  t.Cleanup(testinfra.Start(t))

  // use whichever infra you need
  chConfig := testinfra.NewClickHouseConfig(t)
  awsMQConfig := testinfra.NewMQAWSConfig(t, attributesMap)
  rabbitmqConfig := testinfra.NewMQRabbitMQConfig(t)
  // ...
}