mirror of
https://github.com/alibaba/higress.git
synced 2026-03-10 03:30:48 +08:00
282 lines
8.3 KiB
Go
282 lines
8.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
|
"github.com/higress-group/wasm-go/pkg/test"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestTruncateString tests the truncateString function
|
|
func TestTruncateString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
maxLen int
|
|
expected string
|
|
}{
|
|
{"Short String", "Higress Is an AI-Native API Gateway", 1000, "Higress Is an AI-Native API Gateway"},
|
|
{"Exact Length", "Higress Is an AI-Native API Gateway", 35, "Higress Is an AI-Native API Gateway"},
|
|
{"Truncated String", "Higress Is an AI-Native API Gateway", 20, "Higress Is...(truncated)...PI Gateway"},
|
|
{"Empty String", "", 10, ""},
|
|
{"Single Char", "A", 10, "A"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
config := McpConverterConfig{MaxHeaderLength: tt.maxLen}
|
|
result := truncateString(tt.input, config)
|
|
if result != tt.expected {
|
|
t.Errorf("truncateString(%q, %d) = %q; want %q", tt.input, tt.maxLen, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestIsPreRequestStage tests the isPreRequestStage function
|
|
func TestIsPreRequestStage(t *testing.T) {
|
|
config := McpConverterConfig{Stage: ProcessRequest}
|
|
require.True(t, isPreRequestStage(config))
|
|
|
|
config = McpConverterConfig{Stage: ProcessResponse}
|
|
require.False(t, isPreRequestStage(config))
|
|
}
|
|
|
|
// TestIsPreResponseStage tests the isPreResponseStage function
|
|
func TestIsPreResponseStage(t *testing.T) {
|
|
config := McpConverterConfig{Stage: ProcessResponse}
|
|
require.True(t, isPreResponseStage(config))
|
|
|
|
config = McpConverterConfig{Stage: ProcessRequest}
|
|
require.False(t, isPreResponseStage(config))
|
|
}
|
|
|
|
// TestIsMethodAllowed tests the isMethodAllowed function
|
|
func TestIsMethodAllowed(t *testing.T) {
|
|
config := McpConverterConfig{AllowedMethods: []string{MethodToolList, MethodToolCall}}
|
|
|
|
require.True(t, isMethodAllowed(config, MethodToolList))
|
|
require.True(t, isMethodAllowed(config, MethodToolCall))
|
|
require.False(t, isMethodAllowed(config, "invalid/method"))
|
|
}
|
|
|
|
// TestConstants tests the constant values
|
|
func TestConstants(t *testing.T) {
|
|
require.Equal(t, "x-envoy-jsonrpc-id", JsonRpcId)
|
|
require.Equal(t, "x-envoy-jsonrpc-method", JsonRpcMethod)
|
|
require.Equal(t, "x-envoy-jsonrpc-params", JsonRpcParams)
|
|
require.Equal(t, "x-envoy-jsonrpc-result", JsonRpcResult)
|
|
require.Equal(t, "x-envoy-jsonrpc-error", JsonRpcError)
|
|
require.Equal(t, "x-envoy-mcp-tool-name", McpToolName)
|
|
require.Equal(t, "x-envoy-mcp-tool-arguments", McpToolArguments)
|
|
require.Equal(t, "x-envoy-mcp-tool-response", McpToolResponse)
|
|
require.Equal(t, "x-envoy-mcp-tool-error", McpToolError)
|
|
require.Equal(t, 4000, DefaultMaxHeaderLength)
|
|
require.Equal(t, "tools/list", MethodToolList)
|
|
require.Equal(t, "tools/call", MethodToolCall)
|
|
require.Equal(t, ProcessStage("request"), ProcessRequest)
|
|
require.Equal(t, ProcessStage("response"), ProcessResponse)
|
|
}
|
|
|
|
// TestMcpConverterConfigDefaults tests config default values
|
|
func TestMcpConverterConfigDefaults(t *testing.T) {
|
|
config := McpConverterConfig{}
|
|
require.Equal(t, 0, config.MaxHeaderLength)
|
|
require.Equal(t, ProcessStage(""), config.Stage)
|
|
require.Nil(t, config.AllowedMethods)
|
|
}
|
|
|
|
// TestProcessStage tests ProcessStage type
|
|
func TestProcessStage(t *testing.T) {
|
|
require.Equal(t, ProcessStage("request"), ProcessRequest)
|
|
require.Equal(t, ProcessStage("response"), ProcessResponse)
|
|
}
|
|
|
|
// TestRemoveJsonRpcHeadersFunction tests removeJsonRpcHeaders function logic
|
|
func TestRemoveJsonRpcHeadersFunction(t *testing.T) {
|
|
headersToRemove := []string{
|
|
JsonRpcId,
|
|
JsonRpcMethod,
|
|
JsonRpcParams,
|
|
JsonRpcResult,
|
|
McpToolName,
|
|
McpToolArguments,
|
|
McpToolResponse,
|
|
McpToolError,
|
|
}
|
|
require.Len(t, headersToRemove, 8)
|
|
}
|
|
|
|
// TestTruncateStringLong tests truncation of very long strings
|
|
func TestTruncateStringLong(t *testing.T) {
|
|
longString := ""
|
|
for i := 0; i < 5000; i++ {
|
|
longString += "a"
|
|
}
|
|
config := McpConverterConfig{MaxHeaderLength: 1000}
|
|
result := truncateString(longString, config)
|
|
require.Contains(t, result, "...(truncated)...")
|
|
require.LessOrEqual(t, len(result), 1020)
|
|
}
|
|
|
|
// TestTruncateStringWithSmallMaxLength tests truncation with small max length
|
|
func TestTruncateStringWithSmallMaxLength(t *testing.T) {
|
|
config := McpConverterConfig{MaxHeaderLength: 10}
|
|
result := truncateString("This is a very long string", config)
|
|
require.Contains(t, result, "...(truncated)...")
|
|
}
|
|
|
|
// TestPluginInit tests plugin initialization
|
|
func TestPluginInit(t *testing.T) {
|
|
configBytes, _ := json.Marshal(McpConverterConfig{
|
|
Stage: ProcessRequest,
|
|
MaxHeaderLength: DefaultMaxHeaderLength,
|
|
AllowedMethods: []string{MethodToolList, MethodToolCall},
|
|
})
|
|
|
|
host, status := test.NewTestHost(configBytes)
|
|
defer host.Reset()
|
|
require.Equal(t, types.OnPluginStartStatusOK, status)
|
|
}
|
|
|
|
// TestProcessJsonRpcRequest tests processJsonRpcRequest function
|
|
func TestProcessJsonRpcRequest(t *testing.T) {
|
|
configBytes, _ := json.Marshal(McpConverterConfig{
|
|
Stage: ProcessRequest,
|
|
MaxHeaderLength: DefaultMaxHeaderLength,
|
|
AllowedMethods: []string{MethodToolList, MethodToolCall},
|
|
})
|
|
|
|
host, status := test.NewTestHost(configBytes)
|
|
defer host.Reset()
|
|
require.Equal(t, types.OnPluginStartStatusOK, status)
|
|
|
|
host.InitHttp()
|
|
host.CallOnHttpRequestHeaders([][2]string{
|
|
{":authority", "mcp-server.example.com"},
|
|
{":method", "POST"},
|
|
{":path", "/mcp"},
|
|
{"content-type", "application/json"},
|
|
})
|
|
|
|
toolsListRequest := `{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"method": "tools/list",
|
|
"params": {}
|
|
}`
|
|
action := host.CallOnHttpRequestBody([]byte(toolsListRequest))
|
|
require.Equal(t, types.ActionContinue, action)
|
|
|
|
host.CompleteHttp()
|
|
}
|
|
|
|
// TestProcessToolCallRequest tests processToolCallRequest function
|
|
func TestProcessToolCallRequest(t *testing.T) {
|
|
configBytes, _ := json.Marshal(McpConverterConfig{
|
|
Stage: ProcessRequest,
|
|
MaxHeaderLength: DefaultMaxHeaderLength,
|
|
AllowedMethods: []string{MethodToolCall},
|
|
})
|
|
|
|
host, status := test.NewTestHost(configBytes)
|
|
defer host.Reset()
|
|
require.Equal(t, types.OnPluginStartStatusOK, status)
|
|
|
|
host.InitHttp()
|
|
host.CallOnHttpRequestHeaders([][2]string{
|
|
{":authority", "mcp-server.example.com"},
|
|
{":method", "POST"},
|
|
{":path", "/mcp"},
|
|
{"content-type", "application/json"},
|
|
})
|
|
|
|
toolCallRequest := `{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"method": "tools/call",
|
|
"params": {
|
|
"name": "test_tool",
|
|
"arguments": {"arg1": "value1"}
|
|
}
|
|
}`
|
|
action := host.CallOnHttpRequestBody([]byte(toolCallRequest))
|
|
require.Equal(t, types.ActionContinue, action)
|
|
|
|
host.CompleteHttp()
|
|
}
|
|
|
|
// TestProcessJsonRpcResponse tests processJsonRpcResponse function
|
|
func TestProcessJsonRpcResponse(t *testing.T) {
|
|
configBytes, _ := json.Marshal(McpConverterConfig{
|
|
Stage: ProcessResponse,
|
|
MaxHeaderLength: DefaultMaxHeaderLength,
|
|
AllowedMethods: []string{MethodToolList, MethodToolCall},
|
|
})
|
|
|
|
host, status := test.NewTestHost(configBytes)
|
|
defer host.Reset()
|
|
require.Equal(t, types.OnPluginStartStatusOK, status)
|
|
|
|
host.InitHttp()
|
|
host.CallOnHttpRequestHeaders([][2]string{
|
|
{":authority", "mcp-server.example.com"},
|
|
{":method", "POST"},
|
|
{":path", "/mcp"},
|
|
{"content-type", "application/json"},
|
|
})
|
|
|
|
responseBody := `{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"result": {
|
|
"tools": [{"name": "test_tool"}]
|
|
}
|
|
}`
|
|
host.CallOnHttpResponseHeaders([][2]string{
|
|
{":status", "200"},
|
|
{"content-type", "application/json"},
|
|
})
|
|
host.CallOnHttpResponseBody([]byte(responseBody))
|
|
|
|
host.CompleteHttp()
|
|
}
|
|
|
|
// TestProcessToolListResponse tests processToolListResponse function
|
|
func TestProcessToolListResponse(t *testing.T) {
|
|
configBytes, _ := json.Marshal(McpConverterConfig{
|
|
Stage: ProcessResponse,
|
|
MaxHeaderLength: DefaultMaxHeaderLength,
|
|
AllowedMethods: []string{MethodToolList},
|
|
})
|
|
|
|
host, status := test.NewTestHost(configBytes)
|
|
defer host.Reset()
|
|
require.Equal(t, types.OnPluginStartStatusOK, status)
|
|
|
|
host.InitHttp()
|
|
host.CallOnHttpRequestHeaders([][2]string{
|
|
{":authority", "mcp-server.example.com"},
|
|
{":method", "POST"},
|
|
{":path", "/mcp"},
|
|
{"content-type", "application/json"},
|
|
})
|
|
|
|
responseBody := `{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"result": {
|
|
"tools": [{"name": "test_tool"}]
|
|
}
|
|
}`
|
|
host.CallOnHttpResponseHeaders([][2]string{
|
|
{":status", "200"},
|
|
{"content-type", "application/json"},
|
|
})
|
|
host.CallOnHttpResponseBody([]byte(responseBody))
|
|
|
|
host.CompleteHttp()
|
|
}
|