You've already forked agentic-coding-workflow
157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
package acp_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/yan1h/agent-coding-workflow/internal/acp"
|
|
)
|
|
|
|
func TestJSONRPC_RoundtripRequestNumberID(t *testing.T) {
|
|
t.Parallel()
|
|
req, err := acp.NewRequestInt(42, "session/prompt", map[string]any{"text": "hi"})
|
|
require.NoError(t, err)
|
|
|
|
var buf bytes.Buffer
|
|
require.NoError(t, acp.NewEncoder(&buf).Encode(req))
|
|
|
|
dec := acp.NewDecoder(&buf, 0)
|
|
msg, err := dec.DecodeMessage()
|
|
require.NoError(t, err)
|
|
|
|
assert.True(t, msg.IsRequest())
|
|
assert.Equal(t, "session/prompt", msg.Method)
|
|
id, ok := msg.IDInt64()
|
|
require.True(t, ok)
|
|
assert.Equal(t, int64(42), id)
|
|
}
|
|
|
|
func TestJSONRPC_RoundtripStringID(t *testing.T) {
|
|
t.Parallel()
|
|
idJSON, _ := json.Marshal("client-abc")
|
|
req := &acp.Message{JSONRPC: "2.0", ID: idJSON, Method: "session/prompt"}
|
|
|
|
var buf bytes.Buffer
|
|
require.NoError(t, acp.NewEncoder(&buf).Encode(req))
|
|
|
|
dec := acp.NewDecoder(&buf, 0)
|
|
msg, _ := dec.DecodeMessage()
|
|
s, ok := msg.IDString()
|
|
require.True(t, ok)
|
|
assert.Equal(t, "client-abc", s)
|
|
|
|
_, ok2 := msg.IDInt64()
|
|
assert.False(t, ok2)
|
|
}
|
|
|
|
func TestJSONRPC_Notification_NoID(t *testing.T) {
|
|
t.Parallel()
|
|
notif, _ := acp.NewNotification("session/update", map[string]string{"x": "y"})
|
|
|
|
var buf bytes.Buffer
|
|
require.NoError(t, acp.NewEncoder(&buf).Encode(notif))
|
|
|
|
msg, _ := acp.NewDecoder(&buf, 0).DecodeMessage()
|
|
assert.True(t, msg.IsNotification())
|
|
assert.False(t, msg.IsRequest())
|
|
assert.False(t, msg.IsResponse())
|
|
}
|
|
|
|
func TestJSONRPC_Response(t *testing.T) {
|
|
t.Parallel()
|
|
idJSON, _ := json.Marshal(int64(7))
|
|
resp, _ := acp.NewResponseOK(idJSON, map[string]string{"sessionId": "abc"})
|
|
|
|
var buf bytes.Buffer
|
|
require.NoError(t, acp.NewEncoder(&buf).Encode(resp))
|
|
|
|
msg, _ := acp.NewDecoder(&buf, 0).DecodeMessage()
|
|
assert.True(t, msg.IsResponse())
|
|
|
|
var result struct {
|
|
SessionID string `json:"sessionId"`
|
|
}
|
|
require.NoError(t, json.Unmarshal(msg.Result, &result))
|
|
assert.Equal(t, "abc", result.SessionID)
|
|
}
|
|
|
|
func TestJSONRPC_ErrorResponse(t *testing.T) {
|
|
t.Parallel()
|
|
idJSON, _ := json.Marshal("client-1")
|
|
resp := acp.NewResponseErr(idJSON, acp.JSONRPCMethodNotFound, "no such method")
|
|
|
|
var buf bytes.Buffer
|
|
require.NoError(t, acp.NewEncoder(&buf).Encode(resp))
|
|
|
|
msg, _ := acp.NewDecoder(&buf, 0).DecodeMessage()
|
|
require.NotNil(t, msg.Error)
|
|
assert.Equal(t, acp.JSONRPCMethodNotFound, msg.Error.Code)
|
|
assert.Equal(t, "no such method", msg.Error.Message)
|
|
}
|
|
|
|
func TestJSONRPC_DecoderEOF(t *testing.T) {
|
|
t.Parallel()
|
|
dec := acp.NewDecoder(bytes.NewReader(nil), 0)
|
|
_, err := dec.DecodeMessage()
|
|
assert.ErrorIs(t, err, io.EOF)
|
|
}
|
|
|
|
func TestJSONRPC_DecoderMaxSize(t *testing.T) {
|
|
t.Parallel()
|
|
huge := make([]byte, 200)
|
|
for i := range huge {
|
|
huge[i] = 'a'
|
|
}
|
|
body := []byte(`{"jsonrpc":"2.0","method":"x","params":"`)
|
|
body = append(body, huge...)
|
|
body = append(body, []byte(`"}`+"\n")...)
|
|
|
|
dec := acp.NewDecoder(bytes.NewReader(body), 100)
|
|
_, err := dec.DecodeMessage()
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "exceeds max size")
|
|
}
|
|
|
|
func TestJSONRPC_DecoderBadJSON(t *testing.T) {
|
|
t.Parallel()
|
|
dec := acp.NewDecoder(bytes.NewReader([]byte("not-json\n")), 0)
|
|
_, err := dec.DecodeMessage()
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestJSONRPC_EncoderConcurrentSafe(t *testing.T) {
|
|
t.Parallel()
|
|
var buf bytes.Buffer
|
|
enc := acp.NewEncoder(&buf)
|
|
|
|
const N = 100
|
|
done := make(chan struct{}, N)
|
|
for i := 0; i < N; i++ {
|
|
go func(id int64) {
|
|
req, _ := acp.NewRequestInt(id, "m", nil)
|
|
_ = enc.Encode(req)
|
|
done <- struct{}{}
|
|
}(int64(i))
|
|
}
|
|
for i := 0; i < N; i++ {
|
|
<-done
|
|
}
|
|
|
|
dec := acp.NewDecoder(&buf, 0)
|
|
count := 0
|
|
for {
|
|
_, err := dec.DecodeMessage()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
require.NoError(t, err)
|
|
count++
|
|
}
|
|
assert.Equal(t, N, count)
|
|
}
|