Files
agentic-coding-workflow/internal/acp/relay_discovery_test.go
T
2026-06-22 08:55:57 +08:00

108 lines
3.1 KiB
Go

// relay_discovery_test.go: relay dispatch tests for the fs/list + fs/grep agent
// discovery handlers (mirrors TestRelay_AgentFsRequest_Echoed).
package acp_test
import (
"encoding/json"
"errors"
"io"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/yan1h/agent-coding-workflow/internal/acp"
)
func relayRoundTrip(t *testing.T, rig *relayTestRig, id int64, method string, params map[string]any) *acp.Message {
t.Helper()
agentDec := acp.NewDecoder(rig.agentReader, 0)
agentEnc := acp.NewEncoder(rig.agentWriter)
req, err := acp.NewRequestInt(id, method, params)
require.NoError(t, err)
require.NoError(t, agentEnc.Encode(req))
respCh := make(chan *acp.Message, 1)
errCh := make(chan error, 1)
go func() {
m, derr := agentDec.DecodeMessage()
if derr != nil {
errCh <- derr
return
}
respCh <- m
}()
select {
case resp := <-respCh:
return resp
case err := <-errCh:
if errors.Is(err, io.EOF) {
t.Fatal("agent saw EOF before relay responded")
}
t.Fatalf("agent decoder error: %v", err)
case <-time.After(3 * time.Second):
t.Fatalf("relay did not respond to %s within 3s", method)
}
return nil
}
func TestRelay_AgentFsList_Dispatched(t *testing.T) {
t.Parallel()
rig := newRelayTestRig(t)
cancel, doneCh := rig.runRelay(t)
t.Cleanup(func() { rig.shutdown(t, cancel, doneCh) })
require.NoError(t, os.WriteFile(filepath.Join(rig.sess.CwdPath, "f.txt"), []byte("hi"), 0o644))
resp := relayRoundTrip(t, rig, 201, "fs/list", map[string]any{"path": ".", "sessionId": "a"})
require.True(t, resp.IsResponse())
require.Nil(t, resp.Error)
var out struct {
Entries []struct {
Name string `json:"name"`
} `json:"entries"`
}
require.NoError(t, json.Unmarshal(resp.Result, &out))
require.Len(t, out.Entries, 1)
assert.Equal(t, "f.txt", out.Entries[0].Name)
}
func TestRelay_AgentFsGrep_Dispatched(t *testing.T) {
t.Parallel()
rig := newRelayTestRig(t)
cancel, doneCh := rig.runRelay(t)
t.Cleanup(func() { rig.shutdown(t, cancel, doneCh) })
require.NoError(t, os.WriteFile(filepath.Join(rig.sess.CwdPath, "code.go"), []byte("package x\nfunc Needle() {}\n"), 0o644))
resp := relayRoundTrip(t, rig, 202, "fs/grep", map[string]any{"pattern": "Needle", "sessionId": "a"})
require.True(t, resp.IsResponse())
require.Nil(t, resp.Error)
var out struct {
Matches []struct {
File string `json:"file"`
Line int `json:"line"`
} `json:"matches"`
}
require.NoError(t, json.Unmarshal(resp.Result, &out))
require.Len(t, out.Matches, 1)
assert.Equal(t, "code.go", out.Matches[0].File)
assert.Equal(t, 2, out.Matches[0].Line)
}
func TestRelay_AgentFsGrep_PathEscapeRejected(t *testing.T) {
t.Parallel()
rig := newRelayTestRig(t)
cancel, doneCh := rig.runRelay(t)
t.Cleanup(func() { rig.shutdown(t, cancel, doneCh) })
outside := filepath.Join(filepath.VolumeName(rig.sess.CwdPath)+string(filepath.Separator), "etc")
resp := relayRoundTrip(t, rig, 203, "fs/grep", map[string]any{"pattern": "x", "path": outside, "sessionId": "a"})
require.True(t, resp.IsResponse())
require.NotNil(t, resp.Error)
assert.Equal(t, -32001, resp.Error.Code)
}