package tools import ( "context" "encoding/json" "testing" "github.com/modelcontextprotocol/go-sdk/mcp" "isphere-ai-bridge/internal/isphere" ) func TestISphereReceiveMessagesToolReturnsSourceMessages(t *testing.T) { fake := &fakeReceiveMessagesSource{ result: isphere.ReceiveMessagesResult{Messages: []isphere.Message{{ ID: "msg-1", ConversationID: "sender@imopenfire1-lanzhou|receiver@imopenfire1-lanzhou", ConversationType: "chat", SenderID: "sender@imopenfire1-lanzhou", ReceiverID: "receiver@imopenfire1-lanzhou", Text: "redacted", Timestamp: "1783423807000", Subject: "FILE_TRANSFER_CANCEL", ReceiptID: "receipt-1", Read: true, }}}, } session, cleanup := connectToolsTestSession(t, func(server *mcp.Server) { RegisterISphereReadTools(server, fake) }) defer cleanup() listResult, err := session.ListTools(context.Background(), &mcp.ListToolsParams{}) if err != nil { t.Fatalf("list tools: %v", err) } gotNames := make([]string, 0, len(listResult.Tools)) for _, tool := range listResult.Tools { gotNames = append(gotNames, tool.Name) } assertSameStrings(t, gotNames, []string{ToolNameReceiveMessages}) callResult, err := session.CallTool(context.Background(), &mcp.CallToolParams{ Name: ToolNameReceiveMessages, Arguments: map[string]any{"limit": 5}, }) if err != nil { t.Fatalf("call %s: %v", ToolNameReceiveMessages, err) } if callResult.IsError { t.Fatalf("call result is error: %+v", callResult) } if len(fake.queries) != 1 || fake.queries[0].Limit != 5 { t.Fatalf("queries = %+v, want one limit=5", fake.queries) } var decoded struct { Messages []struct { ID string `json:"id"` ConversationID string `json:"conversation_id"` ConversationType string `json:"conversation_type"` SenderID string `json:"sender_id"` ReceiverID string `json:"receiver_id"` Text string `json:"text"` Timestamp string `json:"timestamp"` Subject string `json:"subject"` ReceiptID string `json:"receipt_id"` Read bool `json:"read"` } `json:"messages"` } payload, err := json.Marshal(callResult.StructuredContent) if err != nil { t.Fatalf("marshal structured content: %v", err) } if err := json.Unmarshal(payload, &decoded); err != nil { t.Fatalf("decode structured content %s: %v", payload, err) } if len(decoded.Messages) != 1 { t.Fatalf("messages = %+v, want one", decoded.Messages) } msg := decoded.Messages[0] if msg.ID != "msg-1" || msg.Text != "redacted" || msg.Subject != "FILE_TRANSFER_CANCEL" { t.Fatalf("unexpected message content: %+v", msg) } if msg.ConversationID != "sender@imopenfire1-lanzhou|receiver@imopenfire1-lanzhou" { t.Fatalf("conversation_id = %q", msg.ConversationID) } if msg.SenderID != "sender@imopenfire1-lanzhou" || msg.ReceiverID != "receiver@imopenfire1-lanzhou" { t.Fatalf("sender/receiver = %q/%q", msg.SenderID, msg.ReceiverID) } if msg.Timestamp != "1783423807000" || msg.ReceiptID != "receipt-1" || !msg.Read { t.Fatalf("metadata = %+v", msg) } } type fakeReceiveMessagesSource struct { queries []isphere.ReceiveMessagesQuery result isphere.ReceiveMessagesResult } func (f *fakeReceiveMessagesSource) ReceiveMessages(_ context.Context, query isphere.ReceiveMessagesQuery) (isphere.ReceiveMessagesResult, error) { f.queries = append(f.queries, query) return f.result, nil }