test(e2e): a container upstream stub, and the 7 oci remote rows it covers

What this adds

A programmable container upstream stub, a raw container blob reader, and the 7 rows of the OCI catalog's remote group they cover. Catalog coverage goes 112 → 119 on top of the maven branch.

  • e2e/internal/upstream/ociupstream, mirroring npmupstream: programmable blob responses, per-method request recording, and the failure modes the rows need — a digest the upstream does not carry, bytes that miss their digest, an unreachable host.
  • A raw container blob reader on registry.Client, for GET/HEAD with arbitrary request headers. The only raw container HTTP in the tree was ManifestFraming, which is manifest-only; nothing could send a Range or read Docker-Content-Digest off a blob response.
  • 7 rows: blob-cold-miss, blob-cold-head, blob-range-on-miss, blob-upstream-missing, blob-upstream-unreachable, blob-digest-mismatch, and write-rejected.

A harness defect this fixes

registry.Client.CreateRemoteRepository could not create a container remote at all. It always sent metadata_cache_validity_hours, which CreateContainerRemoteSettingsRequest does not declare and refuses under additionalProperties: false, against a server decoding settings per family with DisallowUnknownFields — a 400 on every OCI and docker remote create. The body is now picked per family. Nothing depended on the broken path, so no existing row changes.

Four rows refused, not narrowed

Each is indexed in docs/testing/e2e/limitations.md.

Row Why
blob-cache-hit, blob-range-unsatisfiable Each cell specifies a redirect-delivery arm. The rig cannot serve one — its object store is an in-cluster ClusterIP with no ingress — and namespaces.delivery_mode_override has no writer. The proxy arm of each is drivable; a row narrowed to it would read as covering a cell that names two modes.
credential-never-served The container arm sends a stored credential only on the Docker token exchange, and the realm scheme is unconditionally https. The rig terminates no TLS, so no stub realm this suite can serve will be used.
blob-unhealthy-remote Reachable only with a shorter health-sweep interval templated into the rig; at the shipped 5-minute interval and threshold of 3 it takes 15 minutes to mark a remote unhealthy.

blob-range-unsatisfiable is blocked twice over: its no-download clause has no read at all, which is its own entry.

delete-artifact is not here, and why

e2e.oci.lifecycle.delete-artifact stays not started. Its referrers clause specifies that a deleted subject's referrers stop listing it, and they do not — #1005 has the rig reproduction. The pull-by-digest and pull-by-tag assertions are real coverage nothing else has, so they live in e2e/bootstrap/harness/manifest_delete_test.go declaring no scenario id, alongside the existing "prove the capability the catalog's rows will be written on" tests in that surface. Its pattern entry is removed, so authorable does not advertise a row whose next writer would land on the defect.

Reviewable LOC

11 files, +1,575/−38.

Group +
ociupstream and its unit tests 542
e2e/bootstrap/ rows, the harness-surface test and suite.go 584
registry.Client and its tests 275
docs (limitations.md, oci.md) 102
patterns.go 72

Past 500. The stub has no consumer until the rows land and the rows cannot be split from patterns.go and oci.md without an intermediate commit that fails check, so the useful cut is the one the commit sequence gives: reader, stub, rows.

Verification

  • e2e-catalog check: 0 disagreements.
  • go build -tags=e2e ./e2e/..., go test ./e2e/...: pass.
  • golangci-lint --build-tags=e2e at the pinned 2.13.2: 0 issues.
  • check-comment-caps.sh --base origin/main: OK.

The rows are unverified against a live caproni rig. The stub has unit tests; every assertion about Artifact Registry's own responses is unexercised.

Merge request reports

Loading
Loading