testing

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package testing provides integration test helpers for Deployah scenarios.

Scenario directories under scenarios/ hold sample specs, environment files, expected Kubernetes output, and optional e2e.yaml Kind fixtures. DiscoverScenarios finds them; IntegrationTestSuite loads a spec, generates a chart, renders templates, and compares results to golden files. LoadE2EFixture decodes e2e.yaml.

Index

Constants

View Source
const DefaultE2EStepTimeout = 3 * time.Minute

DefaultE2EStepTimeout is the wait applied when e2e.yaml omits timeout.

View Source
const E2EFixtureFile = "e2e.yaml"

E2EFixtureFile is the Kind fixture filename in a scenario directory.

Variables

View Source
var AllowedE2EImages = []string{
	"nginx:latest",
	"nginx:1.26",
	"busybox:1.36",
	"redis:7-alpine",
	"redis:7",
	"postgres:16",
}

AllowedE2EImages is the Kind preload list. LoadE2EFixture rejects scenario specs that reference any other image.

View Source
var TestScenariosDir = getTestScenariosDir()

TestScenariosDir is the directory containing integration test scenarios.

Functions

func DiffContainsByKey added in v0.8.0

func DiffContainsByKey(path string, want, got []any) []string

DiffContainsByKey reports paths where each object in want is not found among got by identity key ("name", then "type") and recursive subset match. Extra got items are ignored. An empty want matches anything.

func DiffSubset added in v0.8.0

func DiffSubset(path string, want, got any) []string

DiffSubset reports JSON-pointer-style paths where want is not a subset of got. An empty result means every value in want is present in got.

Maps: only keys present in want are compared; extra keys in got are ignored. A nil value in want (YAML null) requires the key to be absent or nil in got. Scalar slices must match in length and order. An empty want slice matches any got slice. Object slices (elements that are maps) are matched by identity key "name", then "type"; extra got elements are ignored.

func RunPlanScenarioTest added in v0.4.0

func RunPlanScenarioTest(t *testing.T, scenario PlanTestScenario)

RunPlanScenarioTest resolves scenario's previous/current manifest pair, computes the diff through the real plan engine, and checks the result against plan-config.yaml (and, when present, golden.txt/golden.json).

Types

type DeleteOp added in v0.8.0

type DeleteOp struct{}

DeleteOp maps to `deployah delete`.

type DeployOp added in v0.8.0

type DeployOp struct {
	Spec string   `json:"spec,omitempty"`
	Args []string `json:"args,omitempty"`
}

DeployOp maps to `deployah deploy`.

type E2EFixture added in v0.8.0

type E2EFixture struct {
	Env       string              `json:"env"`
	Parallel  *bool               `json:"parallel,omitempty"`
	Timeout   string              `json:"timeout,omitempty"`
	Resources []ResourceAssertion `json:"resources,omitempty"`
	Steps     []Step              `json:"steps,omitempty"`
}

