testenv

package
v0.0.0-...-2769864 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

README

testenv — the shared controller test harness

A controller-runtime envtest harness shared across every controller test package, plus the CI gates for the repo's merge/apply conventions.

File Role
testenv.go Starting and stopping the envtest control plane
shared.go The process-wide shared environment, so N test packages do not each stand up an apiserver
sandbox.go An exec.Executor stand-in for tests that reach into a sandbox
Package What it holds
idempotency/ CheckApplyIdempotent and CheckReconcileConverges

The two idempotency gates

Both guard a real production bug, and both come straight from AGENTS.md's "Server-side apply: keep applied fields idempotent; put observations in status".

Check Catches
CheckApplyIdempotent A volatile value — time.Now(), a random ID, a recomputed digest — leaking into a field a client server-side-applies. A byte-identical re-apply must not bump resourceVersion
CheckReconcileConverges A reconciler that unconditionally restamps an observed-at or status field on every pass, producing a reconcile storm

Each splits into an error-returning core (Check*) and a require-based wrapper (Require*), so the package's own tests can assert the core detects a violation — something a t.FailNow-calling helper could never do.

Neither has a build tag or imports envtest; they need only a client.Client (and a reconcile.Reconciler). They are nonetheless meaningful only against a real apiserver.

Non-obvious constraints

  • The envtest control plane is machine-wide. mage test:integration and mage test:e2e serialize via an advisory lock for that reason; concurrent runs from different worktrees starve each other rather than taking turns.

Documentation

Overview

Package testenv provides a controller-runtime envtest harness shared across controller test packages.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Reset

func Reset(t *testing.T, env *Env)

Reset wipes the shared cluster back to empty between serially-run tests: it strips finalizers (tests drive Reconcile by hand, so the controller's finalizer-removal loop never runs and a plain delete would hang in Terminating), then deletes every spicebox CR kind (enumerated from the scheme, so new CRDs are covered automatically) plus the core kinds tests and the operator create.

Reset intentionally does NOT delete namespaces — envtest has no namespace GC, so a namespace deletion hangs in Terminating; it empties each namespace instead. Tests that create a namespace must tolerate it already existing on a later test run within the same package.

func RunPackage

func RunPackage(m *testing.M) int

RunPackage boots ONE envtest cluster for the whole package, runs all the package's tests against it, then stops it — so the apiserver+etcd are booted once per package instead of once per test. Use from TestMain:

func TestMain(m *testing.M) { os.Exit(testenv.RunPackage(m)) }

If envtest binaries are unavailable, it leaves `shared` nil and still runs the tests (each Shared(t) call then skips) — matching Start's skip behavior.

Any OTHER boot failure aborts the package with a non-zero exit instead. This is the difference between "this machine cannot run envtest" and "envtest is broken": the second used to leave `shared` nil too, so every test in the package skipped and the suite exited 0 having verified nothing.

func SandboxRuntimes

func SandboxRuntimes(t *testing.T, c client.Client) sandboxkinds.Runtimes

SandboxRuntimes builds one Runtime per sandbox kind registered in the process (via each kind's own blank import, e.g. `_ ".../sandboxkinds/pod"`) against c, execing through a throwaway fake binder. Every spiceboxsession.Reconciler an integration test constructs needs this: without a populated Runtimes, a session's resolved kind never resolves — Runtimes.For is fail-closed, not a fallback to the built-in backend — so no sandbox is ever created and any wait for one times out.

A test whose controller under test also execs into the sandbox (the ToolCall controller) must use SandboxRuntimesWithExec instead — the throwaway binder here is never programmed, so its responses would never be found.

func SandboxRuntimesWithExec

func SandboxRuntimesWithExec(t *testing.T, c client.Client, execFor func(namespace, pod, container string) exec.Executor) sandboxkinds.Runtimes

SandboxRuntimesWithExec is SandboxRuntimes, but binds every kind's exec transport to execFor instead of an internal throwaway fake. Pass a fake.Binder's For method to let the ToolCall controller's execs land on the same Binder the test programs and asserts against.

Types

type Env

type Env struct {
	Cfg    *rest.Config
	Client client.Client
	Scheme *apiruntime.Scheme
	// contains filtered or unexported fields
}

func Shared

func Shared(t *testing.T) *Env

Shared returns the package-shared env, skipping the test if envtest is unavailable. It registers a t.Cleanup that resets cluster state after the test, so the next test sees an empty cluster.

func Start

func Start(t *testing.T) *Env

Start boots an envtest cluster with Spicebox CRDs installed.

Directories

Path Synopsis
Package idempotency provides two CI-gate checks for the merge/apply convention in AGENTS.md's "Server-side apply: keep applied fields idempotent; put observations in status":
Package idempotency provides two CI-gate checks for the merge/apply convention in AGENTS.md's "Server-side apply: keep applied fields idempotent; put observations in status":

Jump to

Keyboard shortcuts

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