goldengen

package
v0.14.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package goldengen is a test-only helper that sweeps a consumer-supplied version universe, classifies versions into behaviorally-distinct gating regimes by firing-set, generates the minimal goldens covering them, and asserts per-fixture mutation gating.

It is opt-in: a consumer that does not import it pays nothing, and the core Build/ApplyIntent path never references it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckGating

func CheckGating[T any](f Fixture[T], versions []string, firing map[string][]string) error

CheckGating verifies a fixture's Requires/Forbids expectations against its per-version firing-sets. The lattice is:

  • Requires with empty For: the name fires at some swept version.
  • Requires with For=v: the name fires at v.
  • Forbids with empty For: the name fires at no swept version.
  • Forbids with For=v: the name does not fire at v.

It returns a descriptive error on the first violation.

Types

type ComponentPreviewer

type ComponentPreviewer interface {
	RegisteredMutations() []string
	FiringSet() ([]string, error)
	Preview() ([]client.Object, error)
}

ComponentPreviewer is a built component: introspectable and rendered to many client.Objects. *component.Component satisfies it.

type Config

type Config[T any] struct {
	// Dir is the root directory for generated goldens and the manifest.
	Dir string
	// Versions is the version universe to sweep, in supplied order. Representative
	// selection uses this order.
	Versions []string
	// Exclude lists registered mutation Names deliberately left unaccounted by the
	// completeness check. It does not affect gating or golden generation.
	Exclude []string
	// Fixtures are the specs to build and assert across the version sweep.
	Fixtures []Fixture[T]
	// Build materializes a Unit from a fixture spec at a version.
	Build func(version string, spec T) (Unit, error)
}

Config declares the whole version matrix: the versions to sweep, the fixtures to build, the scheme to serialize with, and the Build function that materializes a Unit from a fixture spec at a version.

func LoadMatrix

func LoadMatrix[T any](
	path string,
	newSpec func() T,
	build func(version string, spec T) (Unit, error),
) (Config[T], error)

LoadMatrix reads a YAML matrix file at path and returns a Config ready to run. The file mirrors Config without its Go-only Build, which is supplied here as an argument. Each fixture's CR comes from either an inline spec or an external specFile (exactly one of the two); the CR is unmarshalled into a fresh T from newSpec. A specFile path is resolved relative to the matrix file's directory. Supplying both spec and specFile, or neither, is a load error. The resulting Config is validated via Config.Validate before it is returned, so invariants such as every Expect.For being a member of versions are enforced.

The scheme used to serialize rendered objects is supplied by the build function, which passes it to goldengen.Resource or goldengen.Component when it constructs each Unit.

func (Config[T]) Validate

func (c Config[T]) Validate() error

Validate checks the static invariants of the config before any sweep runs: non-empty Versions, a non-nil Build, a non-empty Dir, unique non-empty fixture names, non-empty expectation names, and every Expect.For being a member of Versions.

type Expect

type Expect struct {
	// Name is the registered mutation Name the expectation applies to.
	Name string
	// For optionally pins the expectation to a single version from Config.Versions.
	For string
}

Expect is an assertion that a named mutation fires (Requires) or does not fire (Forbids) over a fixture's version sweep. For is optional; when set it must be a concrete version drawn from Config.Versions and pins the assertion to that version instead of quantifying over the whole sweep.

type Fixture

type Fixture[T any] struct {
	// Name identifies the fixture and names its golden subdirectory.
	Name string
	// Spec is the input passed to Config.Build for every version.
	Spec T
	// Requires lists mutations that must fire, existentially or pinned via For.
	Requires []Expect
	// Forbids lists mutations that must not fire, existentially or pinned via For.
	Forbids []Expect
}

Fixture is one spec and the gating expectations the author asserts for it.

type FixtureManifest

type FixtureManifest struct {
	Name    string           `json:"name"`
	Regimes []RegimeManifest `json:"regimes"`
}

FixtureManifest records all regimes derived for one fixture.

type Generator

type Generator[T any] struct {
	// contains filtered or unexported fields
}

Generator runs a version matrix: per-fixture gating assertions, minimal goldens, and a coverage manifest, all derived from one Config.

func New

func New[T any](cfg Config[T]) *Generator[T]

