Skip to content
Snippets Groups Projects
Commit db42327e authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Handle auth requests in HomeFeature

parent 24beaf32
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!76Messenger example - auth requests handling
......@@ -55,6 +55,7 @@ extension AppEnvironment {
dbManager: dbManager,
mainQueue: mainQueue,
bgQueue: bgQueue,
now: Date.init,
register: {
RegisterEnvironment(
messenger: messenger,
......
......@@ -6,8 +6,10 @@ import ContactsFeature
import Foundation
import RegisterFeature
import UserSearchFeature
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct HomeState: Equatable {
public init(
......@@ -47,6 +49,12 @@ public enum HomeAction: Equatable {
case failure(NSError)
}
public enum AuthCallbacks: Equatable {
case register
case unregister
case handle(XXClient.AuthCallbacks.Callback)
}
public enum NetworkMonitor: Equatable {
case start
case stop
......@@ -62,6 +70,7 @@ public enum HomeAction: Equatable {
}
case messenger(Messenger)
case authCallbacks(AuthCallbacks)
case networkMonitor(NetworkMonitor)
case deleteAccount(DeleteAccount)
case didDismissAlert
......@@ -81,6 +90,7 @@ public struct HomeEnvironment {
dbManager: DBManager,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>,
now: @escaping () -> Date,
register: @escaping () -> RegisterEnvironment,
contacts: @escaping () -> ContactsEnvironment,
userSearch: @escaping () -> UserSearchEnvironment
......@@ -89,6 +99,7 @@ public struct HomeEnvironment {
self.dbManager = dbManager
self.mainQueue = mainQueue
self.bgQueue = bgQueue
self.now = now
self.register = register
self.contacts = contacts
self.userSearch = userSearch
......@@ -98,6 +109,7 @@ public struct HomeEnvironment {
public var dbManager: DBManager
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
public var now: () -> Date
public var register: () -> RegisterEnvironment
public var contacts: () -> ContactsEnvironment
public var userSearch: () -> UserSearchEnvironment
......@@ -109,6 +121,7 @@ extension HomeEnvironment {
dbManager: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented,
now: XCTUnimplemented("\(Self.self).now", placeholder: Date()),
register: { .unimplemented },
contacts: { .unimplemented },
userSearch: { .unimplemented }
......@@ -119,10 +132,12 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
{ state, action, env in
enum NetworkHealthEffectId {}
enum NetworkNodesEffectId {}
enum AuthCallbacksEffectId {}
switch action {
case .messenger(.start):
return .merge(
Effect(value: .authCallbacks(.register)),
Effect(value: .networkMonitor(.stop)),
Effect.result {
do {
......@@ -160,6 +175,59 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
state.failure = error.localizedDescription
return .none
case .authCallbacks(.register):
return Effect.run { subscriber in
let handler = AuthCallbacks { callback in
subscriber.send(.authCallbacks(.handle(callback)))
}
let cancellable = env.messenger.registerAuthCallbacks(handler)
return AnyCancellable { cancellable.cancel() }
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
.cancellable(id: AuthCallbacksEffectId.self, cancelInFlight: true)
case .authCallbacks(.unregister):
return .cancel(id: AuthCallbacksEffectId.self)
case .authCallbacks(.handle(.request(let contact, _, _, _))):
return .fireAndForget {
let db = try env.dbManager.getDB()
let contactId = try contact.getId()
guard try db.fetchContacts(.init(id: [contactId])).isEmpty else {
return
}
var dbContact = XXModels.Contact(id: contactId)
dbContact.marshaled = contact.data
dbContact.username = try contact.getFact(.username)?.value
dbContact.email = try contact.getFact(.email)?.value
dbContact.phone = try contact.getFact(.phone)?.value
dbContact.authStatus = .verificationInProgress
dbContact.createdAt = env.now()
dbContact = try db.saveContact(dbContact)
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .authCallbacks(.handle(.confirm(let contact, _, _, _))):
return .fireAndForget {
let db = try env.dbManager.getDB()
let contactId = try contact.getId()
guard var dbContact = try db.fetchContacts(.init(id: [contactId])).first else {
return
}
dbContact.authStatus = .friend
dbContact = try db.saveContact(dbContact)
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .authCallbacks(.handle(.reset(let contact, _, _, _))):
return .none
case .networkMonitor(.start):
return .merge(
Effect.run { subscriber in
......
......@@ -21,6 +21,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
store.environment.messenger.isConnected.run = { false }
store.environment.messenger.connect.run = { messengerDidConnect += 1 }
......@@ -32,10 +33,13 @@ final class HomeFeatureTests: XCTestCase {
XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
XCTAssertNoDifference(messengerDidConnect, 1)
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.didStartUnregistered)) {
$0.register = RegisterState()
}
store.send(.authCallbacks(.unregister))
}
func testMessengerStartRegistered() {
......@@ -51,6 +55,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
store.environment.messenger.isConnected.run = { false }
store.environment.messenger.connect.run = { messengerDidConnect += 1 }
......@@ -73,11 +78,14 @@ final class HomeFeatureTests: XCTestCase {
XCTAssertNoDifference(messengerDidConnect, 1)
XCTAssertNoDifference(messengerDidLogIn, 1)
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.didStartRegistered))
store.receive(.networkMonitor(.start))
store.send(.networkMonitor(.stop))
store.send(.authCallbacks(.unregister))
}
func testRegisterFinished() {
......@@ -94,6 +102,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
store.environment.messenger.isConnected.run = { true }
store.environment.messenger.isLoggedIn.run = { false }
......@@ -118,11 +127,14 @@ final class HomeFeatureTests: XCTestCase {
XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
XCTAssertNoDifference(messengerDidLogIn, 1)
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.didStartRegistered))
store.receive(.networkMonitor(.start))
store.send(.networkMonitor(.stop))
store.send(.authCallbacks(.unregister))
}
func testMessengerStartFailure() {
......@@ -137,14 +149,18 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in throw error }
store.send(.messenger(.start))
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authCallbacks(.unregister))
}
func testMessengerStartConnectFailure() {
......@@ -159,16 +175,20 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in }
store.environment.messenger.isConnected.run = { false }
store.environment.messenger.connect.run = { throw error }
store.send(.messenger(.start))
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authCallbacks(.unregister))
}
func testMessengerStartIsRegisteredFailure() {
......@@ -183,6 +203,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in }
store.environment.messenger.isConnected.run = { true }
store.environment.messenger.isLoggedIn.run = { false }
......@@ -190,10 +211,13 @@ final class HomeFeatureTests: XCTestCase {
store.send(.messenger(.start))
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authCallbacks(.unregister))
}
func testMessengerStartLogInFailure() {
......@@ -208,6 +232,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in }
store.environment.messenger.isConnected.run = { true }
store.environment.messenger.isLoggedIn.run = { false }
......@@ -216,10 +241,13 @@ final class HomeFeatureTests: XCTestCase {
store.send(.messenger(.start))
store.receive(.authCallbacks(.register))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authCallbacks(.unregister))
}
func testNetworkMonitorStart() {
......@@ -491,4 +519,109 @@ final class HomeFeatureTests: XCTestCase {
$0.contacts = nil
}
}
func testAuthCallbacks() {
let store = TestStore(
initialState: HomeState(),
reducer: homeReducer,
environment: .unimplemented
)
let now = Date()
var didRegisterCallbacks: [AuthCallbacks] = []
var didCancelAuthCallbacks = 0
var dbContact: XXModels.Contact?
var dbDidSaveContact: [XXModels.Contact] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.now = { now }
store.environment.messenger.registerAuthCallbacks.run = { callbacks in
didRegisterCallbacks.append(callbacks)
return Cancellable { didCancelAuthCallbacks += 1 }
}
store.environment.dbManager.getDB.run = {
var db: Database = .failing
db.fetchContacts.run = { _ in [dbContact].compactMap { $0 } }
db.saveContact.run = { contact in
dbDidSaveContact.append(contact)
return contact
}
return db
}
store.send(.authCallbacks(.register))
XCTAssertNoDifference(didRegisterCallbacks.count, 1)
var contact = XXClient.Contact.unimplemented("data".data(using: .utf8)!)
contact.getIdFromContact.run = { _ in "id".data(using: .utf8)! }
contact.getFactsFromContact.run = { _ in
[
Fact(type: .username, value: "username"),
Fact(type: .email, value: "email"),
Fact(type: .phone, value: "phone"),
]
}
dbContact = nil
dbDidSaveContact = []
didRegisterCallbacks.first?.handle(
.request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)
store.receive(.authCallbacks(.handle(
.request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)))
XCTAssertNoDifference(dbDidSaveContact, [.init(
id: "id".data(using: .utf8)!,
marshaled: "data".data(using: .utf8)!,
username: "username",
email: "email",
phone: "phone",
authStatus: .verificationInProgress,
createdAt: now
)])
dbContact = .init(id: "id".data(using: .utf8)!)
dbDidSaveContact = []
didRegisterCallbacks.first?.handle(
.request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)
store.receive(.authCallbacks(.handle(
.request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)))
XCTAssertNoDifference(dbDidSaveContact, [])
dbContact = .init(id: "id".data(using: .utf8)!)
dbDidSaveContact = []
didRegisterCallbacks.first?.handle(
.confirm(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)
store.receive(.authCallbacks(.handle(
.confirm(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)))
XCTAssertNoDifference(dbDidSaveContact, [.init(
id: "id".data(using: .utf8)!,
authStatus: .friend,
createdAt: dbContact!.createdAt
)])
dbContact = nil
dbDidSaveContact = []
didRegisterCallbacks.first?.handle(
.reset(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)
store.receive(.authCallbacks(.handle(
.reset(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0)
)))
XCTAssertNoDifference(dbDidSaveContact, [])
store.send(.authCallbacks(.unregister))
XCTAssertNoDifference(didCancelAuthCallbacks, 1)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment