Created
March 15, 2022 14:55
-
-
Save srstanic/5b0a3cb5225c1b9fb95d4bdd2f296ff5 to your computer and use it in GitHub Desktop.
RealmMultiThreadingStaleDataTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCTest | |
import Combine | |
import RealmSwift | |
class RealmMultiThreadingStaleDataTests: XCTestCase { | |
private var cancellables: Set<AnyCancellable>! | |
override func setUpWithError() throws { | |
super.setUp() | |
cancellables = [] | |
} | |
override func tearDownWithError() throws { | |
super.tearDown() | |
cancellables = nil | |
} | |
func testWriteOnBackgroundReadOnMain() throws { | |
let expectation = XCTestExpectation(description: "Expected to receive the right person.") | |
let personId1 = ObjectId.generate() | |
let personId2 = ObjectId.generate() | |
let realmQueue = DispatchQueue(label: "realmQueue", qos: .background) | |
getRealm(on: realmQueue) | |
.flatMap { realm -> AnyPublisher<Void, Error> in | |
let person = RealmPerson() | |
person.id = personId1 | |
return realm.save(object: person) | |
.map { _ in () } | |
.receive(on: DispatchQueue.main) | |
.eraseToAnyPublisher() | |
} | |
.flatMap { [self] _ in self.getRealm(on: realmQueue) } | |
.flatMap { realm -> AnyPublisher<Void, Error> in | |
let person = RealmPerson() | |
person.id = personId2 | |
return realm.save(object: person) | |
.map { _ in () } | |
.receive(on: DispatchQueue.main) | |
.eraseToAnyPublisher() | |
} | |
.flatMap { [self] _ in self.getRealm() } | |
.flatMap { realm -> AnyPublisher<RealmPerson?, Error> in | |
print("getting person with id: \(personId1)") | |
return realm.getTypedObject(objectId: personId1.stringValue) | |
.eraseToAnyPublisher() | |
} | |
.sink(receiveCompletion: { event in | |
if case .failure(let error) = event { | |
XCTFail("Received error: \(error)") | |
} | |
}) { personResult in | |
XCTAssertEqual(personId1.stringValue, personResult?.id.stringValue) | |
expectation.fulfill() | |
} | |
.store(in: &cancellables) | |
wait(for: [expectation], timeout: 30) | |
} | |
private func getRealm(on queue: DispatchQueue = .main) -> AnyPublisher<Realm, Error> { | |
return Just(()) | |
.subscribe(on: queue) | |
.flatMap { [name] _ -> AnyPublisher<Realm, Error> in | |
guard let realm = Realm.instance(withIdentifier: name) else { | |
print("dbgt: Failed to get realm instance") | |
return Fail<Realm, Error>(error: CustomError()).eraseToAnyPublisher() | |
} | |
realm.refresh() | |
return Just(realm) | |
.setFailureType(to: Error.self) | |
.eraseToAnyPublisher() | |
} | |
.eraseToAnyPublisher() | |
} | |
} | |
@objcMembers final class RealmPerson: Object { | |
dynamic var id: ObjectId = .generate() | |
dynamic var name: String = "" | |
public override static func primaryKey() -> String? { | |
return "id" | |
} | |
} | |
struct CustomError: Error {} | |
extension Realm { | |
static func configuration(withIdentifier identifier: String) -> Configuration { | |
var config = Realm.Configuration.defaultConfiguration | |
config.inMemoryIdentifier = identifier | |
return config | |
} | |
static func instance(withIdentifier identifier: String) -> Realm? { | |
let config = configuration(withIdentifier: identifier) | |
do { | |
return try Realm(configuration: config) | |
} catch { | |
return nil | |
} | |
} | |
func save<RealmType: Object>(object: RealmType) -> Future<RealmType, Swift.Error> { | |
Future { promise in | |
do { | |
try write { | |
add(object, update: .modified) | |
} | |
promise(.success(object)) | |
} catch { | |
promise(.failure(error)) | |
} | |
} | |
} | |
func getTypedObject<RealmType: Object>(objectId: String) -> Future<RealmType?, Swift.Error> { | |
return Future { promise in | |
do { | |
if let realmObject = try getFirstById(objectId: objectId, objectType: RealmType.self) { | |
let result = realmObject.freeze() | |
promise(.success(result)) | |
} else { | |
promise(.success(nil)) | |
} | |
} catch { | |
promise(.failure(error)) | |
} | |
} | |
} | |
func getFirstById<RealmType: Object>(objectId: String, objectType: RealmType.Type) throws -> RealmType? { | |
let realmId = try? ObjectId(string: objectId) | |
if let result = objects(RealmType.self) | |
.filter("\(RealmType.primaryKey() ?? "id") = %@", realmId ?? objectId) | |
.first | |
{ | |
return result | |
} | |
return nil | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment