Contract codes now use the agent.* values, and runtime can emit structured logs without changing results when no logger is configured. Co-authored-by: Cursor <cursoragent@cursor.com>
64 lines
1.7 KiB
Go
64 lines
1.7 KiB
Go
package contract_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"agent-native/conformance"
|
|
"agent-native/contract"
|
|
)
|
|
|
|
// 契约自测:fake 后端通过最小套件,验证套件本身与类型语义一致。
|
|
func TestFakeBackendSuite(t *testing.T) {
|
|
conformance.Suite(t, func() contract.Backend {
|
|
return &conformance.FakeBackend{
|
|
Desc: contract.BackendDescriptor{
|
|
Name: "fake",
|
|
Capabilities: []contract.Capability{contract.CapText},
|
|
},
|
|
Result: contract.Result{
|
|
Outcome: contract.OutcomeSucceeded,
|
|
Text: "ok",
|
|
},
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFakeCancelSemantics(t *testing.T) {
|
|
block := make(chan struct{})
|
|
b := &conformance.FakeBackend{
|
|
Desc: contract.BackendDescriptor{Name: "fake", Capabilities: []contract.Capability{contract.CapCancel}},
|
|
BlockUntil: block,
|
|
}
|
|
conformance.Run(t, conformance.Case{
|
|
Name: "cancel",
|
|
Backend: b,
|
|
Request: contract.Request{ExecutionID: "e-cancel"},
|
|
CancelAfter: 50_000_000, // 50ms in ns (avoid time import here)
|
|
WantOutcome: contract.OutcomeCanceled,
|
|
WantErrCode: contract.ErrCanceled,
|
|
})
|
|
if !b.CanceledWithCtx {
|
|
t.Fatal("backend must observe ctx cancellation before returning")
|
|
}
|
|
}
|
|
|
|
func TestErrorDuckTypeForLogs(t *testing.T) {
|
|
e := &contract.Error{
|
|
Code: contract.ErrProviderUnavailable,
|
|
Reason: "down",
|
|
Retryable: true,
|
|
SideEffects: contract.SideEffectNone,
|
|
}
|
|
if e.ErrorCode() != "agent.provider_unavailable" {
|
|
t.Fatal(e.ErrorCode())
|
|
}
|
|
fields := e.ErrorFields()
|
|
if fields["reason"] != "down" || fields["side_effects"] != "none" || fields["retryable"] != true {
|
|
t.Fatalf("%v", fields)
|
|
}
|
|
var nilErr *contract.Error
|
|
if nilErr.ErrorCode() != "" || nilErr.ErrorFields() != nil {
|
|
t.Fatal("nil error")
|
|
}
|
|
}
|