adaptertest

package
v1.1.2 Latest Latest
Warning

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

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

Documentation

Overview

Package adaptertest is the conformance suite for the driver SPI. It verifies implementations of driver.Driver directly and has no dependency on the root package's consumer API.

Usage follows the fstest.TestFS / nettest.TestConn idiom:

func TestMyDriverConformance(t *testing.T) {
	adaptertest.TestDriver(t, func() driver.Driver {
		return mydriver.Driver(mydriver.Config{Model: "m-1"})
	},
		adaptertest.WithConfig(mydriver.Config{Model: "m-1"}),
		adaptertest.WithSessionState(&driver.SessionState{...}),
		adaptertest.WithGuardKeys("cwd"),
	)
}

Probes for the optional capability interfaces skip when an interface is not implemented, and the suite never exercises a capability the Descriptor does not declare. NewReferenceDriver returns a fully compliant in-memory implementation that doubles as the suite's self-proof and as a template for driver authors.

Contract clause catalogue

Every failure message carries one of the numbered clauses below. The authority for each clause is the godoc in package driver (file noted per group); clauses marked (opt-in) run only when the corresponding Option is passed, and clauses marked (live) require WithLiveRun.

Core driver and config (driver/driver.go: Driver, Descriptor):

DRV-01  Descriptor().Type and DisplayName are non-empty.
DRV-02  Descriptor() is deterministic across calls and across factory
        instances (the descriptor is a static declaration).
CFG-01  ValidateConfig(nil) must not panic.
CFG-02  ValidateConfig accepts the suite-supplied config.
CFG-03  (opt-in, ExpectRejectForeignConfig) ValidateConfig rejects a
        config value of an unknown type.

Capability-declaration truthfulness (driver/driver.go capability interfaces; driver/environment.go report types):

CAP-01  Sessions.SupportsResume is true iff SessionCodecProvider returns
        a non-nil, stable codec; resume-capable Drivers also implement
        SessionConfigFingerprinter with a stable, non-empty result.
CAP-02  Skills.Supported implies SkillSupport and a declared Mode of
        ephemeral|persistent; unsupported skills must not declare a mode.
CAP-03  CheckEnvironment succeeds hermetically; DriverType matches the
        descriptor; Status is pass|warn|fail; pass implies Healthy;
        checks carry stable Codes.
CAP-04  ListModels succeeds hermetically; every ModelInfo.ID non-empty.
CAP-05  DetectModel succeeds hermetically; a non-nil result carries a
        non-empty Model (and matches WithExpectedDetectedModel).
CAP-06  GetProfile: DriverType matches; Supported implies non-empty Dir
        and Source.
CAP-07  GetQuota succeeds hermetically; DriverType matches; window
        labels non-empty.
CAP-08  ConfigSchema succeeds; field names non-empty and unique;
        contains WithRequiredConfigFields.
CAP-09  SkillSupport echo laws on the empty catalogue: Supported=true,
        DriverType matches, valid Mode, Selected mirrors the (empty)
        selection. SyncSkills half is opt-in (WithSyncSkillsProbe).
CAP-10  StreamCapability() is deterministic.
CAP-11  Process.Persistent implies ProcessLifecycleDriver, so Agent.Close
        can reap every process owned by the configured Driver.

Structured output (driver/driver.go StructuredOutputCapability, driver/output.go; engine resolution in internal/engine/structured.go):

SO-01  WorksWith* flags require a declared JSONSchema* mechanism, and a
       declared mechanism requires WorksWithRun for v1's one execution
       pipeline. Core selects native enforcement first and Prompt
       validation as the fallback. Provider streaming and effective HITL
       Ask additionally require WorksWithStreaming and WorksWithHITL.
SO-02  (live, opt-in) a native structured run yields StructuredOutput with
       Source=native, Valid=true and parseable RawJSON.
SO-03  Suite guarantee: no probe requests a mechanism or transport shape
       the descriptor does not declare.

Session codec (driver/session_codec.go; driver/run.go SessionState):

SES-01  Name() is non-empty and stable.
SES-02  ToParams(nil) is the zero SessionParams; FromParams(zero) is nil.
SES-03  ToParams preserves ResumeID and all Data entries; DisplayID is
        non-empty for a resumable state.
