Cover the mirror client build-error path in buildMirrorRepositories
#1,309 opened on Aug 15, 2026
Repository metrics
- Stars
- (270 stars)
- PR merge metrics
- (Avg merge 5d 20h) (42 merged PRs in 30d)
Description
What
buildMirrorRepositories in registry/remote/builder.go is at 14.3% statement coverage (2 of 14). Only the empty-mirrors guard is exercised:
if len(props.Mirrors) == 0 {
return nil, nil
}
Everything after that — the per-mirror loop that assembles mirrorProps, calls builder.Build, constructs the Registry, applies the PullFromMirror default, and appends the result — is untested.
Why it matters
This function is what turns declarative mirror configuration into the Repository instances that pulls are actually routed through. Two behaviors in particular are load-bearing and currently unpinned:
- An empty
PullFromMirrormust default toPullFromMirrorAll. Silently defaulting the other way would send traffic somewhere unintended. - A mirror whose client fails to build must return a wrapped error naming the offending
m.Location. Without that, a misconfigured mirror is very hard to diagnose.
What to do
Add tests to registry/remote/mirror_test.go. Suggested cases:
1. Multiple mirrors, happy path. Build a properties.Registry with several entries in Mirrors and assert that, for each resulting mirrorRepository, the Registry.Reference.Registry matches the mirror's Location, RepositoryName is inherited from the primary registry's Reference.Repository, and pullFromMirror matches the configured policy.
2. PullFromMirror defaulting. A mirror with PullFromMirror: "" should come back as PullFromMirrorAll. Cover the explicit "all" and "digest-only" values too.
3. Credential and attribute inheritance. Mirrors inherit Credential and Attributes from the primary registry while using their own Transport. Assert that this wiring holds.
4. Build failure. Give a mirror Transport settings that make ClientBuilder.Build fail — for example a TLS config pointing at a CA certificate path that does not exist. Assert the returned slice is nil, the error is non-nil, the message contains the mirror's Location, and the underlying cause is reachable via errors.Is / errors.Unwrap (the function wraps with %w).
5. No mirrors. len(props.Mirrors) == 0 returns nil, nil.
Check ClientBuilder.Build in registry/remote/builder.go for the cheapest way to force case 4 without a live registry — no network access should be required.
Verifying
go test ./registry/remote/ -run Test_buildMirrorRepositories -coverprofile=cover.out
go tool cover -func=cover.out | grep buildMirrorRepositories
buildMirrorRepositories should report 100.0%.
Notes for first-time contributors
- Table-driven tests are the norm in this package; a table covering cases 1, 2 and 5 with a separate function for the error case tends to read well.
- Assert on observable behavior rather than on constructor calls succeeding — a test whose only check is that a value is non-nil does not tell us much.
- Commits need a DCO sign-off (
git commit -s). See CONTRIBUTING.md.