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) } }