mirror of
https://github.com/alibaba/higress.git
synced 2026-05-31 08:07:26 +08:00
refactor: migrate MCP SDK to main repo (#3516)
This commit is contained in:
302
plugins/wasm-go/pkg/mcp/server/proxy_integration_test.go
Normal file
302
plugins/wasm-go/pkg/mcp/server/proxy_integration_test.go
Normal file
@@ -0,0 +1,302 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// MockHttpContext is a mock implementation for testing - skipping interface implementation for now
|
||||
// Tests that require full HttpContext will be tested in integration tests with real host
|
||||
type MockHttpContext struct {
|
||||
responseBody []byte
|
||||
responseStatus int
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
// TestMcpProtocolInitialization tests the MCP protocol initialization flow
|
||||
func TestMcpProtocolInitialization(t *testing.T) {
|
||||
// Create proxy server
|
||||
server := NewMcpProxyServer("test-proxy")
|
||||
|
||||
// Set server fields directly
|
||||
server.SetMcpServerURL("http://mock-backend.example.com/mcp")
|
||||
server.SetTimeout(5000)
|
||||
|
||||
// Create proxy tool
|
||||
toolConfig := McpProxyToolConfig{
|
||||
Name: "test-tool",
|
||||
Description: "Test tool for initialization",
|
||||
Args: []ToolArg{
|
||||
{
|
||||
Name: "input",
|
||||
Description: "Test input",
|
||||
Type: "string",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := server.AddProxyTool(toolConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
tool, exists := server.GetMCPTools()["test-tool"]
|
||||
require.True(t, exists)
|
||||
|
||||
// Create tool instance with parameters
|
||||
params := map[string]interface{}{
|
||||
"input": "test value",
|
||||
}
|
||||
paramsBytes, err := json.Marshal(params)
|
||||
require.NoError(t, err)
|
||||
|
||||
toolInstance := tool.Create(paramsBytes)
|
||||
require.NotNil(t, toolInstance)
|
||||
|
||||
// Skip HttpContext-dependent test for now - will be tested in integration
|
||||
// mockCtx := &MockHttpContext{}
|
||||
// err = toolInstance.Call(mockCtx, server)
|
||||
// assert.NoError(t, err)
|
||||
|
||||
// Test the tool creation was successful
|
||||
assert.NotNil(t, toolInstance)
|
||||
}
|
||||
|
||||
// TestMcpSessionManagement tests temporary session creation and cleanup
|
||||
func TestMcpSessionManagement(t *testing.T) {
|
||||
_ = NewMcpProxyServer("session-test")
|
||||
|
||||
// Skip session management test until implemented
|
||||
t.Skip("Session management not implemented yet")
|
||||
|
||||
// Test session creation
|
||||
sessionManager := NewMcpSessionManager()
|
||||
sessionID, err := sessionManager.CreateSession("http://backend.example.com/mcp")
|
||||
|
||||
// This will fail until session management is implemented
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, sessionID)
|
||||
|
||||
// Test session retrieval
|
||||
session, exists := sessionManager.GetSession(sessionID)
|
||||
assert.True(t, exists)
|
||||
assert.NotNil(t, session)
|
||||
|
||||
// Test session cleanup
|
||||
sessionManager.CleanupSession(sessionID)
|
||||
_, exists = sessionManager.GetSession(sessionID)
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
// TestMcpProtocolVersionNegotiation tests protocol version handling
|
||||
func TestMcpProtocolVersionNegotiation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
requestedVersion string
|
||||
supportedVersions []string
|
||||
shouldSucceed bool
|
||||
expectedVersion string
|
||||
}{
|
||||
{
|
||||
name: "supported version 2025-03-26",
|
||||
requestedVersion: "2025-03-26",
|
||||
supportedVersions: []string{"2024-11-05", "2025-03-26"},
|
||||
shouldSucceed: true,
|
||||
expectedVersion: "2025-03-26",
|
||||
},
|
||||
{
|
||||
name: "unsupported version",
|
||||
requestedVersion: "2026-01-01",
|
||||
supportedVersions: []string{"2024-11-05", "2025-03-26"},
|
||||
shouldSucceed: false,
|
||||
expectedVersion: "",
|
||||
},
|
||||
{
|
||||
name: "fallback to supported version",
|
||||
requestedVersion: "2025-06-18",
|
||||
supportedVersions: []string{"2024-11-05", "2025-03-26"},
|
||||
shouldSucceed: false,
|
||||
expectedVersion: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip until NewMcpVersionNegotiator is implemented
|
||||
t.Skip("Version negotiation not implemented yet")
|
||||
|
||||
negotiator := NewMcpVersionNegotiator(tt.supportedVersions)
|
||||
version, err := negotiator.NegotiateVersion(tt.requestedVersion)
|
||||
|
||||
if tt.shouldSucceed {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedVersion, version)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMcpInitializeRequest tests the initialize request format and handling
|
||||
func TestMcpInitializeRequest(t *testing.T) {
|
||||
_ = NewMcpProxyServer("init-test")
|
||||
|
||||
// Skip until CreateInitializeRequest is implemented
|
||||
t.Skip("MCP protocol initialization not implemented yet")
|
||||
|
||||
// Test initialize request creation
|
||||
initRequest := CreateInitializeRequest()
|
||||
|
||||
assert.Equal(t, "2.0", initRequest.JsonRPC)
|
||||
assert.Equal(t, "initialize", initRequest.Method)
|
||||
assert.NotNil(t, initRequest.Params)
|
||||
|
||||
// Validate client info
|
||||
params := initRequest.Params.(map[string]interface{})
|
||||
clientInfo := params["clientInfo"].(map[string]interface{})
|
||||
assert.Equal(t, "Higress-mcp-proxy", clientInfo["name"])
|
||||
assert.Equal(t, "1.0.0", clientInfo["version"])
|
||||
|
||||
// Test protocol version
|
||||
assert.Equal(t, "2025-03-26", params["protocolVersion"])
|
||||
}
|
||||
|
||||
// TestMcpNotificationsInitialized tests the notifications/initialized message
|
||||
func TestMcpNotificationsInitialized(t *testing.T) {
|
||||
// Skip until CreateInitializedNotification is implemented
|
||||
t.Skip("MCP notifications not implemented yet")
|
||||
|
||||
// Test notifications/initialized request creation
|
||||
notification := CreateInitializedNotification()
|
||||
|
||||
assert.Equal(t, "2.0", notification.JsonRPC)
|
||||
assert.Equal(t, "notifications/initialized", notification.Method)
|
||||
assert.Nil(t, notification.ID) // Notifications don't have IDs
|
||||
}
|
||||
|
||||
// TestMcpErrorHandling tests error response handling and source identification
|
||||
func TestMcpErrorHandling(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
errorType string
|
||||
originalError error
|
||||
expectedSource string
|
||||
expectedCode int
|
||||
}{
|
||||
{
|
||||
name: "backend connection error",
|
||||
errorType: "connection",
|
||||
originalError: assert.AnError,
|
||||
expectedSource: "mcp-proxy",
|
||||
expectedCode: -32603,
|
||||
},
|
||||
{
|
||||
name: "backend timeout error",
|
||||
errorType: "timeout",
|
||||
originalError: assert.AnError,
|
||||
expectedSource: "mcp-proxy",
|
||||
expectedCode: -32000,
|
||||
},
|
||||
{
|
||||
name: "protocol version error",
|
||||
errorType: "version",
|
||||
originalError: assert.AnError,
|
||||
expectedSource: "mcp-proxy",
|
||||
expectedCode: -32602,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Skip until CreateMcpErrorResponse is implemented
|
||||
t.Skip("MCP error handling not implemented yet")
|
||||
|
||||
errorResponse := CreateMcpErrorResponse(tt.errorType, tt.originalError, "http://backend.example.com/mcp")
|
||||
|
||||
assert.Equal(t, "2.0", errorResponse.JsonRPC)
|
||||
assert.NotNil(t, errorResponse.Error)
|
||||
assert.Equal(t, tt.expectedCode, errorResponse.Error.Code)
|
||||
assert.Equal(t, tt.expectedSource, errorResponse.Error.Data["source"])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helper types and functions that will fail until implemented
|
||||
|
||||
type McpSessionManager struct{}
|
||||
|
||||
func NewMcpSessionManager() *McpSessionManager {
|
||||
panic("McpSessionManager not implemented yet")
|
||||
}
|
||||
|
||||
func (m *McpSessionManager) CreateSession(backendURL string) (string, error) {
|
||||
panic("CreateSession not implemented yet")
|
||||
}
|
||||
|
||||
func (m *McpSessionManager) GetSession(sessionID string) (interface{}, bool) {
|
||||
panic("GetSession not implemented yet")
|
||||
}
|
||||
|
||||
func (m *McpSessionManager) CleanupSession(sessionID string) {
|
||||
panic("CleanupSession not implemented yet")
|
||||
}
|
||||
|
||||
type McpVersionNegotiator struct {
|
||||
supportedVersions []string
|
||||
}
|
||||
|
||||
func NewMcpVersionNegotiator(versions []string) *McpVersionNegotiator {
|
||||
panic("McpVersionNegotiator not implemented yet")
|
||||
}
|
||||
|
||||
func (n *McpVersionNegotiator) NegotiateVersion(requested string) (string, error) {
|
||||
panic("NegotiateVersion not implemented yet")
|
||||
}
|
||||
|
||||
type McpRequest struct {
|
||||
JsonRPC string `json:"jsonrpc"`
|
||||
ID interface{} `json:"id,omitempty"`
|
||||
Method string `json:"method"`
|
||||
Params interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
type McpErrorResponse struct {
|
||||
JsonRPC string `json:"jsonrpc"`
|
||||
ID interface{} `json:"id,omitempty"`
|
||||
Error *McpError `json:"error"`
|
||||
}
|
||||
|
||||
type McpError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func CreateInitializeRequest() *McpRequest {
|
||||
panic("CreateInitializeRequest not implemented yet")
|
||||
}
|
||||
|
||||
func CreateInitializedNotification() *McpRequest {
|
||||
panic("CreateInitializedNotification not implemented yet")
|
||||
}
|
||||
|
||||
func CreateMcpErrorResponse(errorType string, originalError error, backendURL string) *McpErrorResponse {
|
||||
panic("CreateMcpErrorResponse not implemented yet")
|
||||
}
|
||||
Reference in New Issue
Block a user