Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCOCOA-1883: Add "Sync is not enabled for this App" as a catchable error in error handler #8643

Merged
merged 5 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
public enum SyncMode {
case pbs(String) // partition based
case flx([String]) // flexible sync
case notSync
}

// MARK: RealmServer
Expand All @@ -484,7 +485,7 @@
}

/// Shared RealmServer. This class only needs to be initialized and torn down once per test suite run.
@objc public static let shared = RealmServer()

Check notice on line 488 in Realm/ObjectServerTests/RealmServer.swift

View check run for this annotation

Xcode Cloud / RealmSwift | swiftui-sync_16 beta 3 | Test - macOS

Realm/ObjectServerTests/RealmServer.swift#L488

Static property 'shared' is not concurrency-safe because non-'Sendable' type 'RealmServer' may have shared mutable state; this is an error in the Swift 6 language mode

/// Log level for the server and mongo processes.
public var logLevel = LogLevel.none
Expand Down Expand Up @@ -815,6 +816,10 @@
}
}

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 @@
"delete": true
]]
]).get()
default:
fatalError()
}
_ = try app.services[serviceId].config.patch(serviceConfig).get()

Expand Down Expand Up @@ -1011,6 +1018,10 @@
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 @@

// 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 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 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 @@
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 Expand Up @@ -1258,7 +1256,7 @@
}
}

extension String: Error {

Check notice on line 1259 in Realm/ObjectServerTests/RealmServer.swift

View check run for this annotation

Xcode Cloud / RealmSwift | swiftui-sync_16 beta 3 | Test - macOS

Realm/ObjectServerTests/RealmServer.swift#L1259

Extension declares a conformance of imported type 'String' to imported protocol 'Error'; this will not behave correctly if the owners of 'Swift' introduce this conformance in the future
}

#endif
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
Loading