swift-sdk/Tests/MCPTests/Helpers/MockTransport.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

115 lines
3.1 KiB
Swift

import class Foundation.JSONEncoder
import class Foundation.JSONDecoder
import struct Foundation.Data
import struct Foundation.POSIXError
import Logging
@testable import MCP
/// Mock transport for testing
actor MockTransport: Transport {
var logger: Logger
let encoder = JSONEncoder()
let decoder = JSONDecoder()
var isConnected = false
private(set) var sentData: [Data] = []
var sentMessages: [String] {
return sentData.compactMap { data in
guard let string = String(data: data, encoding: .utf8) else {
logger.error("Failed to decode sent data as UTF-8")
return nil
}
return string
}
}
private var dataToReceive: [Data] = []
private(set) var receivedMessages: [String] = []
private var dataStreamContinuation: AsyncThrowingStream<Data, Error>.Continuation?
var shouldFailConnect = false
var shouldFailSend = false
init(logger: Logger = Logger(label: "mcp.test.transport")) {
self.logger = logger
}
public func connect() async throws {
if shouldFailConnect {
throw MCPError.transportError(POSIXError(.ECONNREFUSED))
}
isConnected = true
}
public func disconnect() async {
isConnected = false
dataStreamContinuation?.finish()
dataStreamContinuation = nil
}
public func send(_ message: Data) async throws {
if shouldFailSend {
throw MCPError.transportError(POSIXError(.EIO))
}
sentData.append(message)
}
public func receive() -> AsyncThrowingStream<Data, Error> {
return AsyncThrowingStream<Data, Error> { continuation in
dataStreamContinuation = continuation
for message in dataToReceive {
continuation.yield(message)
if let string = String(data: message, encoding: .utf8) {
receivedMessages.append(string)
}
}
dataToReceive.removeAll()
}
}
func setFailConnect(_ shouldFail: Bool) {
shouldFailConnect = shouldFail
}
func setFailSend(_ shouldFail: Bool) {
shouldFailSend = shouldFail
}
func queue<M: Method>(request: Request<M>) throws {
let data = try encoder.encode(request)
if let continuation = dataStreamContinuation {
continuation.yield(data)
} else {
dataToReceive.append(data)
}
}
func queue<M: Method>(response: Response<M>) throws {
let data = try encoder.encode(response)
dataToReceive.append(data)
}
func queue<N: Notification>(notification: Message<N>) throws {
let data = try encoder.encode(notification)
dataToReceive.append(data)
}
func decodeLastSentMessage<T: Decodable>() -> T? {
guard let lastMessage = sentData.last else { return nil }
do {
return try decoder.decode(T.self, from: lastMessage)
} catch {
return nil
}
}
func clearMessages() {
sentData.removeAll()
dataToReceive.removeAll()
}
}