E2EFixture is the decoded form of scenarios/*/e2e.yaml, requiring exactly one of Resources or Steps.

func LoadE2EFixture added in v0.8.0

func LoadE2EFixture(path, scenarioDir string) (E2EFixture, error)

LoadE2EFixture reads path, validates document shape, and checks that images in scenarioDir specs are on AllowedE2EImages.

func (E2EFixture) RunParallel added in v0.8.0

func (f E2EFixture) RunParallel() bool

RunParallel reports whether the fixture may run concurrently. A nil Parallel field means true.

func (E2EFixture) StepTimeout added in v0.8.0

func (f E2EFixture) StepTimeout(step Step) (time.Duration, error)

StepTimeout is the per-step wait: step override, then fixture default, then DefaultE2EStepTimeout.

type IntegrationTestSuite

type IntegrationTestSuite struct {
	// ScenariosDir is the root directory of test scenarios.
	ScenariosDir string
	// OutputDir is the temporary workspace for a test run.
	OutputDir string
}

IntegrationTestSuite runs scenario-based chart and manifest tests.

func NewIntegrationTestSuite

func NewIntegrationTestSuite(t *testing.T) *IntegrationTestSuite

NewIntegrationTestSuite creates a suite rooted at TestScenariosDir.

func (*IntegrationTestSuite) RunScenarioTest

func (suite *IntegrationTestSuite) RunScenarioTest(t *testing.T, scenario TestScenario)

RunScenarioTest executes a test for a specific scenario

type LogsOp added in v0.8.0

type LogsOp struct {
	Component string `json:"component"`
	Contains  string `json:"contains"`
}

LogsOp maps to `deployah logs`.

type PlanConfig added in v0.4.0

type PlanConfig struct {
	// FreshInstall selects an empty previous manifest instead of resolving
	// one from before.yaml or previous.yaml, for the fresh-install case
	// where neither file is expected to exist.
	FreshInstall bool `yaml:"freshInstall"`
	// Changes lists every expected change, in the exact order
	// [plan.ComputeDiff] returns them (sorted by Kind, then Name).
	Changes []PlanConfigChange `yaml:"changes"`
	// Summary is the expected change tally.
	Summary PlanConfigSummary `yaml:"summary"`
	// HooksChanged asserts [plan.Plan.HooksChanged]. True when hook tasks
	// are present on a fresh install (Helm reports hook manifests).
	HooksChanged bool `yaml:"hooksChanged"`
	// Masked lists field paths (as they appear in a Changes[].Fields[]
	// entry's Path) that [plan.ApplyMasking] must flag as masked. Every
	// masked path [RunPlanScenarioTest] finds in the computed plan must
	// appear here, and vice versa.
	Masked []string `yaml:"masked"`
	// Warning is documentary only: this offline harness has no live/faked
	// release store to compute a real warning from ([plan.LastSuccessfulRelease]
	// is covered separately in history_test.go), so the test runner just
	// sets Header.Warning to this value before checking it.
	Warning string `yaml:"warning"`
}

PlanConfig is the structural expectation a scenario author writes by hand in plan-config.yaml: what plan.ComputeDiff must produce for this scenario's before/after pair, independent of how the text or JSON renderers format it.

type PlanConfigChange added in v0.4.0

type PlanConfigChange struct {
	Action string            `yaml:"action"`
	Kind   string            `yaml:"kind"`
	Name   string            `yaml:"name"`
	Fields []PlanConfigField `yaml:"fields"`
}

PlanConfigChange is one expected entry in PlanConfig.Changes.

type PlanConfigField added in v0.4.0

type PlanConfigField struct {
	Path string `yaml:"path"`
	Old  string `yaml:"old"`
	New  string `yaml:"new"`
}

PlanConfigField is one expected field-level difference within a PlanConfigChange. Old is empty for an added field; New is empty for a removed field, mirroring plan.FieldDiff.

type PlanConfigSummary added in v0.4.0

type PlanConfigSummary struct {
	Add     int `yaml:"add"`
	Change  int `yaml:"change"`
	Destroy int `yaml:"destroy"`
}

PlanConfigSummary is the expected plan.Summary.

type PlanTestScenario added in v0.4.0

type PlanTestScenario struct {
	// Name is the scenario directory name (e.g. "plan-image-bump").
	Name string
	// Dir is the scenario's absolute directory path.
	Dir string
}

PlanTestScenario describes one scenarios/plan-* directory: a before/after manifest pair (however each side is sourced) that RunPlanScenarioTest diffs through the real plan.ComputeDiff engine and checks against plan-config.yaml.

func DiscoverPlanScenarios added in v0.4.0

func DiscoverPlanScenarios(scenariosDir string) ([]PlanTestScenario, error)

DiscoverPlanScenarios finds every scenarios/plan-* directory with a plan-config.yaml. Unlike DiscoverScenarios, deployah.yaml is optional: RunPlanScenarioTest falls back to a raw current.yaml for kinds the spec/chart pipeline can't produce (e.g. a Secret).

type ResourceAssertion added in v0.8.0

type ResourceAssertion struct {
	Match    map[string]any `json:"match"`
	MinCount *int           `json:"minCount,omitempty"`
}

ResourceAssertion is one cluster assertion. Match is a partial Kubernetes object compared with DiffSubset. MinCount defaults to 1; 0 requires the list to be empty. When Match sets metadata.name, MinCount may only be 0 or 1 because a named Get cannot count list items.

func (ResourceAssertion) Count added in v0.8.0

func (r ResourceAssertion) Count() int

Count returns the minimum matching resources, or 1 when MinCount is unset.

type RunOp added in v0.8.0

type RunOp struct {
	Task string `json:"task"`
}

RunOp maps to `deployah run`.

type Step added in v0.8.0

type Step struct {
	Deploy         *DeployOp           `json:"deploy,omitempty"`
	Run            *RunOp              `json:"run,omitempty"`
	Logs           *LogsOp             `json:"logs,omitempty"`
	Delete         *DeleteOp           `json:"delete,omitempty"`
	Timeout        string              `json:"timeout,omitempty"`
	StderrContains string              `json:"stderrContains,omitempty"`
	StdoutContains string              `json:"stdoutContains,omitempty"`
	Resources      []ResourceAssertion `json:"resources,omitempty"`
}

Step is one CLI operation plus optional output and resource assertions. Exactly one of Deploy, Run, Logs, or Delete must be set.

func (Step) OpName added in v0.8.0

func (s Step) OpName() string

OpName returns the operation name, or "" if none or more than one is set.

type TestScenario

type TestScenario struct {
	// Name is the scenario directory name.
	Name string
	// ScenarioDir is the relative path under TestScenariosDir.
	ScenarioDir string
	// ManifestFile is the manifest filename within ScenarioDir.
	ManifestFile string
	// Environment selects the manifest environment for chart generation.
	Environment string
	// EnvFiles lists dotenv files to copy into the test workspace.
	EnvFiles []string
	// PlatformFile is the platform filename within ScenarioDir when present.
	PlatformFile string
	// ExpectedDir is the golden output directory, relative to TestScenariosDir.
	ExpectedDir string
	// ExpectError requires manifest loading or resolution to fail.
	ExpectError bool
	// ExpectedErrors requires specific substrings in the load/resolve error message.
	ExpectedErrors []string
	// HasE2EFixture is true when the scenario directory contains e2e.yaml.
	HasE2EFixture bool
	// E2EFixturePath is the absolute path to e2e.yaml when HasE2EFixture is true.
	E2EFixturePath string
}

TestScenario describes one integration test case under scenarios/.

func DiscoverScenarios

func DiscoverScenarios(scenariosDir string) ([]TestScenario, error)

DiscoverScenarios discovers test scenarios from the directory structure.

Jump to

Keyboard shortcuts

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