Skip to content

Commit

Permalink
RCOCOA-1883: Add "Sync is not enabled for this App" as a catchable er…
Browse files Browse the repository at this point in the history
…ror in error handler (#8643)
  • Loading branch information
dianaafanador3 authored Jul 24, 2024
1 parent 2fd2e3f commit baaa5a1
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 24 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ x.y.z Release notes (yyyy-MM-dd)
* Code sign our published xcframeworks. By Apple's requirements, we should sign our release
binaries so Xcode can validate it was signed by the same developer on every new version.
([Apple](https://developer.apple.com/support/third-party-SDK-requirements/)).
* Report sync warnings from the server such as sync being disabled server-side to the sync error handler.
([#8020](https://github.com/realm/realm-swift/issues/8020)).

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-swift/issues/????), since v?.?.?)
Expand Down
46 changes: 22 additions & 24 deletions Realm/ObjectServerTests/RealmServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ class Admin {
public enum SyncMode {
case pbs(String) // partition based
case flx([String]) // flexible sync
case notSync
}

// MARK: RealmServer
Expand Down Expand Up @@ -815,6 +816,10 @@ public class RealmServer: NSObject {
}
}

if case .notSync = syncMode {
return clientAppId
}

app.secrets.post(on: group, [
"name": "BackingDB_uri",
"value": "mongodb://localhost:26000"
Expand Down Expand Up @@ -927,6 +932,8 @@ public class RealmServer: NSObject {
"delete": true
]]
]).get()
default:
fatalError()
}
_ = try app.services[serviceId].config.patch(serviceConfig).get()

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

@objc public func createNotSyncApp() throws -> AppId {
return try createApp(syncMode: .notSync, types: [], persistent: false)
}

/// Delete all Apps created without `persistent: true`
@objc func deleteApps() throws {
for appId in appIds {
Expand All @@ -1028,10 +1039,7 @@ public class RealmServer: NSObject {

// Retrieve Atlas App Services AppId with ClientAppId using the Admin API
public func retrieveAppServerId(_ clientAppId: String) throws -> String {
guard let session = session else {
fatalError()
}

let session = try XCTUnwrap(session)
let appsListInfo = try session.apps.get().get()
guard let appsList = appsListInfo as? [[String: Any]] else {
throw URLError(.badServerResponse)
Expand All @@ -1052,9 +1060,7 @@ public class RealmServer: NSObject {
}

public func retrieveSyncServiceId(appServerId: String) throws -> String {
guard let session = session else {
fatalError()
}
let session = try XCTUnwrap(session)
let app = session.apps[appServerId]
// Get all services
guard let syncServices = try app.services.get().get() as? [[String: Any]] else {
Expand Down Expand Up @@ -1083,14 +1089,11 @@ public class RealmServer: NSObject {
}
}

public func isSyncEnabled(flexibleSync: Bool = false, appServerId: String, syncServiceId: String) throws -> Bool {
let configOption = flexibleSync ? "flexible_sync" : "sync"
guard let session = session else {
fatalError()
}
public func isSyncEnabled(appServerId: String, syncServiceId: String) throws -> Bool {
let session = try XCTUnwrap(session)
let app = session.apps[appServerId]
let response = try app.services[syncServiceId].config.get().get() as? [String: Any]
guard let syncInfo = response?[configOption] as? [String: Any] else {
guard let syncInfo = response?["flexible_sync"] as? [String: Any] else {
return false
}
return syncInfo["state"] as? String == "enabled"
Expand All @@ -1113,28 +1116,23 @@ public class RealmServer: NSObject {
return app.sync.config.put(["development_mode_enabled": true])
}

public func disableSync(flexibleSync: Bool = false, appServerId: String, syncServiceId: String)
-> Result<Any?, Error> {
let configOption = flexibleSync ? "flexible_sync" : "sync"
guard let session = session else {
return .failure(URLError(.unknown))
}
public func disableSync(appServerId: String, syncServiceId: String) throws -> Any? {
let session = try XCTUnwrap(session)
let app = session.apps[appServerId]
return app.services[syncServiceId].config.patch([configOption: ["state": ""]])
return app.services[syncServiceId].config.patch(["flexible_sync": ["state": ""]])
}

public func enableSync(flexibleSync: Bool = false, appServerId: String, syncServiceId: String, syncServiceConfiguration: [String: Any]) -> Result<Any?, Error> {
let configOption = flexibleSync ? "flexible_sync" : "sync"
public func enableSync(appServerId: String, syncServiceId: String, syncServiceConfiguration: [String: Any]) -> Result<Any?, Error> {
var syncConfig = syncServiceConfiguration
guard let session = session else {
return .failure(URLError(.unknown))
}
let app = session.apps[appServerId]
guard var syncInfo = syncConfig[configOption] as? [String: Any] else {
guard var syncInfo = syncConfig["flexible_sync"] as? [String: Any] else {
return .failure(URLError(.unknown))
}
syncInfo["state"] = "enabled"
syncConfig[configOption] = syncInfo
syncConfig["flexible_sync"] = syncInfo
return app.services[syncServiceId].config.patch(syncConfig)
}

Expand Down
14 changes: 14 additions & 0 deletions Realm/ObjectServerTests/SwiftFlexibleSyncServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,20 @@ class SwiftFlexibleSyncTests: SwiftSyncTestCase {
XCTAssertEqual(downloadCount.value, 0)
XCTAssertEqual(uploadCount.value, 0)
}

func testFlexibleSyncNotEnabledError() throws {
let appId = try RealmServer.shared.createNotSyncApp()
let app = app(id: appId)
let ex = expectation(description: "Waiting for error handler to be called...")
ex.assertForOverFulfill = false // error handler can legally be called multiple times
app.syncManager.errorHandler = { @Sendable (error, _) in
assertSyncError(error, .serverWarning, "Sync is not enabled for this app")
ex.fulfill()
}

_ = try Realm(configuration: configuration(app: app)) // Sync is disabled so we cannot use async open
wait(for: [ex], timeout: 10.0)
}
}

#endif // os(macOS)
8 changes: 8 additions & 0 deletions Realm/RLMError.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,14 @@ typedef RLM_ERROR_ENUM(NSInteger, RLMSyncError, RLMSyncErrorDomain) {
Connecting to the server failed due to a TLS issue such as an invalid certificate.
*/
RLMSyncErrorTLSHandshakeFailed = 13,
/**
The server has encountered an error that it wants the user to know about,
but is not necessarily fatal.
An error with this code may indicate that either sync is not enabled or it's trying to connect to
an edge server app.
*/
RLMSyncErrorServerWarning = 14,
};

#pragma mark - RLMSyncAuthError
Expand Down
2 changes: 2 additions & 0 deletions Realm/RLMError.mm
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ - (NSString *)reason {
errorCode = RLMSyncErrorClientResetError;
else if (isSyncError)
errorCode = RLMSyncErrorClientSessionError;
else if (error.server_requests_action == realm::sync::ProtocolErrorInfo::Action::Warning)
errorCode = RLMSyncErrorServerWarning;
else if (!error.is_fatal)
return nil;
break;
Expand Down

0 comments on commit baaa5a1

Please sign in to comment.