From e9736909fcade1faa14b24c8e4d54fc1b4c3b038 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Thu, 18 Jan 2024 19:26:13 -0300 Subject: [PATCH] Test --- Sources/Realtime/V2/RealtimeClientV2.swift | 7 +- Sources/Realtime/V2/WebSocketClient.swift | 2 +- Tests/RealtimeTests/MockWebSocketClient.swift | 6 +- Tests/RealtimeTests/RealtimeTests.swift | 278 ++++++++++-------- 4 files changed, 157 insertions(+), 136 deletions(-) diff --git a/Sources/Realtime/V2/RealtimeClientV2.swift b/Sources/Realtime/V2/RealtimeClientV2.swift index fe778d65..6388df32 100644 --- a/Sources/Realtime/V2/RealtimeClientV2.swift +++ b/Sources/Realtime/V2/RealtimeClientV2.swift @@ -143,15 +143,12 @@ public actor RealtimeClientV2 { status = .connecting let realtimeURL = realtimeWebSocketURL - let ws = makeWebSocketClient(realtimeURL, config.headers) self.ws = ws - await ws.connect() + ws.connect() - let connectionStatus = try? await Task(timeout: config.timeoutInterval) { - await ws.status.first { _ in true } - }.value + let connectionStatus = await ws.status.first { _ in true } switch connectionStatus { case .open: diff --git a/Sources/Realtime/V2/WebSocketClient.swift b/Sources/Realtime/V2/WebSocketClient.swift index 1f2a3dda..08c0f85d 100644 --- a/Sources/Realtime/V2/WebSocketClient.swift +++ b/Sources/Realtime/V2/WebSocketClient.swift @@ -18,7 +18,7 @@ protocol WebSocketClientProtocol: Sendable { func send(_ message: RealtimeMessageV2) async throws func receive() -> AsyncThrowingStream - func connect() async + func connect() func cancel() } diff --git a/Tests/RealtimeTests/MockWebSocketClient.swift b/Tests/RealtimeTests/MockWebSocketClient.swift index fe8af38b..9b4125b2 100644 --- a/Tests/RealtimeTests/MockWebSocketClient.swift +++ b/Tests/RealtimeTests/MockWebSocketClient.swift @@ -25,7 +25,7 @@ final class MockWebSocketClient: WebSocketClientProtocol { (status, continuation) = AsyncStream.makeStream() } - func connect() async {} + func connect() {} func send(_ message: RealtimeMessageV2) async throws { mutableState.withValue { @@ -58,4 +58,8 @@ final class MockWebSocketClient: WebSocketClientProtocol { func mockReceive(_ message: RealtimeMessageV2) { mutableState.receiveContinuation?.yield(message) } + + func mockStatus(_ status: WebSocketClient.ConnectionStatus) { + continuation.yield(status) + } } diff --git a/Tests/RealtimeTests/RealtimeTests.swift b/Tests/RealtimeTests/RealtimeTests.swift index e9f641bd..70a41769 100644 --- a/Tests/RealtimeTests/RealtimeTests.swift +++ b/Tests/RealtimeTests/RealtimeTests.swift @@ -14,137 +14,157 @@ final class RealtimeTests: XCTestCase { return "\(ref)" } -// func testConnect() async { -// let mock = MockWebSocketClient() -// -// let realtime = RealtimeClientV2( -// config: RealtimeClientV2.Configuration(url: url, apiKey: apiKey), -// makeWebSocketClient: { _, _ in mock } -// ) -// - //// XCTAssertNoLeak(realtime) -// -// await realtime.connect() -// -// let status = await realtime.status.first(where: { _ in true }) -// XCTAssertEqual(status, .connected) -// } - -// func testChannelSubscription() async throws { -// let mock = MockWebSocketClient() -// -// let realtime = RealtimeClientV2( -// config: RealtimeClientV2.Configuration(url: url, apiKey: apiKey), -// makeWebSocketClient: { _, _ in mock } -// ) -// -// let channel = await realtime.channel("users") -// -// let changes = await channel.postgresChange( -// AnyAction.self, -// table: "users" -// ) -// -// await channel.subscribe() -// -// let receivedPostgresChangeTask = Task { -// await changes -// .compactMap { $0.wrappedAction as? DeleteAction } -// .first { _ in true } -// } -// -// let sentMessages = mock.mutableState.sentMessages -// let expectedJoinMessage = try RealtimeMessageV2( -// joinRef: nil, -// ref: makeRef(), -// topic: "realtime:users", -// event: "phx_join", -// payload: [ -// "config": AnyJSON( -// RealtimeJoinConfig( -// postgresChanges: [ -// .init(event: .all, schema: "public", table: "users", filter: nil), -// ] -// ) -// ), -// ] -// ) -// -// XCTAssertNoDifference(sentMessages, [expectedJoinMessage]) -// -// let currentDate = Date(timeIntervalSince1970: 725552399) -// -// let deleteActionRawMessage = try RealtimeMessageV2( -// joinRef: nil, -// ref: makeRef(), -// topic: "realtime:users", -// event: "postgres_changes", -// payload: [ -// "data": AnyJSON( -// PostgresActionData( -// type: "DELETE", -// record: nil, -// oldRecord: ["email": "mail@example.com"], -// columns: [ -// Column(name: "email", type: "string"), -// ], -// commitTimestamp: currentDate -// ) -// ), -// "ids": [0], -// ] -// ) -// -// let action = DeleteAction( -// columns: [Column(name: "email", type: "string")], -// commitTimestamp: currentDate, -// oldRecord: ["email": "mail@example.com"], -// rawMessage: deleteActionRawMessage -// ) -// -// let postgresChangeReply = RealtimeMessageV2( -// joinRef: nil, -// ref: makeRef(), -// topic: "realtime:users", -// event: "phx_reply", -// payload: [ -// "response": [ -// "postgres_changes": [ -// [ -// "schema": "public", -// "table": "users", -// "filter": nil, -// "event": "*", -// "id": 0, -// ], -// ], -// ], -// "status": "ok", -// ] -// ) -// -// mock.mockReceive(postgresChangeReply) -// mock.mockReceive(deleteActionRawMessage) -// -// let receivedChange = await receivedPostgresChangeTask.value -// XCTAssertNoDifference(receivedChange, action) -// -// await channel.unsubscribe() -// -// mock.mockReceive( -// RealtimeMessageV2( -// joinRef: nil, -// ref: nil, -// topic: "realtime:users", -// event: ChannelEvent.leave, -// payload: [:] -// ) -// ) -// -// await Task.megaYield() -// } + func testConnect() async { + let mock = MockWebSocketClient() + + let realtime = RealtimeClientV2( + config: RealtimeClientV2.Configuration(url: url, apiKey: apiKey), + makeWebSocketClient: { _, _ in mock } + ) + +// XCTAssertNoLeak(realtime) + + Task { + await realtime.connect() + } + + mock.mockStatus(.open) + + await Task.megaYield() + + let status = await realtime.status + XCTAssertEqual(status, .connected) + } + + func testChannelSubscription() async throws { + let mock = MockWebSocketClient() + + let realtime = RealtimeClientV2( + config: RealtimeClientV2.Configuration(url: url, apiKey: apiKey), + makeWebSocketClient: { _, _ in mock } + ) + + let channel = await realtime.channel("users") + + let changes = await channel.postgresChange( + AnyAction.self, + table: "users" + ) + + let task = Task { + await channel.subscribe() + } + + mock.mockStatus(.open) + + await Task.megaYield() + + await task.value + + let receivedPostgresChangeTask = Task { + await changes + .compactMap { $0.wrappedAction as? DeleteAction } + .first { _ in true } + } + + let sentMessages = mock.mutableState.sentMessages + let expectedJoinMessage = try RealtimeMessageV2( + joinRef: nil, + ref: makeRef(), + topic: "realtime:users", + event: "phx_join", + payload: [ + "config": AnyJSON( + RealtimeJoinConfig( + postgresChanges: [ + .init(event: .all, schema: "public", table: "users", filter: nil), + ] + ) + ), + ] + ) + + XCTAssertNoDifference(sentMessages, [expectedJoinMessage]) + + let currentDate = Date(timeIntervalSince1970: 725552399) + + let deleteActionRawMessage = try RealtimeMessageV2( + joinRef: nil, + ref: makeRef(), + topic: "realtime:users", + event: "postgres_changes", + payload: [ + "data": AnyJSON( + PostgresActionData( + type: "DELETE", + record: nil, + oldRecord: ["email": "mail@example.com"], + columns: [ + Column(name: "email", type: "string"), + ], + commitTimestamp: currentDate + ) + ), + "ids": [0], + ] + ) + + let action = DeleteAction( + columns: [Column(name: "email", type: "string")], + commitTimestamp: currentDate, + oldRecord: ["email": "mail@example.com"], + rawMessage: deleteActionRawMessage + ) + + let postgresChangeReply = RealtimeMessageV2( + joinRef: nil, + ref: makeRef(), + topic: "realtime:users", + event: "phx_reply", + payload: [ + "response": [ + "postgres_changes": [ + [ + "schema": "public", + "table": "users", + "filter": nil, + "event": "*", + "id": 0, + ], + ], + ], + "status": "ok", + ] + ) + + mock.mockReceive(postgresChangeReply) + mock.mockReceive(deleteActionRawMessage) + + let receivedChange = await receivedPostgresChangeTask.value + XCTAssertNoDifference(receivedChange, action) + + await channel.unsubscribe() + + mock.mockReceive( + RealtimeMessageV2( + joinRef: nil, + ref: nil, + topic: "realtime:users", + event: ChannelEvent.leave, + payload: [:] + ) + ) + + await Task.megaYield() + } func testHeartbeat() { // TODO: test heartbeat behavior } } + +extension AsyncSequence { + func collect() async rethrows -> [Element] { + try await reduce(into: [Element]()) { $0.append($1) } + } +}