Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7d6870f

Browse files
authoredMay 28, 2025··
fix(realtime): make Push associated to MainActor (#721)
* fix(realtime): make Push associated to MainActor * code format * skip test in Linux
1 parent 899e2e5 commit 7d6870f

File tree

4 files changed

+300
-306
lines changed

4 files changed

+300
-306
lines changed
 

‎Sources/Realtime/PushV2.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public enum PushStatus: String, Sendable {
1515
case timeout
1616
}
1717

18-
actor PushV2 {
18+
@MainActor
19+
final class PushV2 {
1920
private weak var channel: RealtimeChannelV2?
2021
let message: RealtimeMessageV2
2122

‎Sources/Realtime/RealtimeChannelV2.swift

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ public final class RealtimeChannelV2: Sendable {
3232
var pushes: [String: PushV2] = [:]
3333
}
3434

35-
private let mutableState = LockIsolated(MutableState())
35+
@MainActor
36+
private var mutableState = MutableState()
3637

3738
let topic: String
3839
let config: RealtimeChannelConfig
3940
let logger: (any SupabaseLogger)?
4041
let socket: RealtimeClientV2
41-
var joinRef: String? { mutableState.joinRef }
42+
43+
@MainActor var joinRef: String? { mutableState.joinRef }
4244

4345
let callbackManager = CallbackManager()
4446
private let statusSubject = AsyncValueSubject<RealtimeChannelStatus>(.unsubscribed)
@@ -81,6 +83,7 @@ public final class RealtimeChannelV2: Sendable {
8183
}
8284

8385
/// Subscribes to the channel
86+
@MainActor
8487
public func subscribe() async {
8588
if socket.status != .connected {
8689
if socket.options.connectOnSubscribe != true {
@@ -109,7 +112,7 @@ public final class RealtimeChannelV2: Sendable {
109112
)
110113

111114
let joinRef = socket.makeRef()
112-
mutableState.withValue { $0.joinRef = joinRef }
115+
mutableState.joinRef = joinRef
113116

114117
logger?.debug("Subscribing to channel with body: \(joinConfig)")
115118

@@ -497,8 +500,8 @@ public final class RealtimeChannelV2: Sendable {
497500
filter: filter
498501
)
499502

500-
mutableState.withValue {
501-
$0.clientChanges.append(config)
503+
Task { @MainActor in
504+
mutableState.clientChanges.append(config)
502505
}
503506

504507
let id = callbackManager.addPostgresCallback(filter: config, callback: callback)
@@ -538,32 +541,28 @@ public final class RealtimeChannelV2: Sendable {
538541
self.onSystem { _ in callback() }
539542
}
540543

544+
@MainActor
541545
@discardableResult
542546
func push(_ event: String, ref: String? = nil, payload: JSONObject = [:]) async -> PushStatus {
543-
let push = mutableState.withValue {
544-
let message = RealtimeMessageV2(
545-
joinRef: $0.joinRef,
546-
ref: ref ?? socket.makeRef(),
547-
topic: self.topic,
548-
event: event,
549-
payload: payload
550-
)
551-
552-
let push = PushV2(channel: self, message: message)
553-
if let ref = message.ref {
554-
$0.pushes[ref] = push
555-
}
547+
let message = RealtimeMessageV2(
548+
joinRef: joinRef,
549+
ref: ref ?? socket.makeRef(),
550+
topic: self.topic,
551+
event: event,
552+
payload: payload
553+
)
556554

557-
return push
555+
let push = PushV2(channel: self, message: message)
556+
if let ref = message.ref {
557+
mutableState.pushes[ref] = push
558558
}
559559

560560
return await push.send()
561561
}
562562

563-
private func didReceiveReply(ref: String, status: String) async {
564-
let push = mutableState.withValue {
565-
$0.pushes.removeValue(forKey: ref)
566-
}
567-
await push?.didReceive(status: PushStatus(rawValue: status) ?? .ok)
563+
@MainActor
564+
private func didReceiveReply(ref: String, status: String) {
565+
let push = mutableState.pushes.removeValue(forKey: ref)
566+
push?.didReceive(status: PushStatus(rawValue: status) ?? .ok)
568567
}
569568
}

‎Tests/IntegrationTests/RealtimeIntegrationTests.swift

Lines changed: 202 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -24,247 +24,247 @@ struct TestLogger: SupabaseLogger {
2424
}
2525

2626
#if !os(Android) && !os(Linux)
27-
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
28-
final class RealtimeIntegrationTests: XCTestCase {
27+
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
28+
final class RealtimeIntegrationTests: XCTestCase {
2929

30-
let testClock = TestClock<Duration>()
30+
let testClock = TestClock<Duration>()
3131

32-
let client = SupabaseClient(
33-
supabaseURL: URL(string: DotEnv.SUPABASE_URL) ?? URL(string: "http://localhost:54321")!,
34-
supabaseKey: DotEnv.SUPABASE_ANON_KEY
35-
)
36-
37-
override func setUp() {
38-
super.setUp()
32+
let client = SupabaseClient(
33+
supabaseURL: URL(string: DotEnv.SUPABASE_URL) ?? URL(string: "http://localhost:54321")!,
34+
supabaseKey: DotEnv.SUPABASE_ANON_KEY
35+
)
3936

40-
_clock = testClock
41-
}
37+
override func setUp() {
38+
super.setUp()
4239

43-
#if !os(Windows) && !os(Linux) && !os(Android)
44-
override func invokeTest() {
45-
withMainSerialExecutor {
46-
super.invokeTest()
40+
_clock = testClock
4741
}
48-
}
49-
#endif
5042

51-
func testDisconnectByUser_shouldNotReconnect() async {
52-
await client.realtimeV2.connect()
53-
let status: RealtimeClientStatus = client.realtimeV2.status
54-
XCTAssertEqual(status, .connected)
43+
#if !os(Windows) && !os(Linux) && !os(Android)
44+
override func invokeTest() {
45+
withMainSerialExecutor {
46+
super.invokeTest()
47+
}
48+
}
49+
#endif
5550

56-
client.realtimeV2.disconnect()
51+
func testDisconnectByUser_shouldNotReconnect() async {
52+
await client.realtimeV2.connect()
53+
let status: RealtimeClientStatus = client.realtimeV2.status
54+
XCTAssertEqual(status, .connected)
5755

58-
/// Wait for the reconnection delay
59-
await testClock.advance(by: .seconds(RealtimeClientOptions.defaultReconnectDelay))
56+
client.realtimeV2.disconnect()
6057

61-
XCTAssertEqual(client.realtimeV2.status, .disconnected)
62-
}
58+
/// Wait for the reconnection delay
59+
await testClock.advance(by: .seconds(RealtimeClientOptions.defaultReconnectDelay))
6360

64-
func testBroadcast() async throws {
65-
let channel = client.realtimeV2.channel("integration") {
66-
$0.broadcast.receiveOwnBroadcasts = true
61+
XCTAssertEqual(client.realtimeV2.status, .disconnected)
6762
}
6863

69-
let receivedMessagesTask = Task {
70-
await channel.broadcastStream(event: "test").prefix(3).collect()
71-
}
64+
func testBroadcast() async throws {
65+
let channel = client.realtimeV2.channel("integration") {
66+
$0.broadcast.receiveOwnBroadcasts = true
67+
}
7268

73-
await Task.yield()
69+
let receivedMessagesTask = Task {
70+
await channel.broadcastStream(event: "test").prefix(3).collect()
71+
}
7472

75-
await channel.subscribe()
73+
await Task.yield()
7674

77-
struct Message: Codable {
78-
var value: Int
79-
}
75+
await channel.subscribe()
8076

81-
try await channel.broadcast(event: "test", message: Message(value: 1))
82-
try await channel.broadcast(event: "test", message: Message(value: 2))
83-
try await channel.broadcast(event: "test", message: ["value": 3, "another_value": 42])
77+
struct Message: Codable {
78+
var value: Int
79+
}
8480

85-
let receivedMessages = try await withTimeout(interval: 5) {
86-
await receivedMessagesTask.value
87-
}
81+
try await channel.broadcast(event: "test", message: Message(value: 1))
82+
try await channel.broadcast(event: "test", message: Message(value: 2))
83+
try await channel.broadcast(event: "test", message: ["value": 3, "another_value": 42])
8884

89-
assertInlineSnapshot(of: receivedMessages, as: .json) {
90-
"""
91-
[
92-
{
93-
"event" : "test",
94-
"payload" : {
95-
"value" : 1
96-
},
97-
"type" : "broadcast"
98-
},
99-
{
100-
"event" : "test",
101-
"payload" : {
102-
"value" : 2
85+
let receivedMessages = try await withTimeout(interval: 5) {
86+
await receivedMessagesTask.value
87+
}
88+
89+
assertInlineSnapshot(of: receivedMessages, as: .json) {
90+
"""
91+
[
92+
{
93+
"event" : "test",
94+
"payload" : {
95+
"value" : 1
96+
},
97+
"type" : "broadcast"
10398
},
104-
"type" : "broadcast"
105-
},
106-
{
107-
"event" : "test",
108-
"payload" : {
109-
"another_value" : 42,
110-
"value" : 3
99+
{
100+
"event" : "test",
101+
"payload" : {
102+
"value" : 2
103+
},
104+
"type" : "broadcast"
111105
},
112-
"type" : "broadcast"
113-
}
114-
]
115-
"""
116-
}
117-
118-
await channel.unsubscribe()
119-
}
120-
121-
func testBroadcastWithUnsubscribedChannel() async throws {
122-
let channel = client.realtimeV2.channel("integration") {
123-
$0.broadcast.acknowledgeBroadcasts = true
124-
}
125-
126-
struct Message: Codable {
127-
var value: Int
128-
}
129-
130-
try await channel.broadcast(event: "test", message: Message(value: 1))
131-
try await channel.broadcast(event: "test", message: Message(value: 2))
132-
try await channel.broadcast(event: "test", message: ["value": 3, "another_value": 42])
133-
}
134-
135-
func testPresence() async throws {
136-
let channel = client.realtimeV2.channel("integration") {
137-
$0.broadcast.receiveOwnBroadcasts = true
138-
}
139-
140-
let receivedPresenceChangesTask = Task {
141-
await channel.presenceChange().prefix(4).collect()
106+
{
107+
"event" : "test",
108+
"payload" : {
109+
"another_value" : 42,
110+
"value" : 3
111+
},
112+
"type" : "broadcast"
113+
}
114+
]
115+
"""
116+
}
117+
118+
await channel.unsubscribe()
142119
}
143120

144-
await Task.yield()
121+
func testBroadcastWithUnsubscribedChannel() async throws {
122+
let channel = client.realtimeV2.channel("integration") {
123+
$0.broadcast.acknowledgeBroadcasts = true
124+
}
145125

146-
await channel.subscribe()
126+
struct Message: Codable {
127+
var value: Int
128+
}
147129

148-
struct UserState: Codable, Equatable {
149-
let email: String
130+
try await channel.broadcast(event: "test", message: Message(value: 1))
131+
try await channel.broadcast(event: "test", message: Message(value: 2))
132+
try await channel.broadcast(event: "test", message: ["value": 3, "another_value": 42])
150133
}
151134

152-
try await channel.track(UserState(email: "test@supabase.com"))
153-
try await channel.track(["email": "test2@supabase.com"])
135+
func testPresence() async throws {
136+
let channel = client.realtimeV2.channel("integration") {
137+
$0.broadcast.receiveOwnBroadcasts = true
138+
}
154139

155-
await channel.untrack()
140+
let receivedPresenceChangesTask = Task {
141+
await channel.presenceChange().prefix(4).collect()
142+
}
156143

157-
let receivedPresenceChanges = try await withTimeout(interval: 5) {
158-
await receivedPresenceChangesTask.value
159-
}
160-
161-
let joins = try receivedPresenceChanges.map { try $0.decodeJoins(as: UserState.self) }
162-
let leaves = try receivedPresenceChanges.map { try $0.decodeLeaves(as: UserState.self) }
163-
expectNoDifference(
164-
joins,
165-
[
166-
[], // This is the first PRESENCE_STATE event.
167-
[UserState(email: "test@supabase.com")],
168-
[UserState(email: "test2@supabase.com")],
169-
[],
170-
]
171-
)
172-
173-
expectNoDifference(
174-
leaves,
175-
[
176-
[], // This is the first PRESENCE_STATE event.
177-
[],
178-
[UserState(email: "test@supabase.com")],
179-
[UserState(email: "test2@supabase.com")],
180-
]
181-
)
182-
183-
await channel.unsubscribe()
184-
}
185-
186-
func testPostgresChanges() async throws {
187-
let channel = client.realtimeV2.channel("db-changes")
188-
189-
let receivedInsertActions = Task {
190-
await channel.postgresChange(InsertAction.self, schema: "public").prefix(1).collect()
191-
}
144+
await Task.yield()
192145

193-
let receivedUpdateActions = Task {
194-
await channel.postgresChange(UpdateAction.self, schema: "public").prefix(1).collect()
195-
}
146+
await channel.subscribe()
196147

197-
let receivedDeleteActions = Task {
198-
await channel.postgresChange(DeleteAction.self, schema: "public").prefix(1).collect()
199-
}
148+
struct UserState: Codable, Equatable {
149+
let email: String
150+
}
200151

201-
let receivedAnyActionsTask = Task {
202-
await channel.postgresChange(AnyAction.self, schema: "public").prefix(3).collect()
203-
}
152+
try await channel.track(UserState(email: "test@supabase.com"))
153+
try await channel.track(["email": "test2@supabase.com"])
204154

205-
await Task.yield()
206-
await channel.subscribe()
155+
await channel.untrack()
207156

208-
struct Entry: Codable, Equatable {
209-
let key: String
210-
let value: AnyJSON
211-
}
157+
let receivedPresenceChanges = try await withTimeout(interval: 5) {
158+
await receivedPresenceChangesTask.value
159+
}
212160

213-
// Wait until a system event for makind sure DB change listeners are set before making DB changes.
214-
_ = await channel.system().first(where: { _ in true })
215-
216-
let key = try await
217-
(client.from("key_value_storage")
218-
.insert(["key": AnyJSON.string(UUID().uuidString), "value": "value1"]).select().single()
219-
.execute().value as Entry).key
220-
try await client.from("key_value_storage").update(["value": "value2"]).eq("key", value: key)
221-
.execute()
222-
try await client.from("key_value_storage").delete().eq("key", value: key).execute()
223-
224-
let insertedEntries = try await receivedInsertActions.value.map {
225-
try $0.decodeRecord(
226-
as: Entry.self,
227-
decoder: JSONDecoder()
228-
)
229-
}
230-
let updatedEntries = try await receivedUpdateActions.value.map {
231-
try $0.decodeRecord(
232-
as: Entry.self,
233-
decoder: JSONDecoder()
161+
let joins = try receivedPresenceChanges.map { try $0.decodeJoins(as: UserState.self) }
162+
let leaves = try receivedPresenceChanges.map { try $0.decodeLeaves(as: UserState.self) }
163+
expectNoDifference(
164+
joins,
165+
[
166+
[], // This is the first PRESENCE_STATE event.
167+
[UserState(email: "test@supabase.com")],
168+
[UserState(email: "test2@supabase.com")],
169+
[],
170+
]
234171
)
235-
}
236-
let deletedEntryIds = await receivedDeleteActions.value.compactMap {
237-
$0.oldRecord["key"]?.stringValue
238-
}
239172

240-
expectNoDifference(insertedEntries, [Entry(key: key, value: "value1")])
241-
expectNoDifference(updatedEntries, [Entry(key: key, value: "value2")])
242-
expectNoDifference(deletedEntryIds, [key])
243-
244-
let receivedAnyActions = await receivedAnyActionsTask.value
245-
XCTAssertEqual(receivedAnyActions.count, 3)
246-
247-
if case let .insert(action) = receivedAnyActions[0] {
248-
let record = try action.decodeRecord(as: Entry.self, decoder: JSONDecoder())
249-
expectNoDifference(record, Entry(key: key, value: "value1"))
250-
} else {
251-
XCTFail("Expected a `AnyAction.insert` on `receivedAnyActions[0]`")
252-
}
173+
expectNoDifference(
174+
leaves,
175+
[
176+
[], // This is the first PRESENCE_STATE event.
177+
[],
178+
[UserState(email: "test@supabase.com")],
179+
[UserState(email: "test2@supabase.com")],
180+
]
181+
)
253182

254-
if case let .update(action) = receivedAnyActions[1] {
255-
let record = try action.decodeRecord(as: Entry.self, decoder: JSONDecoder())
256-
expectNoDifference(record, Entry(key: key, value: "value2"))
257-
} else {
258-
XCTFail("Expected a `AnyAction.update` on `receivedAnyActions[1]`")
183+
await channel.unsubscribe()
259184
}
260185

261-
if case let .delete(action) = receivedAnyActions[2] {
262-
expectNoDifference(key, action.oldRecord["key"]?.stringValue)
263-
} else {
264-
XCTFail("Expected a `AnyAction.delete` on `receivedAnyActions[2]`")
186+
func testPostgresChanges() async throws {
187+
let channel = client.realtimeV2.channel("db-changes")
188+
189+
let receivedInsertActions = Task {
190+
await channel.postgresChange(InsertAction.self, schema: "public").prefix(1).collect()
191+
}
192+
193+
let receivedUpdateActions = Task {
194+
await channel.postgresChange(UpdateAction.self, schema: "public").prefix(1).collect()
195+
}
196+
197+
let receivedDeleteActions = Task {
198+
await channel.postgresChange(DeleteAction.self, schema: "public").prefix(1).collect()
199+
}
200+
201+
let receivedAnyActionsTask = Task {
202+
await channel.postgresChange(AnyAction.self, schema: "public").prefix(3).collect()
203+
}
204+
205+
await Task.yield()
206+
await channel.subscribe()
207+
208+
struct Entry: Codable, Equatable {
209+
let key: String
210+
let value: AnyJSON
211+
}
212+
213+
// Wait until a system event for makind sure DB change listeners are set before making DB changes.
214+
_ = await channel.system().first(where: { _ in true })
215+
216+
let key = try await
217+
(client.from("key_value_storage")
218+
.insert(["key": AnyJSON.string(UUID().uuidString), "value": "value1"]).select().single()
219+
.execute().value as Entry).key
220+
try await client.from("key_value_storage").update(["value": "value2"]).eq("key", value: key)
221+
.execute()
222+
try await client.from("key_value_storage").delete().eq("key", value: key).execute()
223+
224+
let insertedEntries = try await receivedInsertActions.value.map {
225+
try $0.decodeRecord(
226+
as: Entry.self,
227+
decoder: JSONDecoder()
228+
)
229+
}
230+
let updatedEntries = try await receivedUpdateActions.value.map {
231+
try $0.decodeRecord(
232+
as: Entry.self,
233+
decoder: JSONDecoder()
234+
)
235+
}
236+
let deletedEntryIds = await receivedDeleteActions.value.compactMap {
237+
$0.oldRecord["key"]?.stringValue
238+
}
239+
240+
expectNoDifference(insertedEntries, [Entry(key: key, value: "value1")])
241+
expectNoDifference(updatedEntries, [Entry(key: key, value: "value2")])
242+
expectNoDifference(deletedEntryIds, [key])
243+
244+
let receivedAnyActions = await receivedAnyActionsTask.value
245+
XCTAssertEqual(receivedAnyActions.count, 3)
246+
247+
if case let .insert(action) = receivedAnyActions[0] {
248+
let record = try action.decodeRecord(as: Entry.self, decoder: JSONDecoder())
249+
expectNoDifference(record, Entry(key: key, value: "value1"))
250+
} else {
251+
XCTFail("Expected a `AnyAction.insert` on `receivedAnyActions[0]`")
252+
}
253+
254+
if case let .update(action) = receivedAnyActions[1] {
255+
let record = try action.decodeRecord(as: Entry.self, decoder: JSONDecoder())
256+
expectNoDifference(record, Entry(key: key, value: "value2"))
257+
} else {
258+
XCTFail("Expected a `AnyAction.update` on `receivedAnyActions[1]`")
259+
}
260+
261+
if case let .delete(action) = receivedAnyActions[2] {
262+
expectNoDifference(key, action.oldRecord["key"]?.stringValue)
263+
} else {
264+
XCTFail("Expected a `AnyAction.delete` on `receivedAnyActions[2]`")
265+
}
266+
267+
await channel.unsubscribe()
265268
}
266-
267-
await channel.unsubscribe()
268269
}
269-
}
270270
#endif

‎Tests/RealtimeTests/_PushTests.swift

Lines changed: 73 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -12,91 +12,85 @@ import XCTest
1212

1313
@testable import Realtime
1414

15-
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
16-
final class _PushTests: XCTestCase {
17-
var ws: FakeWebSocket!
18-
var socket: RealtimeClientV2!
15+
#if !os(Android) && !os(Linux) && !os(Windows)
16+
@MainActor
17+
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
18+
final class _PushTests: XCTestCase {
19+
var ws: FakeWebSocket!
20+
var socket: RealtimeClientV2!
1921

20-
#if !os(Windows) && !os(Linux) && !os(Android)
21-
override func invokeTest() {
22-
withMainSerialExecutor {
23-
super.invokeTest()
24-
}
25-
}
26-
#endif
22+
override func setUp() {
23+
super.setUp()
2724

28-
override func setUp() {
29-
super.setUp()
25+
let (client, server) = FakeWebSocket.fakes()
26+
ws = server
3027

31-
let (client, server) = FakeWebSocket.fakes()
32-
ws = server
28+
socket = RealtimeClientV2(
29+
url: URL(string: "https://localhost:54321/v1/realtime")!,
30+
options: RealtimeClientOptions(
31+
headers: ["apiKey": "apikey"]
32+
),
33+
wsTransport: { _, _ in client },
34+
http: HTTPClientMock()
35+
)
36+
}
3337

34-
socket = RealtimeClientV2(
35-
url: URL(string: "https://localhost:54321/v1/realtime")!,
36-
options: RealtimeClientOptions(
37-
headers: ["apiKey": "apikey"]
38-
),
39-
wsTransport: { _, _ in client },
40-
http: HTTPClientMock()
41-
)
42-
}
38+
func testPushWithoutAck() async {
39+
let channel = RealtimeChannelV2(
40+
topic: "realtime:users",
41+
config: RealtimeChannelConfig(
42+
broadcast: .init(acknowledgeBroadcasts: false),
43+
presence: .init(),
44+
isPrivate: false
45+
),
46+
socket: socket,
47+
logger: nil
48+
)
49+
let push = PushV2(
50+
channel: channel,
51+
message: RealtimeMessageV2(
52+
joinRef: nil,
53+
ref: "1",
54+
topic: "realtime:users",
55+
event: "broadcast",
56+
payload: [:]
57+
)
58+
)
59+
60+
let status = await push.send()
61+
XCTAssertEqual(status, .ok)
62+
}
4363

44-
func testPushWithoutAck() async {
45-
let channel = RealtimeChannelV2(
46-
topic: "realtime:users",
47-
config: RealtimeChannelConfig(
48-
broadcast: .init(acknowledgeBroadcasts: false),
49-
presence: .init(),
50-
isPrivate: false
51-
),
52-
socket: socket,
53-
logger: nil
54-
)
55-
let push = PushV2(
56-
channel: channel,
57-
message: RealtimeMessageV2(
58-
joinRef: nil,
59-
ref: "1",
64+
func testPushWithAck() async {
65+
let channel = RealtimeChannelV2(
6066
topic: "realtime:users",
61-
event: "broadcast",
62-
payload: [:]
67+
config: RealtimeChannelConfig(
68+
broadcast: .init(acknowledgeBroadcasts: true),
69+
presence: .init(),
70+
isPrivate: false
71+
),
72+
socket: socket,
73+
logger: nil
74+
)
75+
let push = PushV2(
76+
channel: channel,
77+
message: RealtimeMessageV2(
78+
joinRef: nil,
79+
ref: "1",
80+
topic: "realtime:users",
81+
event: "broadcast",
82+
payload: [:]
83+
)
6384
)
64-
)
6585

66-
let status = await push.send()
67-
XCTAssertEqual(status, .ok)
68-
}
86+
let task = Task {
87+
await push.send()
88+
}
89+
await Task.megaYield()
90+
push.didReceive(status: .ok)
6991

70-
// FIXME: Flaky test, it fails some time due the task scheduling, even tho we're using withMainSerialExecutor.
71-
// func testPushWithAck() async {
72-
// let channel = RealtimeChannelV2(
73-
// topic: "realtime:users",
74-
// config: RealtimeChannelConfig(
75-
// broadcast: .init(acknowledgeBroadcasts: true),
76-
// presence: .init(),
77-
// isPrivate: false
78-
// ),
79-
// socket: Socket(client: socket),
80-
// logger: nil
81-
// )
82-
// let push = PushV2(
83-
// channel: channel,
84-
// message: RealtimeMessageV2(
85-
// joinRef: nil,
86-
// ref: "1",
87-
// topic: "realtime:users",
88-
// event: "broadcast",
89-
// payload: [:]
90-
// )
91-
// )
92-
//
93-
// let task = Task {
94-
// await push.send()
95-
// }
96-
// await Task.yield()
97-
// await push.didReceive(status: .ok)
98-
//
99-
// let status = await task.value
100-
// XCTAssertEqual(status, .ok)
101-
// }
102-
}
92+
let status = await task.value
93+
XCTAssertEqual(status, .ok)
94+
}
95+
}
96+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.