test: migrate RealtimeTests to Swift Testing (Phase 7)#1141
Conversation
Converts every XCTest suite in Tests/RealtimeTests to Swift Testing (@Suite/@test, #expect/#require, Issue.record), per SDK-435 phase 7 (SDK-1254). - Replaces XCTestExpectation/fulfillment(of:timeout:) with a shared `waitUntil` polling helper (Tests/RealtimeTests/TestSupport.swift), since Swift Testing has no direct async-condition-with-timeout primitive. - Preserves `withMainSerialExecutor` usage in RealtimeTests.swift, now applied per-test-body with `@Suite(.serialized)` to keep the process-global executor flag from racing across concurrently running tests. - Converts XCTestCase setUp/tearDown to struct/class init()/deinit, keeping class-based suites (with explicit `sut.disconnect()` in deinit) where teardown must run background-task cancellation, not just ARC release. - Serializes WebSocketTests (`@Suite(.serialized)`): its cert-pinning tests import self-signed identities via SecPKCS12Import, which is flaky when several tests run concurrently (Swift Testing's default parallel execution, vs. XCTest's serial method execution). - Converts completion-handler-based challenge-forwarding tests to `confirmation(_:)`. - Adds "RealtimeTests" to Package.swift's swift6TestTargets now that the target is fully migrated. Behavior, coverage, and assertions are unchanged; only the test framework and incidental concurrency helpers differ.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe Realtime test target is migrated from XCTest to Swift Testing using Possibly related PRs
Suggested labels: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The following capabilities are marked
These may have been renamed, removed, or never registered. Please update the capability matrix. |
- WebSocketTests: mark local delegate test doubles @unchecked Sendable to satisfy Sendable-conforming URLSessionDelegate/URLSessionTaskDelegate under strict concurrency (compile error on all xcodebuild jobs) - ConnectionManagerTests: replace fixed 50ms sleep with waitUntil poll to avoid a race under parallel Swift Testing execution (flaky on Linux CI) - dictionary: add 'deinits' for cspell
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Tests/RealtimeTests/RealtimeChannelTests.swift`:
- Around line 929-944: Update the `@MainActor` Testing_waitUntil helper to perform
one final condition() check after the polling loop reaches its deadline,
matching the shared waitUntil behavior. Preserve the existing polling and
timeout flow, and return successfully if the condition becomes true at the
boundary or immediately after the loop.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 8dbe8404-0b2b-4cfb-bfa1-1d2321106f48
📒 Files selected for processing (23)
Package.swiftTests/RealtimeTests/CallbackManagerTests.swiftTests/RealtimeTests/ChannelStateManagerTests.swiftTests/RealtimeTests/ConnectionManagerTests.swiftTests/RealtimeTests/ExportsTests.swiftTests/RealtimeTests/PostgresActionTests.swiftTests/RealtimeTests/PostgresJoinConfigTests.swiftTests/RealtimeTests/PresenceActionTests.swiftTests/RealtimeTests/PushV2Tests.swiftTests/RealtimeTests/RealtimeChannelBroadcastTests.swiftTests/RealtimeTests/RealtimeChannelTests.swiftTests/RealtimeTests/RealtimeColdStartTests.swiftTests/RealtimeTests/RealtimeErrorTests.swiftTests/RealtimeTests/RealtimeJoinConfigTests.swiftTests/RealtimeTests/RealtimeLifecycleTests.swiftTests/RealtimeTests/RealtimeMessageV2Tests.swiftTests/RealtimeTests/RealtimePostgresFilterTests.swiftTests/RealtimeTests/RealtimePostgresFilterValueTests.swiftTests/RealtimeTests/RealtimeSerializerTests.swiftTests/RealtimeTests/RealtimeTests.swiftTests/RealtimeTests/TestSupport.swiftTests/RealtimeTests/WebSocketTests.swiftTests/RealtimeTests/_PushTests.swift
|
|
||
| /// `@MainActor`-safe wrapper around the shared, non-isolated `waitUntil` helper — | ||
| /// avoids a "passing a `@MainActor`-isolated closure as a `@Sendable` closure" diagnostic | ||
| /// when the condition captures main-actor-isolated state (e.g. `RealtimeChannelV2.status`). | ||
| @MainActor | ||
| private func Testing_waitUntil( | ||
| timeout: TimeInterval, | ||
| pollInterval: UInt64, | ||
| condition: @MainActor @escaping () -> Bool | ||
| ) async { | ||
| let deadline = Date().addingTimeInterval(timeout) | ||
| while Date() < deadline { | ||
| if condition() { return } | ||
| try? await Task.sleep(nanoseconds: pollInterval) | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Missing final check in Testing_waitUntil can cause flaky failures.
Unlike the shared waitUntil helper (Tests/RealtimeTests/TestSupport.swift), this loop returns without re-checking condition() once the deadline passes. On slow CI, a status change landing right at/after the deadline boundary will be missed, and the subsequent #expect (e.g. in waitForChannelStatus) will fail spuriously.
🔧 Proposed fix
`@MainActor`
private func Testing_waitUntil(
timeout: TimeInterval,
pollInterval: UInt64,
condition: `@MainActor` `@escaping` () -> Bool
) async {
let deadline = Date().addingTimeInterval(timeout)
while Date() < deadline {
if condition() { return }
try? await Task.sleep(nanoseconds: pollInterval)
}
+ _ = condition()
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Tests/RealtimeTests/RealtimeChannelTests.swift` around lines 929 - 944,
Update the `@MainActor` Testing_waitUntil helper to perform one final condition()
check after the polling loop reaches its deadline, matching the shared waitUntil
behavior. Preserve the existing polling and timeout flow, and return
successfully if the condition becomes true at the boundary or immediately after
the loop.
Summary
Implements SDK-1254: migrates every XCTest suite in
Tests/RealtimeTeststo Swift Testing (@Suite/@Test,#expect/#require,Issue.record), per the SDK-435 phase-by-phase migration plan.Details
Tests/RealtimeTests/TestSupport.swift: a sharedwaitUntil(timeout:pollInterval:condition:)polling helper that replacesXCTestExpectation/fulfillment(of:timeout:)— Swift Testing has no direct async-condition-with-timeout primitive.RealtimeTests.swift: keeps thewithMainSerialExecutorrequirement (previously applied viainvokeTest()override), now wrapped per test body, with@Suite(.serialized)so the process-global executor flag can't race across concurrently-scheduled tests.setUp/tearDowntoinit()/deinit, keeping class-based suites where teardown must actively cancel background tasks (e.g.sut.disconnect()), not just rely on ARC releasing the struct.WebSocketTests.swift: serializes the suite (@Suite(.serialized)) — its cert-pinning tests import self-signed identities viaSecPKCS12Import, which is flaky when several tests run concurrently under Swift Testing's default parallel execution (XCTest ran these serially). Converts completion-handler-based challenge-forwarding tests toconfirmation(_:).Package.swift: addsRealtimeTeststoswift6TestTargetsnow that the target is fully migrated (gets full Swift 6 language mode checking, matching other migrated modules).Behavior, coverage, and assertions are unchanged — only the test framework and incidental concurrency helpers differ.
Testing
swift build(whole package) — clean.swift test --filter RealtimeTests— 254 tests / 22 suites pass, run 5x in a row with no flakiness (including theWebSocketTestscert-pinning tests, which were flaky before serializing the suite)../scripts/format.sh— applied.