Help us shape the future of Go! Take the 2026 Go Developer Survey

agenttest

package
v0.4.8 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package agenttest provides reusable contract-test machinery for the interfaces declared in core/agent — agent.Engine, agent.Host, agent.Observer, agent.Referee, agent.CheckpointStore, agent.Resumer, agent.StreamSink, agent.Preparer, agent.Committer, agent.CommitViewProvider, agent.CheckpointSuggester and agent.ScriptRuntime.

Modeled on net/http/httptest, testing/iotest, and gocloud.dev/blob/drivertest: a single sibling package next to its subject covers every contract-checking surface the parent package exposes. Importable from any concrete implementation's *_test files; contains exclusively test-support code; nothing in here should be referenced from non-test production paths.

What lives here

  • EngineSuite — the standard contract every agent.Engine implementation should pass. New engines add a one-liner:

    func TestEngineContract(t *testing.T) { agenttest.EngineSuite(t, func() (agent.Engine, agenttest.Capabilities) { return newMyEngine(), agenttest.Capabilities{} }) }

  • HostSuite — the standard contract every agent.Host implementation should pass:

    func TestMyHost_Contract(t *testing.T) { agenttest.HostSuite(t, func() agent.Host { return newMyHost() }) }

  • ObserverSuite — the standard contract every agent.Observer implementation should pass (no input mutation, prompt return, concurrent safety).

  • RefereeSuite — the standard contract every agent.Referee implementation should pass.

  • CheckpointStoreSuite — the shared conformance suite every agent.CheckpointStore implementation should pass, including the optional agent.CheckpointLister / agent.CheckpointDeleter extensions.

  • ResumerSuite — the contract every agent.Resumer implementation should pass (cheap, classified, mutation-free, concurrent-safe).

  • StreamSinkSuite — the contract every agent.StreamSink implementation should pass (panic-free, ctx-observing, concurrent-safe).

  • PreparerSuite — the contract every agent.Preparer implementation should pass (non-nil fresh boards, no input mutation, ctx-observing).

  • CommitterSuite — the contract every agent.Committer implementation should pass (no input mutation, ctx-observing).

  • CommitViewProviderSuite — the contract every agent.CommitViewProvider implementation should pass (non-nil projected board, no input mutation, ctx-observing).

  • CheckpointSuggesterSuite — the contract every agent.CheckpointSuggester implementation should pass (panic-free, prompt return).

  • ScriptRuntimeSuite — the contract every agent.ScriptRuntime implementation should pass (panic-free, executes a caller-supplied minimal fixture, concurrent-safe).

  • MockHost — a minimal Host implementation that records every interaction, lets tests inject interrupts / user replies / publish-checkpoint-usage errors / steered messages, and exposes the captured envelopes / usage / checkpoints / steer queue for assertion. It implements the optional agent.SteerSource capability, so engine tests can assert where a script's host.drainSteer() call lands relative to the rest of the round. Engines may use it directly in their own tests instead of re-implementing the full Host surface.

What does NOT live here

This package does not enumerate engine- or host-specific behaviours (graph-edge ordering, script-language semantics, application-specific sandbox bus routing, …). It only asserts what every implementation of the targeted interface is contractually obliged to do. Implementation-specific tests live next to the implementation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckpointStoreSuite

func CheckpointStoreSuite(t *testing.T, newStore func() agent.CheckpointStore)

CheckpointStoreSuite exercises the agent.CheckpointStore contract: absent-load semantics, Save/Load round trips, last-write-wins ordering, caller ownership on both Save and Load, and concurrent use. newStore must return a fresh, ready-to-use store for every call.

The optional CheckpointLister / CheckpointDeleter interfaces are exercised when the store implements them; otherwise those subtests skip.

func CheckpointSuggesterSuite added in v0.1.2

func CheckpointSuggesterSuite(t *testing.T, f SuggesterFactory)

CheckpointSuggesterSuite runs every contract probe that applies to the agent.CheckpointSuggester produced by f:

  • a suggestion on a fresh engine must not panic and may return any error (the host logs/retries; there is no classification contract);
  • SuggestCheckpoint is advisory and MUST return promptly — it is not obligated to have written anything by the time it returns.

func CommitViewProviderSuite added in v0.1.2

func CommitViewProviderSuite(t *testing.T, f CommitViewFactory)

CommitViewProviderSuite runs every contract probe that applies to the agent.CommitViewProvider produced by f:

  • zero inputs must not panic;
  • a successful CommitView MUST carry a non-nil LastBoard (a nil board with a nil error silently fails finalization);
  • CommitView MUST NOT mutate the Request or Result it receives;
  • CommitView MUST honour ctx cancellation and return promptly.

