oras-project/oras-go

Cover the mirror client build-error path in buildMirrorRepositories

Open

#1,309 opened on Aug 15, 2026

 (1 comment) (0 reactions) (0 assignees)Go (112 forks)auto 404
good first issuehelp wantedv3

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 PullFromMirror must default to PullFromMirrorAll. 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.

Contributor guide