Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 271 additions & 3 deletions internal/logger/rpc_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package logger
import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestExtractErrorMessage(t *testing.T) {
Expand Down Expand Up @@ -151,9 +154,7 @@ func TestExtractErrorMessage(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ExtractErrorMessage(tt.input)
if result != tt.expected {
t.Errorf("ExtractErrorMessage(%q) = %q, want %q", tt.input, result, tt.expected)
}
assert.Equal(t, tt.expected, result, "ExtractErrorMessage(%q)", tt.input)
})
}
}
Expand All @@ -173,3 +174,270 @@ func BenchmarkExtractErrorMessageLong(b *testing.B) {
ExtractErrorMessage(testLine)
}
}

// TestTruncateAndSanitize tests the truncateAndSanitize function
func TestTruncateAndSanitize(t *testing.T) {
tests := []struct {
name string
payload string
maxLength int
want string
}{
{
name: "short string no truncation",
payload: "Hello, World!",
maxLength: 50,
want: "Hello, World!",
},
{
name: "exact max length",
payload: "Hello",
maxLength: 5,
want: "Hello",
},
{
name: "truncation needed",
payload: "This is a very long string that needs to be truncated",
maxLength: 20,
want: "This is a very long ...",
},
{
name: "empty string",
payload: "",
maxLength: 10,
want: "",
},
{
name: "zero max length",
payload: "test",
maxLength: 0,
want: "...",
},
{
name: "sanitize secrets - GitHub token",
payload: "token: ghp_1234567890abcdefghijklmnopqrstuvwxyz",
maxLength: 100,
want: "token: [REDACTED]",
},
{
name: "sanitize and truncate",
payload: "auth bearer ghp_1234567890abcdefghijklmnopqrstuvwxyz " + strings.Repeat("x", 100),
maxLength: 50,
want: "auth bearer [REDACTED] " + strings.Repeat("x", 23) + "...",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := truncateAndSanitize(tt.payload, tt.maxLength)
assert.Equal(t, tt.want, result)
})
}
}

// TestExtractEssentialFields tests the extractEssentialFields function
func TestExtractEssentialFields(t *testing.T) {
tests := []struct {
name string
payload string
want map[string]interface{}
}{
{
name: "valid JSON-RPC request",
payload: `{"jsonrpc":"2.0","method":"tools/list","id":1,"params":{"name":"test"}}`,
want: map[string]interface{}{
"jsonrpc": "2.0",
"method": "tools/list",
"id": float64(1),
"params_keys": []string{"name"},
},
},
{
name: "JSON-RPC response with error",
payload: `{"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"Invalid Request"}}`,
want: map[string]interface{}{
"jsonrpc": "2.0",
"id": float64(1),
"error": map[string]interface{}{
"code": float64(-32600),
"message": "Invalid Request",
},
},
},
{
name: "minimal request with method only",
payload: `{"method":"initialize"}`,
want: map[string]interface{}{
"method": "initialize",
},
},
{
name: "request with null params",
payload: `{"jsonrpc":"2.0","method":"test","id":2,"params":null}`,
want: map[string]interface{}{
"jsonrpc": "2.0",
"method": "test",
"id": float64(2),
},
},
{
name: "request with complex params",
payload: `{"method":"call","params":{"arg1":"val1","arg2":"val2","arg3":"val3"}}`,
want: map[string]interface{}{
"method": "call",
"params_keys": []string{"arg1", "arg2", "arg3"},
},
},
{
name: "invalid JSON",
payload: `{invalid json}`,
want: nil,
},
{
name: "empty JSON object",
payload: `{}`,
want: map[string]interface{}{},
},
{
name: "empty string",
payload: ``,
want: nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := extractEssentialFields([]byte(tt.payload))

if tt.want == nil {
assert.Nil(t, result)
return
}

require.NotNil(t, result)
assert.Equal(t, tt.want["jsonrpc"], result["jsonrpc"])
assert.Equal(t, tt.want["method"], result["method"])
assert.Equal(t, tt.want["id"], result["id"])
assert.Equal(t, tt.want["error"], result["error"])

// Special handling for params_keys since order may vary
if expectedKeys, ok := tt.want["params_keys"].([]string); ok {
actualKeys, ok := result["params_keys"].([]string)
require.True(t, ok, "params_keys should be []string")
assert.ElementsMatch(t, expectedKeys, actualKeys)
}
})
}
}

// TestGetMapKeys tests the getMapKeys function
func TestGetMapKeys(t *testing.T) {
tests := []struct {
name string
m map[string]interface{}
want []string
}{
{
name: "normal map",
m: map[string]interface{}{
"key1": "value1",
"key2": "value2",
"key3": "value3",
},
want: []string{"key1", "key2", "key3"},
},
{
name: "empty map",
m: map[string]interface{}{},
want: []string{},
},
{
name: "single key",
m: map[string]interface{}{
"only": "value",
},
want: []string{"only"},
},
{
name: "nil values",
m: map[string]interface{}{
"null1": nil,
"null2": nil,
},
want: []string{"null1", "null2"},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := getMapKeys(tt.m)
assert.ElementsMatch(t, tt.want, result, "keys should match regardless of order")
assert.Len(t, result, len(tt.want), "should have correct number of keys")
})
}
}

// TestIsEffectivelyEmpty tests the isEffectivelyEmpty function
func TestIsEffectivelyEmpty(t *testing.T) {
tests := []struct {
name string
data map[string]interface{}
want bool
}{
{
name: "truly empty map",
data: map[string]interface{}{},
want: true,
},
{
name: "only params with null value",
data: map[string]interface{}{
"params": nil,
},
want: true,
},
{
name: "params with non-null value",
data: map[string]interface{}{
"params": "some value",
},
want: false,
},
{
name: "multiple fields including params",
data: map[string]interface{}{
"params": nil,
"method": "test",
},
want: false,
},
{
name: "single non-params field",
data: map[string]interface{}{
"method": "test",
},
want: false,
},
{
name: "params with empty map",
data: map[string]interface{}{
"params": map[string]interface{}{},
},
want: false,
},
{
name: "params with empty string",
data: map[string]interface{}{
"params": "",
},
want: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := isEffectivelyEmpty(tt.data)
assert.Equal(t, tt.want, result)
})
}
}