Skip to content

Commit 4ab05e4

Browse files
Add ability to override implementation of publish
Will be needed by some upcoming integration tests that I'm porting from JS. There might be a better way to do this (injecting a special CoreSDK and thus not having to add this hook to the RealtimeObjects itself) but it'll do.
1 parent 7e6f671 commit 4ab05e4

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

Sources/AblyLiveObjects/Internal/CoreSDK.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,31 @@ internal protocol CoreSDK: AnyObject, Sendable {
88
/// Implements the internal `#publish` method of RTO15.
99
func publish(objectMessages: [OutboundObjectMessage]) async throws(InternalError)
1010

11+
/// Replaces the implementation of ``publish(objectMessages:)``.
12+
///
13+
/// Used by integration tests, for example to disable `ObjectMessage` publishing so that a test can verify that a behaviour is not a side effect of an `ObjectMessage` sent by the SDK.
14+
func testsOnly_overridePublish(with newImplementation: @escaping ([OutboundObjectMessage]) async throws(InternalError) -> Void)
15+
1116
/// Returns the current state of the Realtime channel that this wraps.
1217
var channelState: ARTRealtimeChannelState { get }
1318
}
1419

1520
internal final class DefaultCoreSDK: CoreSDK {
21+
/// Used to synchronize access to internal mutable state.
22+
private let mutex = NSLock()
23+
1624
private let channel: AblyPlugin.RealtimeChannel
1725
private let client: AblyPlugin.RealtimeClient
1826
private let pluginAPI: PluginAPIProtocol
1927
private let logger: AblyPlugin.Logger
2028

29+
/// If set to true, ``publish(objectMessages:)`` will behave like a no-op.
30+
///
31+
/// This enables the `testsOnly_overridePublish(with:)` test hook.
32+
///
33+
/// - Note: This should be `throws(InternalError)` but that causes a compilation error of "Runtime support for typed throws function types is only available in macOS 15.0.0 or newer".
34+
private nonisolated(unsafe) var overriddenPublishImplementation: (([OutboundObjectMessage]) async throws -> Void)?
35+
2136
internal init(
2237
channel: AblyPlugin.RealtimeChannel,
2338
client: AblyPlugin.RealtimeClient,
@@ -35,6 +50,22 @@ internal final class DefaultCoreSDK: CoreSDK {
3550
internal func publish(objectMessages: [OutboundObjectMessage]) async throws(InternalError) {
3651
logger.log("publish(objectMessages: \(LoggingUtilities.formatObjectMessagesForLogging(objectMessages)))", level: .debug)
3752

53+
// Use the overridden implementation if supplied
54+
let overriddenImplementation = mutex.withLock {
55+
overriddenPublishImplementation
56+
}
57+
if let overriddenImplementation {
58+
do {
59+
try await overriddenImplementation(objectMessages)
60+
} catch {
61+
guard let internalError = error as? InternalError else {
62+
preconditionFailure("Expected InternalError, got \(error)")
63+
}
64+
throw internalError
65+
}
66+
return
67+
}
68+
3869
// TODO: Implement the full spec of RTO15 (https://github.com/ably/ably-cocoa-liveobjects-plugin/issues/47)
3970
try await DefaultInternalPlugin.sendObject(
4071
objectMessages: objectMessages,
@@ -44,6 +75,12 @@ internal final class DefaultCoreSDK: CoreSDK {
4475
)
4576
}
4677

78+
internal func testsOnly_overridePublish(with newImplementation: @escaping ([OutboundObjectMessage]) async throws(InternalError) -> Void) {
79+
mutex.withLock {
80+
overriddenPublishImplementation = newImplementation
81+
}
82+
}
83+
4784
internal var channelState: ARTRealtimeChannelState {
4885
channel.state
4986
}

Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultRealtimeObjects.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,13 @@ internal final class PublicDefaultRealtimeObjects: RealtimeObjects {
117117
internal var testsOnly_receivedObjectSyncProtocolMessages: AsyncStream<[InboundObjectMessage]> {
118118
proxied.testsOnly_receivedObjectSyncProtocolMessages
119119
}
120+
121+
// These are used by the integration tests.
122+
123+
/// Replaces the method that this `RealtimeObjects` uses to send any outbound `ObjectMessage`s.
124+
///
125+
/// Used by integration tests, for example to disable `ObjectMessage` publishing so that a test can verify that a behaviour is not a side effect of an `ObjectMessage` sent by the SDK.
126+
internal func testsOnly_overridePublish(with newImplementation: @escaping ([OutboundObjectMessage]) async throws(InternalError) -> Void) {
127+
coreSDK.testsOnly_overridePublish(with: newImplementation)
128+
}
120129
}

Tests/AblyLiveObjectsTests/Mocks/MockCoreSDK.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ final class MockCoreSDK: CoreSDK {
2020
}
2121
}
2222

23+
func testsOnly_overridePublish(with _: @escaping ([OutboundObjectMessage]) async throws(InternalError) -> Void) {
24+
protocolRequirementNotImplemented()
25+
}
26+
2327
var channelState: ARTRealtimeChannelState {
2428
get {
2529
mutex.withLock {

0 commit comments

Comments
 (0)