You've already forked agentic-coding-workflow
108 lines
3.1 KiB
Go
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)
|
|
}
|