SES-04  params -> FromParams -> ToParams is lossless (DeepEqual).
SES-05  GuardFingerprint is non-empty and deterministic.
SES-06  (opt-in, WithGuardKeys) mutating a guard value changes the
        fingerprint (resume-guard doctrine in the SessionCodec godoc).
SES-07  nil/zero codec inputs never panic.
SES-08  (opt-in, WithSessionKeys) required keys survive the round-trip.
SES-09  Resume and persistent-process guards use
        ProfilePayload.SessionFingerprint(); exact Fingerprint and payload
        remain authoritative for current-invocation materialization.

Stream event timing (live; driver/events.go StreamKind, StreamPayload field-usage table, Role; driver/driver.go EventSink):

EVT-01  run.started is emitted exactly once and before every other payload,
        including vendor extensions and provider-side drop reports.
EVT-02  exactly one run.finished or run.error is emitted, it is last,
        and run.error carries Error.
EVT-03  text lifecycles: MessageID required, opened once by text.start,
        content/end only while open.
EVT-04  text.content carries a non-empty Delta.
EVT-05  tool_call lifecycles: start requires ToolCallID+Name; args
        require an open lifecycle and non-empty Delta; end/result
        require a known ToolCallID.
EVT-06  reasoning lifecycles mirror EVT-03/EVT-04.
EVT-07  step.started / step.finished require Name.
EVT-08  hitl.requested / hitl.resolved carry their decision envelopes.
EVT-09  Role is left at the zero value on every driver-emitted payload.
EVT-10  Sequence, Seq, and Timestamp are left zero by drivers (the SDK
        backfills them in EmitStream).
EVT-11  every opened lifecycle is closed before run.finished.
EVT-12  StreamCapability negatives hold: no tool_call.args when
        ToolCallArgs=false, no reasoning.* when Reasoning=false, no
        hitl.* when HITL=false.
EVT-13  run.* frames leave MessageID and ToolCallID empty.

Vendor-specific StreamKinds and RunEventTypes outside the declared enums are tolerated for field validation, but no payload may follow a terminal.

RunEvent envelope and transcript (live; driver/events.go RunEvent, TranscriptItem):

RUN-01  chunk events carry Stream "stdout"|"stderr".
RUN-02  item events carry a non-nil Item obeying the TRN rules.
RUN-03  drivers leave RunEvent.Seq zero (SDK-assigned).
RUN-04  the RunEventItem sequence exactly mirrors Response.Transcript.
TRN-01  text-bearing kinds (assistant/thinking/user/stdout/stderr/
        system/summary/question/failure) require Text.
TRN-02  tool_call requires ToolName.
TRN-03  tool_result requires ToolUseID.
TRN-04  Delta is allowed on assistant and thinking only.

Response invariants (live; driver/run.go):

RSP-01  Checkpoint.Valid=true requires State with a ResumeID and a clean
        outcome (Driver.Run error nil, exit 0, no signal/timeout/Failure).
RSP-02  Failure.HumanDecision is non-nil exactly when Code is
        decision_rejected or decision_timeout.
RSP-03  Output is never the raw protocol-shaped stdout dump.
RSP-04  a valid checkpoint round-trips through the session codec with
        its ResumeID and a non-empty guard fingerprint.
RSP-05  when a provider exposes terminal JSON, RawStreams.Terminal carries
        its non-empty official event name and valid exact JSON payload.

These clauses are normative. The driver package states the lifecycle, codec-empty mapping, core-owned sequence, transcript mirror, resume-codec, checkpoint, structured-output transport and HumanDecision requirements as MUST rules; this suite does not offer lenient/advisory escape hatches.

Index

Constants

View Source
const DefaultLivePrompt = "Reply with exactly: OK"

DefaultLivePrompt is used by WithLiveRun("").

Variables

This section is empty.

Functions

func NewReferenceDriver

func NewReferenceDriver(cfg ReferenceConfig) driver.Driver

NewReferenceDriver returns the suite's reference driver.Driver: a fully in-memory implementation that satisfies every clause TestDriver enforces and implements all optional capability interfaces. It is both the suite's self-proof (see the package tests) and a template for third-party driver authors — every emission below is annotated with the clause it upholds.

func TestDriver

func TestDriver(t *testing.T, newDriver func() driver.Driver, opts ...Option)

