swift-sdk/Tests/MCPTests/ServerTests.swift
Mattt 09da2a1c01
Rename Error to MCPError (#44)
* Rename Error to MCPError

* Conform MCPError to Swift.Error

* Use unqualified Error instead of Swift.Error

* Use unqualified MCPError instead of MCP.MCPError

* Rename file back to Error.swift

* Introduce top-level MCP namespace with nested Error typealias to provide deprecation notice for existing usage of MCP.Error

* Fix markup for MCP enum warning
2025-04-03 05:25:00 -07:00

143 lines
4.5 KiB
Swift

import Foundation
import Testing
@testable import MCP
@Suite("Server Tests")
struct ServerTests {
@Test("Start and stop server")
func testServerStartAndStop() async throws {
let transport = MockTransport()
let server = Server(name: "TestServer", version: "1.0")
#expect(await transport.isConnected == false)
try await server.start(transport: transport)
#expect(await transport.isConnected == true)
await server.stop()
#expect(await transport.isConnected == false)
}
@Test("Initialize request handling")
func testServerHandleInitialize() async throws {
let transport = MockTransport()
// Queue an initialize request
try await transport.queue(
request: Initialize.request(
.init(
protocolVersion: Version.latest,
capabilities: .init(),
clientInfo: .init(name: "TestClient", version: "1.0")
)
))
// Start the server
let server: Server = Server(
name: "TestServer",
version: "1.0"
)
try await server.start(transport: transport)
// Wait for message processing and response
try await Task.sleep(nanoseconds: 10_000_000) // 10ms
#expect(await transport.sentMessages.count == 1)
let messages = await transport.sentMessages
if let response = messages.first {
#expect(response.contains("serverInfo"))
}
// Clean up
await server.stop()
await transport.disconnect()
}
@Test("Initialize hook - successful")
func testInitializeHookSuccess() async throws {
let transport = MockTransport()
actor TestState {
var hookCalled = false
func setHookCalled() { hookCalled = true }
func wasHookCalled() -> Bool { hookCalled }
}
let state = TestState()
let server = Server(name: "TestServer", version: "1.0")
// Start with the hook directly
try await server.start(transport: transport) { clientInfo, capabilities in
#expect(clientInfo.name == "TestClient")
#expect(clientInfo.version == "1.0")
await state.setHookCalled()
}
// Wait for server to initialize
try await Task.sleep(for: .milliseconds(10))
// Queue an initialize request
try await transport.queue(
request: Initialize.request(
.init(
protocolVersion: Version.latest,
capabilities: .init(),
clientInfo: .init(name: "TestClient", version: "1.0")
)
))
// Wait for message processing and hook execution
try await Task.sleep(for: .milliseconds(500))
#expect(await state.wasHookCalled() == true)
#expect(await transport.sentMessages.count >= 1)
let messages = await transport.sentMessages
if let response = messages.first {
#expect(response.contains("serverInfo"))
}
await server.stop()
await transport.disconnect()
}
@Test("Initialize hook - rejection")
func testInitializeHookRejection() async throws {
let transport = MockTransport()
let server = Server(name: "TestServer", version: "1.0")
try await server.start(transport: transport) { clientInfo, _ in
if clientInfo.name == "BlockedClient" {
throw MCPError.invalidRequest("Client not allowed")
}
}
// Wait for server to initialize
try await Task.sleep(nanoseconds: 10_000_000) // 10ms
// Queue an initialize request from blocked client
try await transport.queue(
request: Initialize.request(
.init(
protocolVersion: Version.latest,
capabilities: .init(),
clientInfo: .init(name: "BlockedClient", version: "1.0")
)
))
// Wait for message processing
try await Task.sleep(nanoseconds: 200_000_000) // 200ms
#expect(await transport.sentMessages.count >= 1)
let messages = await transport.sentMessages
if let response = messages.first {
#expect(response.contains("error"))
#expect(response.contains("Client not allowed"))
}
await server.stop()
await transport.disconnect()
}
}