Testing¶
The library is tested at three levels: unit tests in each package, fuzz targets over every parser and independent ACME clients in a separate module. This page explains how to run each level and what it proves.
Unit tests¶
make test
Runs go vet and every test under the race detector with coverage written to the scratch
directory. The root package tests drive complete flows through the handler with memstore, a test
CA and test validators, including account, order, renewal, revocation, timeout, recovery and
tkauth-01 scenarios. The challenge tests check proof and egress rules against local servers.
memstore runs the storetest suite.
Fuzzing¶
make fuzz
make fuzz FUZZ_TIME=2m
Fuzzes the JWS, JWK, strict JSON, identifier, DNS response and TLS-ALPN proof parsers for
FUZZ_TIME each. CI runs 30 seconds per target on every push. Go writes a failing input under the
package's testdata/fuzz directory. Commit that input with the fix so it stays a regression test.
The target passes -fuzzminimizetime 0, so Go does not minimize inputs. Minimization stalls the
workers for seconds at a time and a worker that is still busy when FUZZ_TIME expires makes Go
report the run as failed with context deadline exceeded. Set FUZZ_MINIMIZE_TIME to a duration
such as 1m when a crash is found and a smaller reproducer is wanted.
Interoperability¶
make test-interop
Runs acmez, Certbot, lego, the Go crypto/acme client and a raw go-jose client against the server
over HTTPS with the SQLite store, plus the concurrency and two-process recovery tests. Missing
tools, failed tests and skipped required scenarios fail the gate. The clients, versions and
scenarios are listed on Tested clients.
Certbot runs from a pinned Python environment. Install Python 3.14, then:
python3 -m venv .cache/certbot
.cache/certbot/bin/python -m pip install --no-deps --only-binary=:all: --require-hashes -r test/interop/requirements.txt
.cache/certbot/bin/python -m pip check
ACME_CERTBOT="$PWD/.cache/certbot/bin/certbot" make test-interop
ACME_CERTBOT selects the executable and its version must match the pin. The Go clients run in
process and need no installation. make test-recovery runs the process recovery and fencing tests
alone, without Certbot.
test/interop/README.md describes every scenario, the SQLite adapter and the evidence the gate
writes.
The cert-manager scenario¶
make test-cert-manager
Starts a kind cluster, deploys the server from test/interop/cmd/server with the test CA and an
HTTP-01 validator, issues and renews a certificate through a cert-manager ClusterIssuer and
verifies both against the test root. It needs Docker, kind, kubectl and openssl. The cluster is
deleted afterwards unless ACME_KEEP_CLUSTER=1 is set. CI runs it weekly and on request.
Testing your integration¶
The pieces you implement have their own verification paths:
| Your code | Verify with |
|---|---|
Store |
storetest.Run in your test suite, plus a crash test between BeginIssuance and CompleteIssuance |
Issuer and Revoker |
A test that calls Issue or Revoke twice with one OperationID and expects one CA action |
Validator |
The same table-driven tests the challenge package uses against a local target |
| The whole host | An ACME client against a staging deployment, as in Getting started |
acmeserver.ClockFunc replaces the clock in tests, which makes expiry and retry timing
deterministic. Config.AllowInsecureBaseURL and the validators' TestPort options exist for
tests that cannot bind privileged ports or terminate TLS.
Evidence¶
The interoperability gate writes interop-summary.json into the scratch directory with the Go
version, operating system, architecture, test names, outcomes and elapsed times. Nothing else.
CI uploads only that summary. Keys, databases and client logs stay local.