Files
Agent-Native/conformance/fake.go
T
weichenandCursor 4a10818535 Drop the intent adapter and fold contract into exec
Why: native must compile without agent-intent, and the two execution packages were the same contract under two names.
Evidence: GOWORK=off go test -count=1 ./... passed, including schema.TestRequestAndResultRoundTrip and the native adapter tests after Options was split into embedded sub-structs.
Impact: adapters/intentgate is gone, go.mod no longer requires agent-intent, and the nested gitlink stays for the release task. Callers of Options composite literals name the sub-struct.
Refs: D1
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 13:31:48 +00:00

148 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package conformance 提供所有 Backend 实现共用的行为验收套件。
//
// 用法:实现方在自己的测试中调用 conformance.Run(t, backend, conformance.Case{...})。
// fake 后端用于契约自测;真实实现(runtime、PI adapter)必须通过同一套件,
// fake 通过不等于真实适配完成(分别记证据)。
package conformance
import (
"context"
"fmt"
"testing"
"time"
"agent-native/exec"
)
// FakeBackend 是确定性假实现,仅用于契约套件自测与消费方单测。
// 不模拟任何模型行为;按 Script 逐项返回。
type FakeBackend struct {
Desc exec.BackendDescriptor
// Result 为每次 Execute 返回的终态(浅拷贝后返回)。
Result exec.ContractResult
// BlockUntil 若非 nil,Execute 阻塞直到该 channel 关闭或 ctx 取消,
// 用于验证取消语义。
BlockUntil <-chan struct{}
// CanceledWithCtx 记录 Execute 返回时 ctx 是否已取消。
CanceledWithCtx bool
// LastRequest 记录最近一次请求。
LastRequest exec.ContractRequest
}
func (f *FakeBackend) Descriptor() exec.BackendDescriptor { return f.Desc }
func (f *FakeBackend) Execute(ctx context.Context, req exec.ContractRequest) (*exec.ContractResult, error) {
f.LastRequest = req
if f.BlockUntil != nil {
select {
case <-f.BlockUntil:
case <-ctx.Done():
f.CanceledWithCtx = true
res := *(&f.Result)
res.Outcome = exec.OutcomeCanceled
res.Err = &exec.Error{
Code: exec.ErrCanceled,
SideEffects: exec.SideEffectNone,
}
return &res, nil
}
}
res := f.Result
return &res, nil
}
// Case 是一条契约验收用例。
type Case struct {
Name string
// Backend 为被测实现。
Backend exec.ContractBackend
// Request 为请求模板。
Request exec.ContractRequest
// CancelAfter 若非零,在等待该时长后取消 ctx(验证取消路径)。
CancelAfter time.Duration
// WantOutcome 为期望终态。
WantOutcome exec.Outcome
// WantErrCode 为期望错误码(Failed/Canceled/Unknown 时)。
WantErrCode exec.ErrorCode
}
// Run 执行一条契约用例。
func Run(t *testing.T, c Case) {
t.Helper()
ctx := context.Background()
var cancel context.CancelFunc
if c.CancelAfter > 0 {
ctx, cancel = context.WithTimeout(ctx, c.CancelAfter)
defer cancel()
}
res, err := c.Backend.Execute(ctx, c.Request)
if err != nil {
t.Fatalf("[%s] Execute returned transport error %v; business outcomes must be in Result", c.Name, err)
}
if res == nil {
t.Fatalf("[%s] Execute returned nil Result", c.Name)
}
if res.Outcome != c.WantOutcome {
t.Fatalf("[%s] Outcome = %q, want %q", c.Name, res.Outcome, c.WantOutcome)
}
if c.WantErrCode != "" {
if res.Err == nil {
t.Fatalf("[%s] expected error code %q, got nil Err", c.Name, c.WantErrCode)
}
if res.Err.Code != c.WantErrCode {
t.Fatalf("[%s] Err.Code = %q, want %q", c.Name, res.Err.Code, c.WantErrCode)
}
if res.Err.SideEffects == "" {
t.Fatalf("[%s] Err.SideEffects must be explicit (none|possible), got empty", c.Name)
}
}
if res.Outcome == exec.OutcomeSucceeded && res.Err != nil {
t.Fatalf("[%s] Succeeded result must not carry Err", c.Name)
}
}
// Suite 是最小契约套件:成功、失败带副作用标记、取消三态。
// 每个真实 Backend 实现都必须通过;套件外按实现能力补充专项用例。
func Suite(t *testing.T, mk func() exec.ContractBackend) {
t.Helper()
t.Run("succeeded_minimal", func(t *testing.T) {
b := mk()
Run(t, Case{
Name: "succeeded",
Backend: b,
Request: exec.ContractRequest{ExecutionID: "e1", Prompt: "hi"},
WantOutcome: exec.OutcomeSucceeded,
})
})
t.Run("descriptor_has_name", func(t *testing.T) {
b := mk()
d := b.Descriptor()
if d.Name == "" {
t.Fatal("Descriptor().Name must not be empty")
}
if len(d.Capabilities) == 0 {
t.Fatal("Descriptor().Capabilities must declare at least one capability")
}
})
t.Run("error_sideeffects_explicit", func(t *testing.T) {
b := mk()
// 通过描述能力判定是否有失败路径可测;无失败路径的实现跳过。
if !b.Descriptor().Has(exec.CapText) && !b.Descriptor().Has(exec.CapFiles) {
t.Skip("no text/files capability to force failure path")
}
// 空提示在多数实现下是确定性失败或成功空输出;仅验证当 Outcome=Failed
// 时错误字段完整。具体实现应补充自身失败注入用例。
res, _ := b.Execute(context.Background(), exec.ContractRequest{ExecutionID: "e2"})
if res != nil && res.Outcome == exec.OutcomeFailed {
if res.Err == nil || res.Err.Code == "" || res.Err.SideEffects == "" {
t.Fatalf("failed result must carry Code and SideEffects, got %+v", res.Err)
}
}
})
_ = fmt.Sprint() // keep fmt import stable for future diagnostics
}