TestDriver runs the v1 driver conformance suite against drivers produced by newDriver, in the style of fstest.TestFS / nettest.TestConn. Probes for optional capability interfaces skip when the driver does not implement them; capability declarations in the Descriptor are cross-checked against the implemented interfaces (truthfulness), and the suite never probes a capability the descriptor does not declare. Failure messages carry the numbered contract clauses catalogued in the package documentation.

Types

type Option

type Option func(*suiteConfig)

Option configures TestDriver.

func ExpectRejectForeignConfig

func ExpectRejectForeignConfig() Option

ExpectRejectForeignConfig asserts that ValidateConfig rejects a config value of a type the driver has never seen (CFG-03). All built-in drivers satisfy this; it is opt-in because the SPI does not mandate it.

func SkipLiveRun

func SkipLiveRun(reason string) Option

SkipLiveRun records why the live probes are skipped (for example "codex CLI not in PATH") and wins over WithLiveRun.

func WithConfig

func WithConfig(cfg any) Option

WithConfig supplies the driver-specific config value passed to every probe (ValidateConfig, CheckEnvironment, ListModels, ...) and to live runs via Request.Config. v1 drivers built with <pkg>.Driver(cfg) may receive nil here; they inject their captured config themselves.

func WithExpectedDetectedModel

func WithExpectedDetectedModel(model string) Option

WithExpectedDetectedModel asserts the ModelDetector result (CAP-05).

func WithGuardKeys

func WithGuardKeys(keys ...string) Option

WithGuardKeys lists session parameter keys that participate in the codec's GuardFingerprint; mutating any of them must change the fingerprint (SES-06). Without this option SES-06 is skipped, because which keys are guard-relevant is driver-specific.

func WithLiveRun

func WithLiveRun(prompt string) Option

WithLiveRun enables the live execution probes (EVT-*, RUN-*, TRN-*, RSP-*): the suite invokes Run against the real provider with prompt. An empty prompt selects DefaultLivePrompt. Callers gate this on CLI availability; see SkipLiveRun.

func WithLiveRunTimeout

func WithLiveRunTimeout(d time.Duration) Option

WithLiveRunTimeout overrides the live run deadline (default 5 minutes).

func WithLiveStructuredOutput

func WithLiveStructuredOutput() Option

WithLiveStructuredOutput additionally runs the native structured-output probe (SO-02) when the descriptor declares JSONSchemaNative for Run. The suite never requests a mechanism the descriptor does not declare (SO-03).

func WithRequiredConfigFields

func WithRequiredConfigFields(names ...string) Option

WithRequiredConfigFields asserts that the hydrated ConfigSchema contains these field names (CAP-08).

func WithSessionKeys

func WithSessionKeys(keys ...string) Option

WithSessionKeys lists SessionState.Data keys that must survive the codec round-trip (SES-08). Keys must be present in the seeded session state.

func WithSessionState

func WithSessionState(state *driver.SessionState) Option

WithSessionState seeds the session-codec round-trip probes (SES-*). When omitted the suite uses a generic resumable state.

func WithSyncSkillsProbe

func WithSyncSkillsProbe() Option

WithSyncSkillsProbe additionally exercises SyncSkills with the empty catalogue (CAP-09). Opt-in because SyncSkills reconciles host-side state and may write into the driver profile directory.

func WithWorkspace

func WithWorkspace(cwd string) Option

WithWorkspace sets the workspace CWD used for live runs.

type RecordingSink

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

RecordingSink is a concurrency-safe driver.EventSink that records every RunEvent and StreamPayload exactly as the driver emitted them. Unlike the SDK's production sink it performs no Sequence/Seq/Timestamp backfill, so the verifiers can check the driver-side halves of the contract (EVT-10, RUN-03: drivers leave those fields zero).

func NewRecordingSink

func NewRecordingSink() *RecordingSink

NewRecordingSink returns an empty RecordingSink.

func (*RecordingSink) Emit

func (s *RecordingSink) Emit(event driver.RunEvent) error

Emit records event and never fails.

func (*RecordingSink) EmitStream

func (s *RecordingSink) EmitStream(payload driver.StreamPayload) error

EmitStream records payload and never fails.

func (*RecordingSink) Events

func (s *RecordingSink) Events() []driver.RunEvent

Events returns a copy of the recorded RunEvents in emission order.

func (*RecordingSink) Stream

func (s *RecordingSink) Stream() []driver.StreamPayload