func CommitterSuite added in v0.1.2

func CommitterSuite(t *testing.T, f CommitterFactory)

CommitterSuite runs every contract probe that applies to the agent.Committer produced by f:

  • zero inputs must not panic;
  • Commit MUST NOT mutate the Request or Result it receives;
  • Commit MUST honour ctx cancellation and return promptly.

func EngineSuite

func EngineSuite(t *testing.T, f Factory)

EngineSuite runs every contract test that applies to the engine produced by f. Engines should call this from their own *_test.go:

func TestEngineContract(t *testing.T) {
    agenttest.EngineSuite(t, func() (agent.Engine, agenttest.Capabilities) {
        return graph.NewEngine(), agenttest.Capabilities{SupportsResume: true}
    })
}

Each subtest constructs a fresh engine, so failures isolate cleanly. The whole suite must pass for an implementation to be considered agent.Engine-compliant.

func HostSuite

func HostSuite(t *testing.T, f HostFactory, caps ...HostCapabilities)

HostSuite runs every applicable contract subtest against hosts produced by f. Each subtest builds a fresh host so failures isolate cleanly.

func ObserverSuite

func ObserverSuite(t *testing.T, f ObserverFactory, caps ...ObserverCapabilities)

ObserverSuite runs every applicable contract subtest against observers produced by f.

func PreparerSuite added in v0.1.2

func PreparerSuite(t *testing.T, f PreparerFactory)

