265 lines
6.5 KiB
Go
265 lines
6.5 KiB
Go
package test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
testPort = 8099
|
|
testEndpoint = "/test/echo"
|
|
)
|
|
|
|
// setupTestEnvironment creates test configuration files and starts the bridge
|
|
func setupTestEnvironment(t *testing.T) (*exec.Cmd, func()) {
|
|
// Create a temporary directory for test configurations
|
|
tmpDir, err := ioutil.TempDir("", "mcp-bridge-test")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp dir: %v", err)
|
|
}
|
|
|
|
// Create the main config file
|
|
mainConfig := fmt.Sprintf(`
|
|
port: %d
|
|
services:
|
|
test-adapter:
|
|
config: %s/service.yaml
|
|
command:
|
|
- %s
|
|
`, testPort, tmpDir, "../bin/adapter")
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(tmpDir, "config.yaml"), []byte(mainConfig), 0644); err != nil {
|
|
os.RemoveAll(tmpDir)
|
|
t.Fatalf("Failed to write main config: %v", err)
|
|
}
|
|
|
|
// Create the service config file
|
|
serviceConfig := `
|
|
serviceName: test-adapter
|
|
endpoints:
|
|
- path: /test/echo
|
|
mcp_method: echo
|
|
tool_name: echo
|
|
- path: /test/error
|
|
mcp_method: error
|
|
tool_name: error
|
|
- path: /test/sum
|
|
mcp_method: sum
|
|
tool_name: sum
|
|
- path: /test/tools/call
|
|
mcp_method: tools/call
|
|
tool_name: tools/call
|
|
`
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(tmpDir, "service.yaml"), []byte(serviceConfig), 0644); err != nil {
|
|
os.RemoveAll(tmpDir)
|
|
t.Fatalf("Failed to write service config: %v", err)
|
|
}
|
|
|
|
// Start the bridge
|
|
bridgePath := "../mcp-bridge" // Use the binary in the project root
|
|
cmd := exec.Command(bridgePath, "-port", fmt.Sprintf("%d", testPort), "-config", filepath.Join(tmpDir, "config.yaml"))
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
os.RemoveAll(tmpDir)
|
|
t.Fatalf("Failed to start bridge: %v", err)
|
|
}
|
|
|
|
// Wait for the server to start
|
|
time.Sleep(2 * time.Second)
|
|
|
|
// Return a cleanup function
|
|
cleanup := func() {
|
|
cmd.Process.Signal(os.Interrupt)
|
|
cmd.Wait()
|
|
os.RemoveAll(tmpDir)
|
|
}
|
|
|
|
return cmd, cleanup
|
|
}
|
|
|
|
func TestEchoEndpoint(t *testing.T) {
|
|
_, cleanup := setupTestEnvironment(t)
|
|
defer cleanup()
|
|
|
|
// Send a request to the echo endpoint
|
|
payload := map[string]string{"message": "hello world"}
|
|
jsonPayload, _ := json.Marshal(payload)
|
|
|
|
resp, err := http.Post(fmt.Sprintf("http://localhost:%d%s", testPort, testEndpoint),
|
|
"application/json", bytes.NewBuffer(jsonPayload))
|
|
if err != nil {
|
|
t.Fatalf("Failed to send request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Check the status code
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("Expected status OK, got %v", resp.Status)
|
|
}
|
|
|
|
// Read and parse the response
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read response body: %v", err)
|
|
}
|
|
|
|
var response struct {
|
|
Message string `json:"message"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
if err := json.Unmarshal(body, &response); err != nil {
|
|
t.Fatalf("Failed to parse response: %v", err)
|
|
}
|
|
|
|
// Verify the response
|
|
if response.Message != "hello world" {
|
|
t.Errorf("Expected message 'hello world', got '%s'", response.Message)
|
|
}
|
|
if response.Status != "success" {
|
|
t.Errorf("Expected status 'success', got '%s'", response.Status)
|
|
}
|
|
}
|
|
|
|
func TestErrorEndpoint(t *testing.T) {
|
|
_, cleanup := setupTestEnvironment(t)
|
|
defer cleanup()
|
|
|
|
// Send a request to the error endpoint
|
|
payload := map[string]interface{}{
|
|
"code": -32000,
|
|
"message": "test error",
|
|
}
|
|
jsonPayload, _ := json.Marshal(payload)
|
|
|
|
resp, err := http.Post(fmt.Sprintf("http://localhost:%d/test/error", testPort),
|
|
"application/json", bytes.NewBuffer(jsonPayload))
|
|
if err != nil {
|
|
t.Fatalf("Failed to send request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Check the status code - should be BadRequest for JSON-RPC errors
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Errorf("Expected status BadRequest, got %v", resp.Status)
|
|
}
|
|
|
|
// Read and parse the response
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read response body: %v", err)
|
|
}
|
|
|
|
var response struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
if err := json.Unmarshal(body, &response); err != nil {
|
|
t.Fatalf("Failed to parse response: %v", err)
|
|
}
|
|
|
|
// Verify the response
|
|
if response.Code != -32000 {
|
|
t.Errorf("Expected code -32000, got %d", response.Code)
|
|
}
|
|
if response.Message != "test error" {
|
|
t.Errorf("Expected message 'test error', got '%s'", response.Message)
|
|
}
|
|
}
|
|
|
|
func TestSumEndpoint(t *testing.T) {
|
|
_, cleanup := setupTestEnvironment(t)
|
|
defer cleanup()
|
|
|
|
// Send a request to the sum endpoint
|
|
numbers := []float64{1.5, 2.5, 3.5, 4.5, 5.0}
|
|
jsonPayload, _ := json.Marshal(numbers)
|
|
|
|
resp, err := http.Post(fmt.Sprintf("http://localhost:%d/test/sum", testPort),
|
|
"application/json", bytes.NewBuffer(jsonPayload))
|
|
if err != nil {
|
|
t.Fatalf("Failed to send request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Check the status code
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("Expected status OK, got %v", resp.Status)
|
|
}
|
|
|
|
// Read and parse the response
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read response body: %v", err)
|
|
}
|
|
|
|
var result float64
|
|
if err := json.Unmarshal(body, &result); err != nil {
|
|
t.Fatalf("Failed to parse response: %v", err)
|
|
}
|
|
|
|
// Verify the response
|
|
expected := 17.0 // 1.5 + 2.5 + 3.5 + 4.5 + 5.0
|
|
if result != expected {
|
|
t.Errorf("Expected sum %f, got %f", expected, result)
|
|
}
|
|
}
|
|
|
|
func TestToolsCallEndpoint(t *testing.T) {
|
|
_, cleanup := setupTestEnvironment(t)
|
|
defer cleanup()
|
|
|
|
// Send a request to the tools/call endpoint
|
|
payload := map[string]interface{}{
|
|
"name": "test-tool",
|
|
"parameters": map[string]string{
|
|
"param1": "value1",
|
|
"param2": "value2",
|
|
},
|
|
}
|
|
jsonPayload, _ := json.Marshal(payload)
|
|
|
|
resp, err := http.Post(fmt.Sprintf("http://localhost:%d/test/tools/call", testPort),
|
|
"application/json", bytes.NewBuffer(jsonPayload))
|
|
if err != nil {
|
|
t.Fatalf("Failed to send request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Check the status code
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("Expected status OK, got %v", resp.Status)
|
|
}
|
|
|
|
// Read and parse the response
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read response body: %v", err)
|
|
}
|
|
|
|
var response struct {
|
|
Result map[string]string `json:"result"`
|
|
}
|
|
|
|
if err := json.Unmarshal(body, &response); err != nil {
|
|
t.Fatalf("Failed to parse response: %v", err)
|
|
}
|
|
|
|
// Verify the response
|
|
if response.Result["param1"] != "value1" || response.Result["param2"] != "value2" {
|
|
t.Errorf("Response does not match expected parameters: %v", response.Result)
|
|
}
|
|
}
|