Stream returns a copy of the recorded StreamPayloads in emission order.

type ReferenceConfig

type ReferenceConfig struct {
	// Model is the configured model; defaults to "reference-1".
	Model string
	// CWD is the fallback working directory when the request carries no
	// workspace lease.
	CWD string
	// FailRun makes Run report a provider-level failure (FailureAgentError
	// plus a run.error terminal frame) instead of a successful run.
	FailRun bool
}

ReferenceConfig configures the in-memory reference driver returned by NewReferenceDriver.

type Violation

type Violation struct {
	Clause  string
	Message string
}

Violation is one contract breach detected by a verifier. Clause is the numbered contract rule from the catalogue in the package documentation; each clause cites the driver-package godoc it is grounded in.

func VerifyCheckpointCodec

func VerifyCheckpointCodec(d driver.Driver, resp *driver.Response) (out []Violation)

VerifyCheckpointCodec checks RSP-04 without running a paid/live probe. A valid checkpoint is meaningful only when the same Driver exposes a codec that accepts its resume identity and derives a non-empty guard.

func VerifyOutcome

func VerifyOutcome(resp *driver.Response, runErr error) []Violation

VerifyOutcome checks Response-level structural invariants (clauses RSP-01 .. RSP-03 plus TRN-* for the transcript) together with the error returned by Driver.Run. A non-nil runErr makes a valid checkpoint unsafe even when the Response's process fields happen to look successful.

func VerifyProcessCapability

func VerifyProcessCapability(d driver.Driver) []Violation

VerifyProcessCapability checks that a Driver advertising a persistent process also exposes the lifecycle hook Agent.Close needs to reap it.

func VerifyResponse

func VerifyResponse(resp *driver.Response) []Violation

VerifyResponse checks the invariants observable from Response alone. Use VerifyOutcome when the Driver.Run error is available.

func VerifyRunEvents

func VerifyRunEvents(events []driver.RunEvent) []Violation

VerifyRunEvents checks the driver-side RunEvent envelope contract (clauses RUN-01 .. RUN-03; TRN-* for embedded transcript items) against events exactly as the driver emitted them.

func VerifySessionCapability

func VerifySessionCapability(d driver.Driver) (out []Violation)

VerifySessionCapability checks the declaration and support-interface half of CAP-01 without starting a provider process. Resume support requires both a stable, non-nil SessionCodec and a stable, non-empty construction-config fingerprint; Thread correctness depends on both identities.

func VerifyStreamCapability

func VerifyStreamCapability(capability driver.StreamCapability, payloads []driver.StreamPayload) []Violation

VerifyStreamCapability cross-checks a driver's declared StreamCapability against the payloads it actually emitted (clause EVT-12). Only negative declarations are enforced: a false capability flag means the corresponding kinds must not appear (StreamCapability docs: every field is additive).

func VerifyStreamSequence

func VerifyStreamSequence(payloads []driver.StreamPayload) []Violation

VerifyStreamSequence checks the driver-side stream event timing contract (clauses EVT-01 .. EVT-11, EVT-13) against payloads exactly as the driver emitted them (before SDK Sequence/Timestamp backfill). The authority for each clause is the godoc in package driver (StreamKind, StreamPayload, Role, EventSink); see the package documentation for the catalogue.

func VerifyStructuredOutputCapability

func VerifyStructuredOutputCapability(capability driver.StructuredOutputCapability) []Violation

VerifyStructuredOutputCapability checks the declaration half of the structured-output matrix (SO-01). The optional live probe verifies the native, non-streaming baseline; core's structured contract tests own automatic selection and rejection across provider-streaming and HITL.

func VerifyTranscript

func VerifyTranscript(items []driver.TranscriptItem) []Violation

VerifyTranscript checks TranscriptItem kind field rules (clauses TRN-01 .. TRN-04) for a full transcript slice.

func VerifyTranscriptMirror

func VerifyTranscriptMirror(events []driver.RunEvent, transcript []driver.TranscriptItem) []Violation

VerifyTranscriptMirror checks the hard SPI invariant that collecting every driver-emitted RunEventItem in emission order exactly reproduces Response.Transcript. Streaming deltas participate when and only when the driver also includes them in the final Transcript.

func (Violation) String

func (v Violation) String() string

Jump to

Keyboard shortcuts

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