mcp-bridge/test/integration_test.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)
}
}