Skip to content

Commit 6d1c7a9

Browse files
author
Guilherme Souza
committed
test: add test for channel subscribe timeout
1 parent 805c6a0 commit 6d1c7a9

File tree

3 files changed

+121
-24
lines changed

3 files changed

+121
-24
lines changed

Sources/Realtime/V2/PushV2.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ actor PushV2 {
3030
}
3131
}
3232
} catch is TimeoutError {
33+
channel?.logger?.debug("Push timed out.")
3334
return .timeout
3435
} catch {
35-
channel?.logger?.error("error sending Push: \(error)")
36+
channel?.logger?.error("Error sending push: \(error)")
3637
return .error
3738
}
3839
}

Sources/Realtime/V2/RealtimeChannelV2.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,18 @@ public actor RealtimeChannelV2 {
106106
)
107107
)
108108

109-
_ = await statusChange.first { @Sendable in $0 == .subscribed }
109+
do {
110+
try await withTimeout(interval: socket?.config.timeoutInterval ?? 10) { [self] in
111+
_ = await statusChange.first { @Sendable in $0 == .subscribed }
112+
}
113+
} catch {
114+
if error is TimeoutError {
115+
logger?.debug("subscribe timed out.")
116+
await subscribe()
117+
} else {
118+
logger?.error("subscribe failed: \(error)")
119+
}
120+
}
110121
}
111122

112123
public func unsubscribe() async {

Tests/RealtimeTests/RealtimeTests.swift

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ final class RealtimeTests: XCTestCase {
2727
url: url,
2828
apiKey: apiKey,
2929
heartbeatInterval: 1,
30-
reconnectDelay: 1
30+
reconnectDelay: 1,
31+
timeoutInterval: 2,
32+
logger: TestLogger()
3133
),
3234
ws: ws
3335
)
@@ -62,10 +64,85 @@ final class RealtimeTests: XCTestCase {
6264
// Wait until channel subscribed
6365
await subscription.value
6466

65-
XCTAssertNoDifference(ws.sentMessages.value, [.subscribeToMessages])
67+
XCTAssertNoDifference(ws.sentMessages.value, [.subscribeToMessages(ref: "1", joinRef: "1")])
6668
}
6769
}
6870

71+
func testSubscribeTimeout() async throws {
72+
let channel = await sut.channel("public:messages")
73+
let joinEventCount = LockIsolated(0)
74+
75+
ws.on { message in
76+
if message.event == "heartbeat" {
77+
return RealtimeMessageV2(
78+
joinRef: message.joinRef,
79+
ref: message.ref,
80+
topic: "phoenix",
81+
event: "phx_reply",
82+
payload: [
83+
"response": [:],
84+
"status": "ok",
85+
]
86+
)
87+
}
88+
89+
if message.event == "phx_join" {
90+
joinEventCount.withValue { $0 += 1 }
91+
92+
// Skip first join.
93+
if joinEventCount.value == 2 {
94+
return .messagesSubscribed
95+
}
96+
}
97+
98+
return nil
99+
}
100+
101+
await connectSocketAndWait()
102+
103+
Task {
104+
await channel.subscribe()
105+
}
106+
107+
await Task.megaYield()
108+
109+
try? await Task.sleep(nanoseconds: NSEC_PER_SEC * 2)
110+
111+
let joinSentMessages = ws.sentMessages.value.filter { $0.event == "phx_join" }
112+
113+
let expectedMessages = try [
114+
RealtimeMessageV2(
115+
joinRef: "1",
116+
ref: "1",
117+
topic: "realtime:public:messages",
118+
event: "phx_join",
119+
payload: JSONObject(
120+
RealtimeJoinPayload(
121+
config: RealtimeJoinConfig(),
122+
accessToken: apiKey
123+
)
124+
)
125+
),
126+
RealtimeMessageV2(
127+
joinRef: "3",
128+
ref: "3",
129+
topic: "realtime:public:messages",
130+
event: "phx_join",
131+
payload: JSONObject(
132+
RealtimeJoinPayload(
133+
config: RealtimeJoinConfig(),
134+
accessToken: apiKey
135+
)
136+
)
137+
),
138+
]
139+
140+
XCTAssertNoDifference(
141+
joinSentMessages,
142+
expectedMessages
143+
)
144+
}
145+
69146
func testHeartbeat() async throws {
70147
try await withTimeout(interval: 4) { [self] in
71148
let expectation = expectation(description: "heartbeat")
@@ -155,27 +232,29 @@ final class RealtimeTests: XCTestCase {
155232
}
156233

157234
extension RealtimeMessageV2 {
158-
static let subscribeToMessages = Self(
159-
joinRef: "1",
160-
ref: "1",
161-
topic: "realtime:public:messages",
162-
event: "phx_join",
163-
payload: [
164-
"access_token": "anon.api.key",
165-
"config": [
166-
"broadcast": [
167-
"self": false,
168-
"ack": false,
169-
],
170-
"postgres_changes": [
171-
["table": "messages", "event": "INSERT", "schema": "public"],
172-
["table": "messages", "schema": "public", "event": "UPDATE"],
173-
["schema": "public", "table": "messages", "event": "DELETE"],
235+
static func subscribeToMessages(ref: String?, joinRef: String?) -> RealtimeMessageV2 {
236+
Self(
237+
joinRef: joinRef,
238+
ref: ref,
239+
topic: "realtime:public:messages",
240+
event: "phx_join",
241+
payload: [
242+
"access_token": "anon.api.key",
243+
"config": [
244+
"broadcast": [
245+
"self": false,
246+
"ack": false,
247+
],
248+
"postgres_changes": [
249+
["table": "messages", "event": "INSERT", "schema": "public"],
250+
["table": "messages", "schema": "public", "event": "UPDATE"],
251+
["schema": "public", "table": "messages", "event": "DELETE"],
252+
],
253+
"presence": ["key": ""],
174254
],
175-
"presence": ["key": ""],
176-
],
177-
]
178-
)
255+
]
256+
)
257+
}
179258

180259
static let messagesSubscribed = Self(
181260
joinRef: nil,
@@ -205,3 +284,9 @@ extension RealtimeMessageV2 {
205284
]
206285
)
207286
}
287+
288+
struct TestLogger: SupabaseLogger {
289+
func log(message: SupabaseLogMessage) {
290+
print(message.description)
291+
}
292+
}

0 commit comments

Comments
 (0)