Open-Source Wikis

/

Caddy

/

How to contribute

/

Testing

caddyserver/caddy

Testing

Caddy has three flavors of tests, and you will likely want to add to all three when writing a new feature:

  1. Unit tests — table-driven *_test.go files alongside the code (modules/..., caddyconfig/...).
  2. Integration tests — full Caddy instances spun up with caddytest.NewTester (caddytest/integration/).
  3. Caddyfile adapt tests — input/expected fixture pairs under caddytest/integration/caddyfile_adapt/ that compare adapted JSON against a golden file.

Run everything with race detection (matches CI):

go test -race -short ./...

Table-driven unit tests

The preferred pattern, lifted from AGENTS.md:

func TestFeature(t *testing.T) {
    for i, tc := range []struct {
        input    string
        expected string
        wantErr  bool
    }{
        {input: "valid", expected: "result", wantErr: false},
        {input: "invalid", expected: "", wantErr: true},
    } {
        actual, err := Function(tc.input)
        if tc.wantErr && err == nil {
            t.Errorf("Test %d: expected error but got none", i)
        }
        if !tc.wantErr && err != nil {
            t.Errorf("Test %d: unexpected error: %v", i, err)
        }
        if actual != tc.expected {
            t.Errorf("Test %d: expected %q, got %q", i, tc.expected, actual)
        }
    }
}

Existing examples:

  • modules/caddyhttp/matchers_test.go (~30 KB) — exhaustive matcher table tests.
  • caddyconfig/caddyfile/parse_test.go (~24 KB) — parser cases including malformed input.
  • replacer_test.go — placeholder substitution.

Integration tests with caddytest.Tester

caddytest/caddytest.go provides a test harness that spins up a real Caddy instance against an isolated admin port and asserts HTTP behavior:

func TestHTTPFeature(t *testing.T) {
    tester := caddytest.NewTester(t)
    tester.InitServer(`
    {
        admin localhost:2999
        http_port 9080
    }
    localhost:9080 {
        respond "hello"
    }`, "caddyfile")

    tester.AssertGetResponse("http://localhost:9080/", 200, "hello")
}

Conventions:

  • Use the non-default ports 9080, 9443, 2999 so a real Caddy on the host doesn't collide.
  • Tests are in caddytest/integration/; run them with go test ./caddytest/integration/....
  • The mockdns_test.go file in caddytest/integration/ registers a fake DNS provider (dns.providers.mock) for ACME-DNS-challenge tests.

InitServer accepts both caddyfile and json as the second argument, so the same harness works whether you want to test the adapter or the underlying JSON.

Caddyfile adapt fixtures

Under caddytest/integration/caddyfile_adapt/ and caddyconfig/caddyfile/testdata/ you will find pairs of input fragments and expected JSON outputs. The test runner reads each fixture, runs the Caddyfile adapter, and diffs the result against the golden file.

When adding a directive or changing how one expands, add a fixture pair so the change is visible in git diff and so future refactors can't silently regress the output.

Fuzz tests

Several core parsers ship fuzz harnesses:

  • caddyconfig/caddyfile/lexer_fuzz.go, formatter_fuzz.go
  • caddyconfig/httpcaddyfile/addresses_fuzz.go
  • replacer_fuzz.go, duration_fuzz.go, listeners_fuzz.go
  • modules/caddyhttp/templates/frontmatter_fuzz.go

Run with go test -fuzz=FuzzX -fuzztime=30s ./path/.... Add a corpus seed to testdata/fuzz/<TestName>/ for known-tricky inputs.

What CI runs

.github/workflows/ci.yml does:

  1. go build ./cmd/caddy with -trimpath -ldflags="-w -s".
  2. A "smoke test" via ./caddy start && ./caddy stop to make sure the service-style start/stop path works.
  3. go test -v -coverprofile=cover-profile.out -short -race ./....
  4. The same matrix on Linux, macOS, and Windows.
  5. A separate s390x-test job that rsyncs the tree to an IBM Z VM and runs the suite there.

.github/workflows/lint.yml runs golangci-lint, and cross-build.yml confirms goreleaser can produce binaries for every advertised platform.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Testing – Caddy wiki | Factory