caddyserver/caddy
caddytest
Package: github.com/caddyserver/caddy/v2/caddytest.
Integration-test harness that spins up a real Caddy instance against an isolated admin port and asserts HTTP behavior.
Purpose
Make it cheap and reliable to write end-to-end tests that:
- Start a Caddy instance with a specific Caddyfile or JSON config.
- Issue real HTTP/HTTPS requests against it.
- Assert response status, body, headers, redirects.
- Tear everything down at test end.
This is what caddytest/integration/... uses, and it's the right place to add tests for cross-module behavior.
Directory layout
| Path | Role |
|---|---|
caddytest/caddytest.go |
The Tester type and its assertion helpers (~17 KB) |
caddytest/caddytest_test.go |
Tests of the harness itself |
caddytest/*.crt, *.key, *.pem, caddy.ca.cer |
Pre-issued test certificates (avoid hitting real ACME) |
caddytest/integration/ |
Big collection of integration tests using Tester |
caddytest/integration/caddyfile_adapt/ |
Caddyfile→JSON golden-file fixtures |
Key abstractions
| Type | Where | Description |
|---|---|---|
Tester |
caddytest.go |
Holds the running Caddy admin URL, an HTTP client, and helper methods |
NewTester(t *testing.T) |
caddytest.go |
Spawns a Caddy instance on isolated ports, returns the tester |
InitServer(config string, configType string) |
caddytest.go |
Loads the given config (caddyfile or json) into the running instance |
AssertGetResponse, AssertPostResponseBody, AssertResponseCode, AssertRedirect |
caddytest.go |
Common HTTP assertions |
How it works
graph TD
NewTester[NewTester(t)] --> Spawn[start in-process caddy]
Spawn --> Admin[admin on localhost:2999]
Test[test code] -->|InitServer| Admin
Admin -->|/load| RunningCfg[running config]
Test -->|HTTP request| Caddy[caddy on 9080/9443]
Caddy --> Resp
Resp --> Test
TestEnd -->|t.Cleanup| Stop
Stop -->|/stop| AdminIn-process Caddy
NewTester initializes the same module registry as a real Caddy binary (by importing modules/standard) and starts the admin endpoint on localhost:2999. The HTTP server, when later configured via InitServer, uses ports 9080 (HTTP) and 9443 (HTTPS) by convention.
Config loading
InitServer(config, "caddyfile") runs the Caddyfile adapter and POSTs the result to /load. InitServer(config, "json") posts the JSON directly. The convention block at the top of every test config is:
{
skip_install_trust
admin localhost:2999
http_port 9080
https_port 9443
grace_period 1ns
}skip_install_trust prevents the test from modifying the OS trust store; grace_period 1ns makes shutdown immediate.
Assertions
Helpers handle the common patterns:
AssertGetResponse(url, expectedStatus, expectedBody)AssertResponseCode(req, expectedStatus)AssertResponse(req, expectedStatus, expectedBody)AssertRedirect(url, expectedLocation, expectedStatus)AssertGetResponseBody(url, expectedStatus, expectedBody)
The bundled HTTP client trusts the test CA (caddy.ca.cer) so HTTPS works without extra setup.
Mock DNS
caddytest/integration/mockdns_test.go registers dns.providers.mock, an in-memory DNS provider used to test ACME-DNS-01 issuance flows without touching real DNS.
Caddyfile adapt fixtures
Under caddytest/integration/caddyfile_adapt/, each test reads a .txt Caddyfile, runs the adapter, and diffs the result against an expected JSON file. This is how the Caddyfile→JSON conversion is regression-tested.
Usage example
func TestStaticResponse(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")
}That's everything you need for a passing test. No mocks, no fakes — a real Caddy.
Integration points
- Module registry:
caddytestimportsmodules/standard, so all default modules are available. - CI: runs
go test ./caddytest/integration/...as part of the normal test step. - Caddyfile adapter: the fixtures are the regression suite for adapter changes.
Entry points for modification
- Add a new assertion helper?
caddytest.go. Aim for the smallest helper that covers the case. - Add an integration test? Place it under
caddytest/integration/<area>/and useNewTester. - Add a new Caddyfile-adapt fixture?
caddytest/integration/caddyfile_adapt/with paired.txt(input) and the expected JSON file.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.