New creates a Generator from a Config.

func (*Generator[T]) AssertComplete

func (g *Generator[T]) AssertComplete(code int) int

AssertComplete proves that every registered mutation is consciously accounted for: each one is either exercised by at least one fixture, by being named in that fixture's Requires (which makes Run assert it actually fires), or it is explicitly listed in Config.Exclude as deliberately not covered. Nothing registered may slip through both untested and unexcluded. It is the guard that a newly added mutation forces exactly one decision: cover it or exclude it.

It is called from the consumer's TestMain so its result gates the package's exit code:

func TestMain(m *testing.M) { os.Exit(gen.AssertComplete(m.Run())) }

Concretely, accounting holds when union(Requires names across all fixtures) plus Config.Exclude equals the set of registered mutation Names. The registered universe is gathered by building each fixture once (registration is version-independent). Forbids does not count toward coverage: forbidding a mutation asserts where it must not fire, which is not evidence that it works, so a mutation that only ever appears in Forbids is still unaccounted.

It returns code unchanged when code is already nonzero (the tests failed, so accounting noise would only obscure that) or when accounting holds. Otherwise it prints the violations to stderr and returns a nonzero code. Violations are: a registered mutation neither required by any fixture nor excluded; a stale Exclude or Requires name not registered by any fixture; and an empty registered mutation Name.

func (*Generator[T]) Run

func (g *Generator[T]) Run(t *testing.T)

Run validates the config, asserts per-fixture gating, and writes (or compares) one golden per regime at <Dir>/<fixture>/<representative>.yaml plus the coverage manifest at <Dir>/manifest.yaml. It honors WithUpdate.

func (*Generator[T]) WithUpdate

func (g *Generator[T]) WithUpdate(enabled bool) *Generator[T]

WithUpdate controls whether Run overwrites goldens and the manifest. Wire it to a -update test flag: gen.WithUpdate(*update).

type Manifest

type Manifest struct {
	Fixtures []FixtureManifest `json:"fixtures"`
}

Manifest is the reviewable coverage map: per fixture, the distinct gating regimes with their representative version and firing-set.

func (Manifest) YAML

func (m Manifest) YAML() ([]byte, error)

YAML renders the manifest as deterministic YAML.

type Regime

type Regime struct {
	// Representative is the first version in supplied order within the group.
	Representative string
	// Versions are all versions in this regime, in supplied order.
	Versions []string
	// Firing is the shared firing-set, sorted.
	Firing []string
}

Regime is a group of swept versions sharing an identical firing-set.

func ClassifyRegimes

func ClassifyRegimes(versions []string, firing map[string][]string) []Regime

ClassifyRegimes groups versions (in supplied order) by identical firing-set. Two versions belong to the same regime when their firing-sets are equal as sets, independent of order. Regimes are returned in order of first appearance; the representative of each is the first version in supplied order belonging to it.

type RegimeManifest

type RegimeManifest struct {
	Representative string   `json:"representative"`
	Versions       []string `json:"versions"`
	Firing         []string `json:"firing"`
}

RegimeManifest records one behaviorally-distinct regime of a fixture: its representative version, the versions it covers, and the shared firing-set.

type ResourcePreviewer

type ResourcePreviewer interface {
	concepts.MutationInspector
	concepts.Previewable
}

ResourcePreviewer is a built single-resource primitive: it can be introspected and rendered to one client.Object. Every built-in primitive satisfies it.

type Unit

type Unit interface {
	// RegisteredMutations returns the deduplicated Names of every registered mutation.
	RegisteredMutations() []string
	// FiringSet returns the Names of mutations enabled at the built version.
	FiringSet() ([]string, error)
	// RenderYAML renders the unit's desired state as canonical golden YAML.
	RenderYAML() ([]byte, error)
}

Unit is a built resource or component the generator can introspect and render.

func Component

func Component(comp ComponentPreviewer, scheme *runtime.Scheme) Unit

Component adapts a built component to a Unit, serializing its managed resources into a multi-document YAML stream through the golden package.

func Resource

func Resource(res ResourcePreviewer, scheme *runtime.Scheme) Unit

Resource adapts a built primitive resource to a Unit, serializing through the golden package with the given scheme.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL