Files
kandev/apps/backend/internal/mcp/handlers/get_task_conversation_test.go
T
João Salavisa c8fcd6c5aa feat(mcp): add get_task_conversation tool (#756)
* feat(mcp): add get_task_conversation tool

* fix(mcp): correct conversation pagination cursor and limits

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-05-01 18:20:01 +01:00

136 lines
4.5 KiB
Go

package handlers
import (
"context"
"encoding/json"
"testing"
"github.com/kandev/kandev/internal/task/models"
"github.com/kandev/kandev/internal/task/service"
ws "github.com/kandev/kandev/pkg/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHandleGetTaskConversation_MissingTaskID(t *testing.T) {
h := &Handlers{}
msg := makeWSMessage(t, ws.ActionMCPGetTaskConversation, map[string]interface{}{})
resp, err := h.handleGetTaskConversation(context.Background(), msg)
require.NoError(t, err)
assertWSError(t, resp, ws.ErrorCodeValidation)
}
func TestHandleGetTaskConversation_UsesPrimarySession(t *testing.T) {
svc, repo := newTestTaskService(t)
task, sess := seedTaskWithSession(t, svc, repo, models.TaskSessionStateWaitingForInput)
_, err := svc.CreateMessage(context.Background(), &service.CreateMessageRequest{
TaskSessionID: sess.ID,
TaskID: task.ID,
AuthorType: "user",
Content: "hello from task",
})
require.NoError(t, err)
h := &Handlers{taskSvc: svc, logger: testLogger(t).WithFields()}
msg := makeWSMessage(t, ws.ActionMCPGetTaskConversation, map[string]interface{}{
"task_id": task.ID,
"limit": 10,
})
resp, err := h.handleGetTaskConversation(context.Background(), msg)
require.NoError(t, err)
assert.Equal(t, ws.MessageTypeResponse, resp.Type)
var payload map[string]interface{}
require.NoError(t, json.Unmarshal(resp.Payload, &payload))
assert.Equal(t, task.ID, payload["task_id"])
assert.Equal(t, sess.ID, payload["session_id"])
assert.Equal(t, float64(1), payload["total"])
}
func TestHandleGetTaskConversation_SessionMustBelongToTask(t *testing.T) {
svc, repo := newTestTaskService(t)
taskA, _ := seedTaskWithSession(t, svc, repo, models.TaskSessionStateWaitingForInput)
// Create another task/session in the same workflow to validate cross-task mismatch.
taskB, err := svc.CreateTask(context.Background(), &service.CreateTaskRequest{
WorkspaceID: "ws-1",
WorkflowID: "wf-1",
Title: "Other task",
})
require.NoError(t, err)
sessB := &models.TaskSession{
ID: "sess-2",
TaskID: taskB.ID,
AgentProfileID: "agent-profile-1",
IsPrimary: true,
State: models.TaskSessionStateWaitingForInput,
}
require.NoError(t, repo.CreateTaskSession(context.Background(), sessB))
h := &Handlers{taskSvc: svc, logger: testLogger(t).WithFields()}
msg := makeWSMessage(t, ws.ActionMCPGetTaskConversation, map[string]interface{}{
"task_id": taskA.ID,
"session_id": "sess-2",
})
resp, err := h.handleGetTaskConversation(context.Background(), msg)
require.NoError(t, err)
assertWSError(t, resp, ws.ErrorCodeValidation)
}
func TestHandleGetTaskConversation_NegativeLimit(t *testing.T) {
svc, repo := newTestTaskService(t)
task, _ := seedTaskWithSession(t, svc, repo, models.TaskSessionStateWaitingForInput)
h := &Handlers{taskSvc: svc, logger: testLogger(t).WithFields()}
msg := makeWSMessage(t, ws.ActionMCPGetTaskConversation, map[string]interface{}{
"task_id": task.ID,
"limit": -1,
})
resp, err := h.handleGetTaskConversation(context.Background(), msg)
require.NoError(t, err)
assertWSError(t, resp, ws.ErrorCodeValidation)
}
func TestHandleGetTaskConversation_FilteredPageStillReturnsCursor(t *testing.T) {
svc, repo := newTestTaskService(t)
task, sess := seedTaskWithSession(t, svc, repo, models.TaskSessionStateWaitingForInput)
_, err := svc.CreateMessage(context.Background(), &service.CreateMessageRequest{
TaskSessionID: sess.ID,
TaskID: task.ID,
AuthorType: "agent",
Type: "tool_call",
Content: "tool call 1",
})
require.NoError(t, err)
_, err = svc.CreateMessage(context.Background(), &service.CreateMessageRequest{
TaskSessionID: sess.ID,
TaskID: task.ID,
AuthorType: "agent",
Type: "tool_call",
Content: "tool call 2",
})
require.NoError(t, err)
h := &Handlers{taskSvc: svc, logger: testLogger(t).WithFields()}
msg := makeWSMessage(t, ws.ActionMCPGetTaskConversation, map[string]interface{}{
"task_id": task.ID,
"limit": 1,
"message_types": []string{"message"},
})
resp, err := h.handleGetTaskConversation(context.Background(), msg)
require.NoError(t, err)
assert.Equal(t, ws.MessageTypeResponse, resp.Type)
var payload map[string]interface{}
require.NoError(t, json.Unmarshal(resp.Payload, &payload))
assert.Equal(t, float64(0), payload["total"])
assert.Equal(t, true, payload["has_more"])
assert.NotEmpty(t, payload["cursor"])
}