项目文件夹

文件
2026-06-28 07:09:03 +01:00

113 行
3.2 KiB
Go

package a2a
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
)
// An agent that embeds NewAgentHandler is directly A2A-queryable — no
// gateway, no registry — and the client talks to it the same way.
func TestEmbeddedAgentHandler(t *testing.T) {
card := Card("solo", "http://localhost:4000", "", []string{"task"})
h := NewAgentHandler(card, func(_ context.Context, text string) (string, error) {
return "echo:" + text, nil
})
ts := httptest.NewServer(h)
defer ts.Close()
cl := NewClient(ts.URL)
got, err := cl.Card(context.Background())
if err != nil || got.Name != "solo" {
t.Fatalf("Card() = %+v, err %v", got, err)
}
reply, err := cl.Send(context.Background(), "hi")
if err != nil || reply != "echo:hi" {
t.Fatalf("Send = %q, err %v", reply, err)
}
}
// The client fetches a card and sends a message to an agent served by the
// gateway — A2A end to end, both directions, in one process.
func TestClientSendAndCard(t *testing.T) {
ts, cleanup := newGatewayWithAgent(t)
defer cleanup()
cl := NewClient(ts.URL + "/agents/echo")
card, err := cl.Card(context.Background())
if err != nil || card.Name != "echo" {
t.Fatalf("Card() = %+v, err %v", card, err)
}
reply, err := cl.Send(context.Background(), "ping")
if err != nil {
t.Fatalf("Send: %v", err)
}
if reply != "pong" {
t.Errorf("Send reply = %q, want pong", reply)
}
}
func TestClientContinuesTaskAndConfiguresPush(t *testing.T) {
card := Card("solo", "http://localhost:4000", "", []string{"task"})
h := NewAgentHandler(card, func(_ context.Context, text string) (string, error) {
return "echo:" + text, nil
})
ts := httptest.NewServer(h)
defer ts.Close()
updates := make(chan Task, 1)
push := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var task Task
if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
t.Errorf("decode push task: %v", err)
return
}
updates <- task
w.WriteHeader(http.StatusAccepted)
}))
defer push.Close()
cl := NewClient(ts.URL)
first, err := cl.SendMessage(context.Background(), Message{
Parts: []Part{{Kind: "text", Text: "one"}},
})
if err != nil {
t.Fatalf("first SendMessage: %v", err)
}
second, err := cl.SendMessage(context.Background(), Message{
TaskID: first.ID,
ContextID: first.ContextID,
Parts: []Part{{Kind: "text", Text: "two"}},
})
if err != nil {
t.Fatalf("second SendMessage: %v", err)
}
if second.ID != first.ID || second.ContextID != first.ContextID || len(second.History) != 4 {
t.Fatalf("continued task = %+v, first %+v", second, first)
}
cfg := PushNotificationConfig{URL: push.URL}
if err := cl.SetPushNotificationConfig(context.Background(), second.ID, cfg); err != nil {
t.Fatalf("SetPushNotificationConfig: %v", err)
}
got, err := cl.PushNotificationConfig(context.Background(), second.ID)
if err != nil {
t.Fatalf("PushNotificationConfig: %v", err)
}
if got.URL != push.URL {
t.Fatalf("PushNotificationConfig URL = %q, want %q", got.URL, push.URL)
}
select {
case update := <-updates:
if update.ID != second.ID {
t.Fatalf("push update ID = %q, want %q", update.ID, second.ID)
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for push update")
}
}