Skip to content

Commit 5d42a6d

Browse files
chore: improved unit tests a little bit
1 parent 349c36a commit 5d42a6d

4 files changed

Lines changed: 57 additions & 62 deletions

File tree

Sources/MCP/Base/Transports/NetworkTransport.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -349,16 +349,20 @@ import Logging
349349
/// - Throws: Error if the connection fails
350350
private func attemptConnection() async throws {
351351
// Create stream for state changes with proper cleanup
352-
let (stateStream, continuation) = AsyncStream.makeStream(of: NWConnection.State.self)
353-
354-
connection.stateUpdateHandler = { state in
355-
continuation.yield(state)
356-
}
352+
let stateStream = AsyncStream<NWConnection.State> { continuation in
353+
continuation.onTermination = { [weak self] _ in
354+
self?.connection.stateUpdateHandler = nil
355+
}
357356

358-
// Ensure cleanup happens when we exit
359-
defer {
360-
continuation.finish()
361-
connection.stateUpdateHandler = nil
357+
connection.stateUpdateHandler = { state in
358+
continuation.yield(state)
359+
switch state {
360+
case .ready, .failed, .cancelled:
361+
continuation.finish()
362+
default:
363+
break
364+
}
365+
}
362366
}
363367

364368
connection.start(queue: .main)

Tests/MCPTests/ClientTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Testing
33

44
@testable import MCP
55

6-
@Suite("Client Tests")
6+
@Suite("Client Tests", .timeLimit(.minutes(1)))
77
struct ClientTests {
88
@Test("Client connect and disconnect")
99
func testClientConnectAndDisconnect() async throws {

Tests/MCPTests/NetworkTransportTests.swift

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ import Testing
268268

269269
// Simulate failure before connecting
270270
mockConnection.simulateFailure(error: NWError.posix(POSIXErrorCode.ECONNRESET))
271-
271+
272272
do {
273273
try await transport.connect()
274274
Issue.record("Expected connect to throw an error")
@@ -496,33 +496,6 @@ import Testing
496496
_ = await receiveTask.result
497497
}
498498

499-
@Test("Connection State Transitions")
500-
func testConnectionStateTransitions() async throws {
501-
let mockConnection = MockNetworkConnection()
502-
let transport = NetworkTransport(
503-
mockConnection,
504-
heartbeatConfig: .disabled
505-
)
506-
507-
// Test setup -> preparing -> ready transition
508-
mockConnection.simulatePreparing()
509-
try await Task.sleep(for: .milliseconds(100))
510-
mockConnection.simulateReady()
511-
try await transport.connect()
512-
#expect(mockConnection.state == .ready)
513-
514-
// Test ready -> failed transition
515-
mockConnection.simulateFailure(error: NWError.posix(POSIXErrorCode.ECONNRESET))
516-
try await Task.sleep(for: .milliseconds(100))
517-
if case .failed = mockConnection.state {
518-
// expected
519-
} else {
520-
Issue.record("Expected state to be failed")
521-
}
522-
523-
await transport.disconnect()
524-
}
525-
526499
@Test("Partial Message Reception")
527500
func testPartialMessageReception() async throws {
528501
let mockConnection = MockNetworkConnection()

Tests/MCPTests/ServerTests.swift

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct ServerTests {
3939
try await server.start(transport: transport)
4040

4141
// Wait for message processing and response
42-
try await Task.sleep(for: .milliseconds(100))
42+
try await Task.sleep(for: .milliseconds(200))
4343

4444
#expect(await transport.sentMessages.count == 1)
4545

@@ -143,49 +143,66 @@ struct ServerTests {
143143

144144
@Test("JSON-RPC batch processing")
145145
func testJSONRPCBatchProcessing() async throws {
146-
let transport = MockTransport()
146+
let (clientTransport, serverTransport) = await InMemoryTransport.createConnectedPair()
147147
let server = Server(name: "TestServer", version: "1.0")
148148

149+
// Connect transports
150+
try await clientTransport.connect()
151+
try await serverTransport.connect()
152+
153+
// Start receiving messages on client side
154+
let receiveTask = Task {
155+
var responses: [String] = []
156+
for try await data in await clientTransport.receive() {
157+
if let response = String(data: data, encoding: .utf8) {
158+
responses.append(response)
159+
}
160+
// Stop after receiving 2 responses (initialize + batch)
161+
if responses.count == 2 {
162+
break
163+
}
164+
}
165+
return responses
166+
}
167+
149168
// Start the server
150-
try await server.start(transport: transport)
169+
try await server.start(transport: serverTransport)
151170

152171
// Initialize the server first
153-
try await transport.queue(
154-
request: Initialize.request(
155-
.init(
156-
protocolVersion: Version.latest,
157-
capabilities: .init(),
158-
clientInfo: .init(name: "TestClient", version: "1.0")
159-
)
172+
let initRequest = Initialize.request(
173+
.init(
174+
protocolVersion: Version.latest,
175+
capabilities: .init(),
176+
clientInfo: .init(name: "TestClient", version: "1.0")
160177
)
161178
)
179+
let initData = try JSONEncoder().encode(AnyRequest(initRequest))
180+
try await clientTransport.send(initData)
162181

163-
// Wait for server to initialize and respond
182+
// Wait for initialization
164183
try await Task.sleep(for: .milliseconds(100))
165184

166-
// Clear sent messages
167-
await transport.clearMessages()
168-
169185
// Create a batch with multiple requests
170186
let batchJSON = """
171187
[
172188
{"jsonrpc":"2.0","id":1,"method":"ping","params":{}},
173189
{"jsonrpc":"2.0","id":2,"method":"ping","params":{}}
174190
]
175191
"""
176-
let batch = try JSONDecoder().decode([AnyRequest].self, from: batchJSON.data(using: .utf8)!)
177-
178-
// Send the batch request
179-
try await transport.queue(batch: batch)
192+
let batchData = batchJSON.data(using: .utf8)!
193+
try await clientTransport.send(batchData)
180194

181195
// Wait for batch processing
182-
try await Task.sleep(for: .milliseconds(100))
196+
try await Task.sleep(for: .milliseconds(200))
183197

184-
// Verify response
185-
let sentMessages = await transport.sentMessages
186-
#expect(sentMessages.count == 1)
198+
// Get responses
199+
let responses = try await receiveTask.value
200+
#expect(responses.count == 2)
201+
202+
// Verify the batch response (second response)
203+
if responses.count >= 2 {
204+
let batchResponse = responses[1]
187205

188-
if let batchResponse = sentMessages.first {
189206
// Should be an array
190207
#expect(batchResponse.hasPrefix("["))
191208
#expect(batchResponse.hasSuffix("]"))
@@ -196,6 +213,7 @@ struct ServerTests {
196213
}
197214

198215
await server.stop()
199-
await transport.disconnect()
216+
await clientTransport.disconnect()
217+
await serverTransport.disconnect()
200218
}
201219
}

0 commit comments

Comments
 (0)