PreparerSuite runs every contract probe that applies to the agent.Preparer produced by f:

  • zero inputs must not panic;
  • a successful Before MUST return a non-nil, fresh Board (the engine mutates the returned board in place, so returning the input aliases the previous stage's state);
  • the previous board must not be mutated on the success path;
  • Before MUST honour ctx cancellation and return promptly.

func RefereeSuite

func RefereeSuite(t *testing.T, f RefereeFactory, caps ...RefereeCapabilities)

RefereeSuite runs every applicable contract subtest against deciders produced by f.

func ResumerSuite added in v0.1.2

func ResumerSuite(t *testing.T, f ResumerFactory)

ResumerSuite runs every contract probe that applies to the agent.Resumer produced by f. Resumer is the optional cheap, local-only admission probe an engine exposes ahead of resume:

  • zero / malformed checkpoints must not panic, and any returned error must be classified as Validation (wrong shape) or NotAvailable (recognised but not resumable);
  • an empty SpecVersion must never be rejected as a drift failure (the checkpoint contract says empty means "skip drift check");
  • the probe must not mutate the caller's checkpoint;
  • it must be cheap (no I/O, no LLM calls) and safe for concurrent use.

func ScriptRuntimeSuite added in v0.1.2

func ScriptRuntimeSuite(t *testing.T, f ScriptRuntimeFactory, fixture ScriptFixture)

ScriptRuntimeSuite runs every contract probe that applies to the agent.ScriptRuntime produced by f:

  • zero inputs must not panic (an error is acceptable);
  • the declared fixture must execute without an error;
  • Exec MUST be safe for concurrent use.

func StreamSinkSuite added in v0.1.2

func StreamSinkSuite(t *testing.T, f SinkFactory)

StreamSinkSuite runs every contract probe that applies to the agent.StreamSink produced by f:

  • zero-value envelopes and payloads must not panic;
  • OnDelta MUST observe ctx cancellation and return promptly;
  • implementations MUST be safe for concurrent OnDelta calls.

Types

type Capabilities

type Capabilities struct {
	// SupportsResume is true when the engine implements Run.ResumeFrom
	// (i.e. given a non-nil ResumeFrom whose ExecID matches Run.ID it
	// resumes the run rather than returning errdefs.NotAvailable).
	//
	// Engines that implement agent.Resumer with stricter CanResume
	// admission rules (e.g. graph runner requires cp.Steps to name
	// real node ids) MAY surface errdefs.Validation when the suite's
	// minimal test checkpoint fails admission; the suite accepts
	// that as a valid SupportsResume=true outcome since the engine
	// honestly rejected an unworkable resume request.
	SupportsResume bool
}

Capabilities lets an engine declare which optional behaviours it implements. The contract suite uses this to skip resume-specific subtests when the engine has SupportsResume == false (those subtests instead assert the engine returns NotAvailable).

type CommitViewFactory added in v0.1.2

type CommitViewFactory func() agent.CommitViewProvider

CommitViewFactory builds a fresh agent.CommitViewProvider for each subtest.

type CommitterFactory added in v0.1.2

type CommitterFactory func() agent.Committer

CommitterFactory builds a fresh agent.Committer for each subtest.

type Factory

type Factory func() (agent.Engine, Capabilities)

Factory builds a fresh engine and reports its capabilities. The suite calls Factory once per subtest so subtests do not share engine state.

Engines that take no construction arguments can wrap a constructor:

agenttest.EngineSuite(t, agenttest.NewFactory(graph.NewEngine))

or implement Factory directly when the construction needs more setup.

func NewFactory

func NewFactory(ctor func() agent.Engine) Factory

NewFactory adapts a parameterless constructor into a Factory that reports zero capabilities. Use Factory directly when you need to declare SupportsResume.

type HostCapabilities

type HostCapabilities struct {
	// SkipAskUserNotAvailable is true when the host is expected
	// to SUCCEED on AskUser (a real UI host with a configured
	// UserPrompter). The suite then asserts the call returns a
	// non-zero reply rather than allowing NotAvailable.
	SkipAskUserNotAvailable bool

	// SkipPublishConcurrency is true when the host's Publish
	// implementation is intentionally serial (e.g. a writer-locked
	// log shipper that must preserve order). The suite then keeps
	// Publish calls out of the concurrent phase and issues them
	// sequentially instead, so the test reflects the real
	// serial-only contract.
	SkipPublishConcurrency bool

	// AcceptsBudgetExceeded, when true, indicates the host's
	// ReportUsage MAY return an errdefs.BudgetExceeded error for
	// the suite's zero-usage probe (= unusual but legal for hosts
	// pre-configured with a zero budget). When false (default),
	// the suite asserts ReportUsage(0-usage) returns nil.
	AcceptsBudgetExceeded bool
}

HostCapabilities lets a host opt out of subtests that don't apply. Most hosts pass the zero value (= every subtest runs).

type HostFactory

type HostFactory func() agent.Host

HostFactory builds a fresh agent.Host for each subtest. The suite invokes it once per case so subtests do not share host state.

type MockHost

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

MockHost is a fully-featured agent.Host for tests. It records every interaction and lets the test inject cooperative interrupts and user replies.

It also implements the optional agent.SteerSource capability, so engine suites can drive host.drainSteer() the way a deployment's steer node would: pre-load messages with MockHost.Steer, then assert what the engine did with them.

All methods are safe for concurrent use; any number of goroutines inside the engine may call them while the test inspects state.

Zero value is NOT ready to use. Call NewMockHost which pre-allocates the channels.

func NewMockHost

func NewMockHost() *MockHost

NewMockHost returns a ready-to-use MockHost. The interrupt channel is buffered so MockHost.Interrupt never blocks the test goroutine when the engine has not yet reached its select on Interrupts().

func (*MockHost) AskUser

AskUser records the prompt and returns the configured reply, or a NotAvailable error when no reply has been set.

func (*MockHost) Checkpoint

func (h *MockHost) Checkpoint(_ context.Context, cp agent.Checkpoint) error

Checkpoint records cp and returns the configured checkpointErr.

func (*MockHost) Checkpoints

func (h *MockHost) Checkpoints() []agent.Checkpoint

Checkpoints returns a copy of every checkpoint the engine submitted.

func (*MockHost) DrainSteer added in v0.4.6

func (h *MockHost) DrainSteer() []message.Message

DrainSteer implements agent.SteerSource: it returns clones of everything queued and empties the queue, the way the real turn-owned queue does — the mock never hands out a message it still holds.

func (*MockHost) Envelopes

func (h *MockHost) Envelopes() []event.Envelope

Envelopes returns a copy of every envelope received so far.

func (*MockHost) Interrupt

func (h *MockHost) Interrupt(cause agent.Cause, detail string)

Interrupt queues an interrupt for the agent. Non-blocking: if the buffer is full the call drops the new signal silently — tests that care should call only once or assert via MockHost.Envelopes that the engine has reached its select.

func (*MockHost) Interrupts

func (h *MockHost) Interrupts() <-chan agent.Interrupt

Interrupts returns the cooperative-interrupt channel.

func (*MockHost) Prompts

func (h *MockHost) Prompts() []agent.UserPrompt

Prompts returns a copy of every UserPrompt the engine submitted.

func (*MockHost) Publish

func (h *MockHost) Publish(_ context.Context, env event.Envelope) error

Publish records the envelope and returns the configured publishErr (default nil).

func (*MockHost) ReportUsage

func (h *MockHost) ReportUsage(_ context.Context, usage inference.Usage) error

ReportUsage records the usage delta. Multiple calls are kept in order so tests can assert per-call totals; sum them with MockHost.TotalUsage when only the total matters.

func (*MockHost) SetCheckpointError

func (h *MockHost) SetCheckpointError(err error)

SetCheckpointError configures all subsequent Checkpoint calls to return err. Pass nil to clear.

func (*MockHost) SetPublishError

func (h *MockHost) SetPublishError(err error)

SetPublishError configures all subsequent Publish calls to return err. Pass nil to clear.

func (*MockHost) SetUsageError added in v0.1.2

func (h *MockHost) SetUsageError(err error)

SetUsageError configures all subsequent ReportUsage calls to return err (typically errdefs.BudgetExceeded). Pass nil to clear.

func (*MockHost) SetUserReply

func (h *MockHost) SetUserReply(reply *agent.UserReply)

SetUserReply configures what AskUser returns. Pass nil to revert to the NotAvailable default.

func (*MockHost) Steer added in v0.4.6

func (h *MockHost) Steer(msg message.Message)

Steer queues msg the way a running turn receives it from Turn.Steer. It never rejects: MockHost models delivery to the engine — admission control (bounds, terminal state, size limits) belongs to the real turn-owned queue and is tested there.

func (*MockHost) SteeredMessages added in v0.4.6

func (h *MockHost) SteeredMessages() []message.Message

SteeredMessages returns clones of the messages still queued, without draining them, so a test can assert delivery position and let the engine drain afterwards. Cloning keeps a caller that mutates the returned messages from changing what the next drain delivers.

func (*MockHost) TotalUsage

func (h *MockHost) TotalUsage() inference.Usage

TotalUsage sums every recorded usage report.

func (*MockHost) Usages

func (h *MockHost) Usages() []inference.Usage

Usages returns a copy of every usage report.

type ObserverCapabilities added in v0.1.2

type ObserverCapabilities struct {
	// SkipMutationCheck is true for observers that intentionally
	// mutate the *Request / *Result they receive. The interface
	// godoc says "MUST treat as read-only"; this knob exists only
	// for the rare migration shim that documents a deliberate
	// breach.
	SkipMutationCheck bool

	// SkipPromptReturnCheck is true for observers that legitimately
	// block (e.g. a synchronous flush observer the caller knows
	// about). The interface godoc says "blocking blocks the run",
	// so the suite enforces a 2s upper bound by default.
	SkipPromptReturnCheck bool
}

ObserverCapabilities lets observers opt out of subtests that don't apply. Most observers pass the zero value.

type ObserverFactory

type ObserverFactory func() agent.Observer

ObserverFactory builds a fresh agent.Observer for each subtest.

type PreparerFactory added in v0.1.2

type PreparerFactory func() agent.Preparer

PreparerFactory builds a fresh agent.Preparer for each subtest so subtests do not share implementation state.

type RefereeCapabilities

type RefereeCapabilities struct {
	// SkipMutationCheck is true when the decider intentionally
	// mutates *Result (extremely rare — the interface comment
	// says "MUST NOT mutate res"; this knob exists only for
	// deciders that document a deliberate breach for migration
	// purposes).
	SkipMutationCheck bool

	// SkipAllStatusProbe is true for deciders that legitimately
	// only handle a subset of statuses and panic on others. The
	// suite then skips the cross-status probe; the decider is
	// expected to ship its own focused unit tests.
	SkipAllStatusProbe bool
}

RefereeCapabilities lets a decider opt out of subtests that don't apply. Most deciders pass the zero value (= every subtest runs).

type RefereeFactory

type RefereeFactory func() agent.Referee

RefereeFactory builds a fresh agent.Referee for each subtest. The suite invokes it once per case so subtests do not share decider state.

type ResumerFactory added in v0.1.2

type ResumerFactory func() agent.Resumer

ResumerFactory builds a fresh agent.Resumer for each subtest so subtests do not share implementation state.

type ScriptFixture added in v0.1.2

type ScriptFixture struct {
	// Source is a minimal runnable script. The zero value (empty
	// source) is a valid trivial script for both bundled runtimes.
	Source string
}

ScriptFixture describes a minimal script the runtime under test must execute without any host bindings. The source is passed verbatim to agent.ScriptRuntime.Exec; the suite only requires it to complete without an error (a nil *ScriptSignal is a valid plain completion).

type ScriptRuntimeFactory added in v0.1.2

type ScriptRuntimeFactory func() agent.ScriptRuntime

ScriptRuntimeFactory builds a fresh agent.ScriptRuntime for each subtest.

type SinkFactory added in v0.1.2

type SinkFactory func() agent.StreamSink

SinkFactory builds a fresh agent.StreamSink for each subtest so subtests do not share sink state.

type SuggesterFactory added in v0.1.2

type SuggesterFactory func() agent.CheckpointSuggester

SuggesterFactory builds a fresh agent.CheckpointSuggester for each subtest.

Jump to

Keyboard shortcuts

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