Skip to content

Commit baaa5a1

Browse files
RCOCOA-1883: Add "Sync is not enabled for this App" as a catchable error in error handler (#8643)
1 parent 2fd2e3f commit baaa5a1

File tree

5 files changed

+48
-24
lines changed

5 files changed

+48
-24
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ x.y.z Release notes (yyyy-MM-dd)
99
* Code sign our published xcframeworks. By Apple's requirements, we should sign our release
1010
binaries so Xcode can validate it was signed by the same developer on every new version.
1111
([Apple](https://developer.apple.com/support/third-party-SDK-requirements/)).
12+
* Report sync warnings from the server such as sync being disabled server-side to the sync error handler.
13+
([#8020](https://github.com/realm/realm-swift/issues/8020)).
1214

1315
### Fixed
1416
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-swift/issues/????), since v?.?.?)

Realm/ObjectServerTests/RealmServer.swift

+22-24
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ class Admin {
469469
public enum SyncMode {
470470
case pbs(String) // partition based
471471
case flx([String]) // flexible sync
472+
case notSync
472473
}
473474

474475
// MARK: RealmServer
@@ -815,6 +816,10 @@ public class RealmServer: NSObject {
815816
}
816817
}
817818

819+
if case .notSync = syncMode {
820+
return clientAppId
821+
}
822+
818823
app.secrets.post(on: group, [
819824
"name": "BackingDB_uri",
820825
"value": "mongodb://localhost:26000"
@@ -927,6 +932,8 @@ public class RealmServer: NSObject {
927932
"delete": true
928933
]]
929934
]).get()
935+
default:
936+
fatalError()
930937
}
931938
_ = try app.services[serviceId].config.patch(serviceConfig).get()
932939

@@ -1011,6 +1018,10 @@ public class RealmServer: NSObject {
10111018
return try createApp(syncMode: .pbs(partitionKeyType), types: types, persistent: persistent)
10121019
}
10131020

1021+
@objc public func createNotSyncApp() throws -> AppId {
1022+
return try createApp(syncMode: .notSync, types: [], persistent: false)
1023+
}
1024+
10141025
/// Delete all Apps created without `persistent: true`
10151026
@objc func deleteApps() throws {
10161027
for appId in appIds {
@@ -1028,10 +1039,7 @@ public class RealmServer: NSObject {
10281039

10291040
// Retrieve Atlas App Services AppId with ClientAppId using the Admin API
10301041
public func retrieveAppServerId(_ clientAppId: String) throws -> String {
1031-
guard let session = session else {
1032-
fatalError()
1033-
}
1034-
1042+
let session = try XCTUnwrap(session)
10351043
let appsListInfo = try session.apps.get().get()
10361044
guard let appsList = appsListInfo as? [[String: Any]] else {
10371045
throw URLError(.badServerResponse)
@@ -1052,9 +1060,7 @@ public class RealmServer: NSObject {
10521060
}
10531061

10541062
public func retrieveSyncServiceId(appServerId: String) throws -> String {
1055-
guard let session = session else {
1056-
fatalError()
1057-
}
1063+
let session = try XCTUnwrap(session)
10581064
let app = session.apps[appServerId]
10591065
// Get all services
10601066
guard let syncServices = try app.services.get().get() as? [[String: Any]] else {
@@ -1083,14 +1089,11 @@ public class RealmServer: NSObject {
10831089
}
10841090
}
10851091

1086-
public func isSyncEnabled(flexibleSync: Bool = false, appServerId: String, syncServiceId: String) throws -> Bool {
1087-
let configOption = flexibleSync ? "flexible_sync" : "sync"
1088-
guard let session = session else {
1089-
fatalError()
1090-
}
1092+
public func isSyncEnabled(appServerId: String, syncServiceId: String) throws -> Bool {
1093+
let session = try XCTUnwrap(session)
10911094
let app = session.apps[appServerId]
10921095
let response = try app.services[syncServiceId].config.get().get() as? [String: Any]
1093-
guard let syncInfo = response?[configOption] as? [String: Any] else {
1096+
guard let syncInfo = response?["flexible_sync"] as? [String: Any] else {
10941097
return false
10951098
}
10961099
return syncInfo["state"] as? String == "enabled"
@@ -1113,28 +1116,23 @@ public class RealmServer: NSObject {
11131116
return app.sync.config.put(["development_mode_enabled": true])
11141117
}
11151118

1116-
public func disableSync(flexibleSync: Bool = false, appServerId: String, syncServiceId: String)
1117-
-> Result<Any?, Error> {
1118-
let configOption = flexibleSync ? "flexible_sync" : "sync"
1119-
guard let session = session else {
1120-
return .failure(URLError(.unknown))
1121-
}
1119+
public func disableSync(appServerId: String, syncServiceId: String) throws -> Any? {
1120+
let session = try XCTUnwrap(session)
11221121
let app = session.apps[appServerId]
1123-
return app.services[syncServiceId].config.patch([configOption: ["state": ""]])
1122+
return app.services[syncServiceId].config.patch(["flexible_sync": ["state": ""]])
11241123
}
11251124

1126-
public func enableSync(flexibleSync: Bool = false, appServerId: String, syncServiceId: String, syncServiceConfiguration: [String: Any]) -> Result<Any?, Error> {
1127-
let configOption = flexibleSync ? "flexible_sync" : "sync"
1125+
public func enableSync(appServerId: String, syncServiceId: String, syncServiceConfiguration: [String: Any]) -> Result<Any?, Error> {
11281126
var syncConfig = syncServiceConfiguration
11291127
guard let session = session else {
11301128
return .failure(URLError(.unknown))
11311129
}
11321130
let app = session.apps[appServerId]
1133-
guard var syncInfo = syncConfig[configOption] as? [String: Any] else {
1131+
guard var syncInfo = syncConfig["flexible_sync"] as? [String: Any] else {
11341132
return .failure(URLError(.unknown))
11351133
}
11361134
syncInfo["state"] = "enabled"
1137-
syncConfig[configOption] = syncInfo
1135+
syncConfig["flexible_sync"] = syncInfo
11381136
return app.services[syncServiceId].config.patch(syncConfig)
11391137
}
11401138

Realm/ObjectServerTests/SwiftFlexibleSyncServerTests.swift

+14
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,20 @@ class SwiftFlexibleSyncTests: SwiftSyncTestCase {
11861186
XCTAssertEqual(downloadCount.value, 0)
11871187
XCTAssertEqual(uploadCount.value, 0)
11881188
}
1189+
1190+
func testFlexibleSyncNotEnabledError() throws {
1191+
let appId = try RealmServer.shared.createNotSyncApp()
1192+
let app = app(id: appId)
1193+
let ex = expectation(description: "Waiting for error handler to be called...")
1194+
ex.assertForOverFulfill = false // error handler can legally be called multiple times
1195+
app.syncManager.errorHandler = { @Sendable (error, _) in
1196+
assertSyncError(error, .serverWarning, "Sync is not enabled for this app")
1197+
ex.fulfill()
1198+
}
1199+
1200+
_ = try Realm(configuration: configuration(app: app)) // Sync is disabled so we cannot use async open
1201+
wait(for: [ex], timeout: 10.0)
1202+
}
11891203
}
11901204

11911205
#endif // os(macOS)

Realm/RLMError.h

+8
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,14 @@ typedef RLM_ERROR_ENUM(NSInteger, RLMSyncError, RLMSyncErrorDomain) {
328328
Connecting to the server failed due to a TLS issue such as an invalid certificate.
329329
*/
330330
RLMSyncErrorTLSHandshakeFailed = 13,
331+
/**
332+
The server has encountered an error that it wants the user to know about,
333+
but is not necessarily fatal.
334+
335+
An error with this code may indicate that either sync is not enabled or it's trying to connect to
336+
an edge server app.
337+
*/
338+
RLMSyncErrorServerWarning = 14,
331339
};
332340

333341
#pragma mark - RLMSyncAuthError

Realm/RLMError.mm

+2
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ - (NSString *)reason {
292292
errorCode = RLMSyncErrorClientResetError;
293293
else if (isSyncError)
294294
errorCode = RLMSyncErrorClientSessionError;
295+
else if (error.server_requests_action == realm::sync::ProtocolErrorInfo::Action::Warning)
296+
errorCode = RLMSyncErrorServerWarning;
295297
else if (!error.is_fatal)
296298
return nil;
297299
break;

0 commit comments

Comments
 (0)