Files
Agent-System-Backend/internal/tools/http_test.go
T
weichen 2c5c68d16c Add layered cross-session reading with gated peer tools
Why: conversation transcripts were the only project channel not
readable across sessions (artifacts/knowledge are already shared),
which caused duplicate parallel work; see proposal
2026-09-30-cross-session-reading.

Evidence: runmgr/crossread_test.go covers the full gate matrix
(project gate on/off x outbound flag x private target x cross-project
x cross-tenant x self-read x archived x limit clamping) against a real
store + settings chain; store tests cover migration v11, flag
persistence and tenant isolation; tools/peers_test.go covers args
validation, transcript rendering and the untrusted-content banner;
go test ./... green.

Impact: setting crossSession.read (default off, schema-driven);
conversation columns allow_cross_read (default true) and cross_private
(default false) with PATCH support; builtin tools list_conversations
and read_conversation gated fail-closed in runmgr toolCtx; nested
agent-system-core pin bumped to fd44179 (Core PR #6).

Refs: Agent-System-Documents proposals/2026-09-30-cross-session-reading.md
(Dev task feature/cross-session-reading).
2026-09-30 15:13:36 +00:00

73 lines
2.2 KiB
Go

package tools
import (
"net/http"
"net/http/httptest"
"testing"
core "agent-system-core"
)
type dummyCtx struct{ project string }
func (dummyCtx) ProjectID() string { return "" }
func (dummyCtx) ConversationID() string { return "" }
func (dummyCtx) Retrieve(q core.RetrievalQuery) ([]core.RetrievalHit, error) { return nil, nil }
func (dummyCtx) WriteArtifact(name, kind, mime string, content []byte) (core.Artifact, error) {
return core.Artifact{}, nil
}
func (dummyCtx) PeerConversations() ([]core.Conversation, error) { return nil, nil }
func (dummyCtx) PeerConversationMessages(id string, limit int) ([]core.Message, error) {
return nil, nil
}
// TestHTTPExecutorTemplateAndPath:模板变量注入、结果路径裁剪、错误状态。
func TestHTTPExecutorTemplateAndPath(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/translate" {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"data":[{"translated":"hello","src":"你好"}],"meta":{"n":1}}`))
}))
defer srv.Close()
spec := core.HTTPToolSpec{
Method: "POST", URL: srv.URL + "/translate",
BodyTemplate: `{"q":"{{param.text}}"}`, ResultPath: "data.0.translated",
}
exec := HTTPExecutor(spec, nil)
out, err := exec(dummyCtx{}, []byte(`{"text":"你好"}`))
if err != nil {
t.Fatal(err)
}
if out != `"hello"` && out != "hello" {
t.Errorf("result: %q", out)
}
// ResultPath 不存在 → 显式错误。
specBad := spec
specBad.ResultPath = "missing.path"
if _, err := HTTPExecutor(specBad, nil)(dummyCtx{}, []byte(`{}`)); err == nil {
t.Error("missing path should error")
}
// 404 → 错误带状态码。
spec404 := spec
spec404.URL = srv.URL + "/nope"
spec404.ResultPath = ""
if _, err := HTTPExecutor(spec404, nil)(dummyCtx{}, nil); err == nil {
t.Error("404 should error")
}
}
func TestExpandTemplate(t *testing.T) {
got := expandTemplate(`{{param.a}}/{{param.b.c}}/{{param.unknown}}`, map[string]any{
"a": "x", "b": map[string]any{"c": "y"},
})
if got != "x/y/" {
t.Errorf("expand: %q", got)
}
}