selftest

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package selftest defines the e2a critical-path self-test: a small battery of scenarios that exercise the real product paths (liveness, authenticated read, the inbound SMTP→webhook round-trip with HMAC verification, and a self-send loopback) against a running instance.

The same battery is consumed three ways (see docs/design/prober-selftest.md):

  • the e2e tests (in-process, against testutil.TestServer);
  • the `e2a selftest` CLI (self-hosters validating an install);
  • cmd/e2a-prober (continuous prod monitor + deploy bake-gate signal).

Scenarios are data (a []Scenario), so adding a check is a list edit. Each scenario carries a SmokeSafe flag: only read-only / round-trip / loopback scenarios that cause no real-world side effect (no external email, no owner notifications, no metering) may run against production. The prober runs only the SmokeSafe subset against live prod; the full set runs in-process.

Index

Constants

This section is empty.

Variables

View Source
var All = []Scenario{
	{Name: "liveness", SmokeSafe: true, Run: scenarioLiveness},
	{Name: "auth_read", SmokeSafe: true, Run: scenarioAuthRead},
	{Name: "inbound_round_trip", SmokeSafe: true, Run: scenarioInboundRoundTrip},

	{Name: "outbound_send", SmokeSafe: true, Run: scenarioOutboundSend},
	{Name: "self_send_loopback", SmokeSafe: true, Run: scenarioSelfSendLoopback},

	{Name: "agent_lifecycle", SmokeSafe: true, Run: scenarioAgentLifecycle},

	{Name: "mcp_http_round_trip", SmokeSafe: true, Run: scenarioMCPHTTPRoundTrip},
}

All is the critical-path battery. Every scenario here is SmokeSafe: read-only, a loopback (no egress), the inbound round-trip (synthetic mail to the probe agent), or a real outbound send to the AWS mailbox simulator (no real recipient). None meters (the probe runs under a system-class account) and none emails an owner.

Functions

This section is empty.

Types

type Delivery

type Delivery struct {
	Headers http.Header
	Body    []byte
}

Delivery is one webhook callback captured by an HTTPSink.

type HTTPSink

type HTTPSink struct {
	// contains filtered or unexported fields
}

HTTPSink is an http.Handler that captures webhook deliveries and lets a scenario await one matching a predicate. The shipped prober mounts it at /sink on its internal server; the in-process tests mount it on an httptest.Server. It is safe for concurrent use.

func NewHTTPSink

func NewHTTPSink() *HTTPSink

NewHTTPSink returns an empty sink.

func (*HTTPSink) Await

func (s *HTTPSink) Await(ctx context.Context, match func(Delivery) bool, timeout time.Duration) (*Delivery, error)

Await returns the first delivery (new or already-buffered) for which match returns true, or an error if ctx/timeout elapses first. It scans the buffer on every new delivery so out-of-order arrivals are handled.

func (*HTTPSink) ServeHTTP

func (s *HTTPSink) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP records the delivery and returns 200. Body read failures are recorded as empty deliveries (the awaiting scenario will simply not match and time out, surfacing the problem) rather than 500s.

type Probe

type Probe struct {
	HTTPBaseURL   string        // e.g. http://e2a:8080 — API + /api/health
	APIKey        string        // probe agent's API key (Bearer)
	AgentEmail    string        // the synthetic probe agent address
	SMTPAddr      string        // host:port of the inbound SMTP listener
	WebhookSecret string        // signing secret of the probe webhook (HMAC verify)
	MCPBaseURL    string        // deployed streamable-HTTP MCP endpoint, e.g. http://mcp-server:3000/mcp; empty ⇒ mcp scenario skips
	Sink          *HTTPSink     // receives the webhook callback for the round-trip
	HTTP          *http.Client  // nil → defaultHTTPClient
	Timeout       time.Duration // round-trip await timeout; 0 → defaultRoundTripTimeout
}

Probe carries everything a scenario needs to talk to a running instance. It is transport-only config plus collaborators; it holds no test scaffolding so both the shipped prober and the in-process tests construct it directly.

type Result

type Result struct {
	Name       string `json:"name"`
	Status     Status `json:"status"`
	DurationMS int64  `json:"duration_ms"`
	Detail     string `json:"detail,omitempty"` // human-readable; never contains secrets
}

Result is the outcome of one scenario run.

func Run

func Run(ctx context.Context, p *Probe, scenarios []Scenario, smokeOnly bool) []Result

Run executes the given scenarios in order and returns their results. When smokeOnly is true, scenarios with SmokeSafe=false are skipped (use this when running against production). Run never aborts early — every scenario runs so the caller sees the full picture in one pass.

type Scenario

type Scenario struct {
	Name      string
	SmokeSafe bool
	Run       func(ctx context.Context, p *Probe) Result
}

Scenario is one critical-path check. Run is given the resolved Probe and returns a Result; it must not panic on failure — return StatusFail with a Detail instead.

type Status

type Status string

Status is the tri-state result of a single scenario, mirroring the IETF health-check vocabulary (draft-inadarei-api-health-check).

const (
	StatusPass Status = "pass"
	StatusWarn Status = "warn"
	StatusFail Status = "fail"
)

func Worst

func Worst(results []Result) Status

Worst returns the most severe status across results (fail > warn > pass). An empty slice is treated as fail — "no checks ran" is not healthy.

Jump to

Keyboard shortcuts

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