Skip to content

No public way to render a Component's assembled resources for whole-component golden tests #121

@sourcehawk

Description

@sourcehawk

Context

A Component owns an ordered set of resources (baseline + feature mutations).
Consumers building components want to snapshot-test the desired output: given
a spec, render every resource the component would apply and assert it against a
golden file. This is the natural end-to-end test for a component — it exercises
baseline construction, mutation wiring, and registration order in one place.

Today the only public surface on Component is Reconcile(...) plus name/
condition accessors. The assembled resources are reachable only via the
unexported allManagedResources() / managedResources() (pkg/component/component.go),
and the Resource interface (pkg/component/resource.go) exposes Object() /
Identity() but not a cluster-free "render desired state" path at the
component level. There's no way to ask a built Component "what would you
apply?" without a fake client and a full reconcile.

The problem

Without a public accessor, whole-component golden tests can't be written
against the real BuildComponent(...) wiring. The test either:

  • reaches into unexported state (impossible from another package), or
  • reassembles the resource pipeline itself in test code, which duplicates the
    exact baseline+mutation registration the component already encodes and drifts
    the moment the real wiring changes — defeating the purpose of the test.

The per-resource-type PreviewObject() (e.g. on the statefulset primitive
Resource) covers single resources, so consumers can golden one resource at
a time by calling that resource's builder. What's missing is the
component-level view: render all of a component's resources together into one
golden, straight from the component the controller actually builds.

Workarounds today (all unsatisfying)

  1. Golden each resource individually by calling its own builder, and accept that
    nothing tests the component's full resource set / registration order as a
    unit.
  2. Reassemble the baseline+mutation pipeline in test code. Duplicates wiring,
    drifts from the real component, asserts a copy rather than the real thing.
  3. Spin up a fake client and run Reconcile, then read objects back from the
    fake client. Heavyweight, conflates reconcile/IO behavior with desired-state
    rendering, and is awkward for a pure "what would you apply" snapshot.

Proposed solution shape

A public, cluster-free way to obtain a component's assembled resources for
inspection/snapshotting. Some options:

  • Component.Resources() []Resource — expose the managed (and optionally
    read-only) resources so callers can iterate and call Object() /
    type-asserted PreviewObject() themselves.
  • A higher-level Component.Preview() ([]client.Object, error) that returns the
    rendered desired-state objects (baseline + mutations applied), with no client
    and no reconcile — the most directly golden-able form.

Either keeps Reconcile as the only IO path while giving consumers a
first-class hook for desired-state assertions.

Open question

Whether this should expose []Resource (flexible, caller does the rendering) or
return already-rendered []client.Object (convenient, opinionated about preview
semantics), and how read-only resources should figure in the result. Happy to
PR whichever shape you prefer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions