Skip to content

Commit b73ad6b

Browse files
re-port
1 parent ea300e3 commit b73ad6b

2 files changed

Lines changed: 55 additions & 81 deletions

File tree

Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsIntegrationTests.swift

Lines changed: 54 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,51 +3467,40 @@ private struct ObjectsIntegrationTests {
34673467
let counter = try #require(ctx.root.get(key: ctx.sampleCounterKey)?.liveCounterValue)
34683468
let callbacks = 3
34693469
let callbacksCalled = MainActorStorage<[Int]>(value: Array(repeating: 0, count: callbacks))
3470-
3471-
// Create multiple subscribers
3472-
let subscriber0 = Subscriber<LiveCounterUpdate, SubscribeResponse>(callbackQueue: .main)
3473-
let subscriber1 = Subscriber<LiveCounterUpdate, SubscribeResponse>(callbackQueue: .main)
3474-
let subscriber2 = Subscriber<LiveCounterUpdate, SubscribeResponse>(callbackQueue: .main)
3475-
3476-
try counter.subscribe(listener: subscriber0.createListener())
3477-
try counter.subscribe(listener: subscriber1.createListener())
3478-
try counter.subscribe(listener: subscriber2.createListener())
3479-
3480-
// Set up async let promises for each subscriber
3481-
async let subscriptionPromise0: Void = withCheckedContinuation { continuation in
3482-
subscriber0.addListener { _, _ in
3483-
MainActor.assumeIsolated {
3484-
callbacksCalled.value[0] += 1
3485-
continuation.resume()
3486-
}
3487-
}
3488-
}
3489-
3490-
async let subscriptionPromise1: Void = withCheckedContinuation { continuation in
3491-
subscriber1.addListener { _, _ in
3492-
MainActor.assumeIsolated {
3493-
callbacksCalled.value[1] += 1
3494-
continuation.resume()
3495-
}
3496-
}
3470+
3471+
// Create multiple subscribers synchronously
3472+
let subscribers = try (0 ..< callbacks).map { _ in
3473+
let subscriber = Subscriber<LiveCounterUpdate, SubscribeResponse>(callbackQueue: .main)
3474+
try counter.subscribe(listener: subscriber.createListener())
3475+
return subscriber
34973476
}
3498-
3499-
async let subscriptionPromise2: Void = withCheckedContinuation { continuation in
3500-
subscriber2.addListener { _, _ in
3501-
MainActor.assumeIsolated {
3502-
callbacksCalled.value[2] += 1
3503-
continuation.resume()
3477+
3478+
// Set up subscription promises using TaskGroup
3479+
async let subscriptionPromises: Void = withTaskGroup(of: Void.self) { group in
3480+
for (index, subscriber) in subscribers.enumerated() {
3481+
group.addTask {
3482+
await withCheckedContinuation { continuation in
3483+
subscriber.addListener { _, _ in
3484+
MainActor.assumeIsolated {
3485+
callbacksCalled.value[index] += 1
3486+
continuation.resume()
3487+
}
3488+
}
3489+
}
35043490
}
35053491
}
3492+
3493+
// Wait for all subscription tasks to complete
3494+
for await _ in group {}
35063495
}
35073496

35083497
let increments = 3
3509-
for i in 0..<increments {
3498+
for i in 0 ..< increments {
35103499
let counterUpdatesStream = try counter.updates()
35113500
async let counterUpdatedPromise: Void = waitForCounterUpdate(counterUpdatesStream)
35123501
_ = try await ctx.objectsHelper.operationRequest(
35133502
channelName: ctx.channelName,
3514-
opBody: ctx.objectsHelper.counterIncRestOp(objectId: ctx.sampleCounterObjectId, number: 1)
3503+
opBody: ctx.objectsHelper.counterIncRestOp(objectId: ctx.sampleCounterObjectId, number: 1),
35153504
)
35163505
await counterUpdatedPromise
35173506

@@ -3522,12 +3511,10 @@ private struct ObjectsIntegrationTests {
35223511
}
35233512

35243513
// Wait for all subscription promises to complete
3525-
await subscriptionPromise0
3526-
await subscriptionPromise1
3527-
await subscriptionPromise2
3514+
await subscriptionPromises
35283515

35293516
#expect(try counter.value == 3, "Check counter has final expected value after all increments")
3530-
for i in 0..<callbacks {
3517+
for i in 0 ..< callbacks {
35313518
#expect(callbacksCalled.value[i] == 1, "Check subscription callback \(i) was called once")
35323519
}
35333520
},
@@ -3586,55 +3573,44 @@ private struct ObjectsIntegrationTests {
35863573
let map = try #require(ctx.root.get(key: ctx.sampleMapKey)?.liveMapValue)
35873574
let callbacks = 3
35883575
let callbacksCalled = MainActorStorage<[Int]>(value: Array(repeating: 0, count: callbacks))
3589-
3590-
// Create multiple subscribers
3591-
let subscriber0 = Subscriber<LiveMapUpdate, SubscribeResponse>(callbackQueue: .main)
3592-
let subscriber1 = Subscriber<LiveMapUpdate, SubscribeResponse>(callbackQueue: .main)
3593-
let subscriber2 = Subscriber<LiveMapUpdate, SubscribeResponse>(callbackQueue: .main)
3594-
3595-
try map.subscribe(listener: subscriber0.createListener())
3596-
try map.subscribe(listener: subscriber1.createListener())
3597-
try map.subscribe(listener: subscriber2.createListener())
3598-
3599-
// Set up async let promises for each subscriber
3600-
async let subscriptionPromise0: Void = withCheckedContinuation { continuation in
3601-
subscriber0.addListener { _, _ in
3602-
MainActor.assumeIsolated {
3603-
callbacksCalled.value[0] += 1
3604-
continuation.resume()
3605-
}
3606-
}
3607-
}
3608-
3609-
async let subscriptionPromise1: Void = withCheckedContinuation { continuation in
3610-
subscriber1.addListener { _, _ in
3611-
MainActor.assumeIsolated {
3612-
callbacksCalled.value[1] += 1
3613-
continuation.resume()
3614-
}
3615-
}
3576+
3577+
// Create multiple subscribers synchronously
3578+
let subscribers = try (0 ..< callbacks).map { _ in
3579+
let subscriber = Subscriber<LiveMapUpdate, SubscribeResponse>(callbackQueue: .main)
3580+
try map.subscribe(listener: subscriber.createListener())
3581+
return subscriber
36163582
}
3617-
3618-
async let subscriptionPromise2: Void = withCheckedContinuation { continuation in
3619-
subscriber2.addListener { _, _ in
3620-
MainActor.assumeIsolated {
3621-
callbacksCalled.value[2] += 1
3622-
continuation.resume()
3583+
3584+
// Set up subscription promises using TaskGroup
3585+
async let subscriptionPromises: Void = withTaskGroup(of: Void.self) { group in
3586+
for (index, subscriber) in subscribers.enumerated() {
3587+
group.addTask {
3588+
await withCheckedContinuation { continuation in
3589+
subscriber.addListener { _, _ in
3590+
MainActor.assumeIsolated {
3591+
callbacksCalled.value[index] += 1
3592+
continuation.resume()
3593+
}
3594+
}
3595+
}
36233596
}
36243597
}
3598+
3599+
// Wait for all subscription tasks to complete
3600+
for await _ in group {}
36253601
}
36263602

36273603
let mapSets = 3
3628-
for i in 0..<mapSets {
3604+
for i in 0 ..< mapSets {
36293605
let mapUpdatesStream = try map.updates()
36303606
async let mapUpdatedPromise: Void = waitForMapKeyUpdate(mapUpdatesStream, "foo-\(i)")
36313607
_ = try await ctx.objectsHelper.operationRequest(
36323608
channelName: ctx.channelName,
36333609
opBody: ctx.objectsHelper.mapSetRestOp(
36343610
objectId: ctx.sampleMapObjectId,
36353611
key: "foo-\(i)",
3636-
value: ["string": "exists"]
3637-
)
3612+
value: ["string": "exists"],
3613+
),
36383614
)
36393615
await mapUpdatedPromise
36403616

@@ -3645,15 +3621,13 @@ private struct ObjectsIntegrationTests {
36453621
}
36463622

36473623
// Wait for all subscription promises to complete
3648-
await subscriptionPromise0
3649-
await subscriptionPromise1
3650-
await subscriptionPromise2
3624+
await subscriptionPromises
36513625

3652-
for i in 0..<mapSets {
3626+
for i in 0 ..< mapSets {
36533627
let value = try #require(map.get(key: "foo-\(i)")?.stringValue)
36543628
#expect(value == "exists", "Check map has value for key \"foo-\(i)\" after all map sets")
36553629
}
3656-
for i in 0..<callbacks {
3630+
for i in 0 ..< callbacks {
36573631
#expect(callbacksCalled.value[i] == 1, "Check subscription callback \(i) was called once")
36583632
}
36593633
},

prompt-re-port-two-subscription-scenarios.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Begin by creating a TODO list for the remaining tests, then work on this TODO li
2626
Porting a couple of patterns used in the JS tests (see existing examples in ObjectsIntegrationTests.swift):
2727

2828
- a subscription listener that manipulates a local variable stored outside the listener: use a local variable of type MainActorStorage, combined with `MainActor.assumeIsolated` inside the listener
29-
- an `async let` task that waits for a subscription listener to be invoked: create a `Subscriber(callbackQueue: .main)` synchronously (so that no events are missed) and then call `.addListener(:_)` on this `Subscription` inside the `withCheckedContinuation` closure
29+
- an `async let` task that waits for a subscription listener to be invoked: create a `Subscriber(callbackQueue: .main)` synchronously (so that no events are missed) and then call `.addListener(:_)` on this `Subscription` inside the `withCheckedContinuation` closure
3030

3131
## Detailed general requirements for the ported tests
3232

0 commit comments

Comments
 (0)