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

Use AuthHandler and MessageListener in AppFeature

parent fe681c02
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!100Messenger - restore from backup
This commit is part of merge request !100. Comments created here will be created in the context of that merge request.
......@@ -85,6 +85,11 @@ extension AppEnvironment {
return AppEnvironment(
dbManager: dbManager,
messenger: messenger,
authHandler: authHandler,
messageListener: .live(
messenger: messenger,
db: dbManager.getDB
),
mainQueue: mainQueue,
bgQueue: bgQueue,
welcome: {
......
......@@ -6,6 +6,7 @@ import Foundation
import HomeFeature
import RestoreFeature
import WelcomeFeature
import XXClient
import XXMessengerClient
struct AppState: Equatable {
......@@ -37,6 +38,7 @@ extension AppState.Screen {
enum AppAction: Equatable, BindableAction {
case start
case stop
case binding(BindingAction<AppState>)
case welcome(WelcomeAction)
case restore(RestoreAction)
......@@ -46,6 +48,8 @@ enum AppAction: Equatable, BindableAction {
struct AppEnvironment {
var dbManager: DBManager
var messenger: Messenger
var authHandler: AuthCallbackHandler
var messageListener: MessageListenerHandler
var mainQueue: AnySchedulerOf<DispatchQueue>
var bgQueue: AnySchedulerOf<DispatchQueue>
var welcome: () -> WelcomeEnvironment
......@@ -57,6 +61,8 @@ extension AppEnvironment {
static let unimplemented = AppEnvironment(
dbManager: .unimplemented,
messenger: .unimplemented,
authHandler: .unimplemented,
messageListener: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented,
welcome: { .unimplemented },
......@@ -67,34 +73,50 @@ extension AppEnvironment {
let appReducer = Reducer<AppState, AppAction, AppEnvironment>
{ state, action, env in
enum EffectId {}
switch action {
case .start, .welcome(.finished), .restore(.finished), .home(.deleteAccount(.success)):
state.screen = .loading
return .run { subscriber in
return Effect.run { subscriber in
var cancellables: [XXClient.Cancellable] = []
do {
if env.dbManager.hasDB() == false {
try env.dbManager.makeDB()
}
if env.messenger.isLoaded() == false {
if env.messenger.isCreated() == false {
subscriber.send(.set(\.$screen, .welcome(WelcomeState())))
subscriber.send(completion: .finished)
return AnyCancellable {}
}
cancellables.append(env.authHandler(onError: { error in
// TODO: handle error
}))
cancellables.append(env.messageListener(onError: { error in
// TODO: handle error
}))
let isLoaded = env.messenger.isLoaded()
let isCreated = env.messenger.isCreated()
if !isLoaded, !isCreated {
subscriber.send(.set(\.$screen, .welcome(WelcomeState())))
} else if !isLoaded {
try env.messenger.load()
subscriber.send(.set(\.$screen, .home(HomeState())))
} else {
subscriber.send(.set(\.$screen, .home(HomeState())))
}
subscriber.send(.set(\.$screen, .home(HomeState())))
} catch {
subscriber.send(.set(\.$screen, .failure(error.localizedDescription)))
}
subscriber.send(completion: .finished)
return AnyCancellable {}
return AnyCancellable { cancellables.forEach { $0.cancel() } }
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
.cancellable(id: EffectId.self, cancelInFlight: true)
case .stop:
return .cancel(id: EffectId.self)
case .welcome(.restoreTapped):
state.screen = .restore(RestoreState())
......
import AppCore
import ComposableArchitecture
import CustomDump
import HomeFeature
import RestoreFeature
import WelcomeFeature
import XCTest
import XXClient
@testable import AppFeature
final class AppFeatureTests: XCTestCase {
func testStartWithoutMessengerCreated() {
var actions: [Action] = []
let store = TestStore(
initialState: AppState(),
reducer: appReducer,
environment: .unimplemented
)
let mainQueue = DispatchQueue.test
let bgQueue = DispatchQueue.test
var didMakeDB = 0
store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { false }
store.environment.dbManager.makeDB.run = { didMakeDB += 1 }
store.environment.messenger.isLoaded.run = { false }
store.environment.messenger.isCreated.run = { false }
store.environment.dbManager.makeDB.run = {
actions.append(.didMakeDB)
}
store.environment.authHandler.run = { _ in
actions.append(.didStartAuthHandler)
return Cancellable {}
}
store.environment.messageListener.run = { _ in
actions.append(.didStartMessageListener)
return Cancellable {}
}
store.send(.start)
bgQueue.advance()
XCTAssertNoDifference(didMakeDB, 1)
mainQueue.advance()
store.receive(.set(\.$screen, .welcome(WelcomeState()))) {
$0.screen = .welcome(WelcomeState())
}
XCTAssertNoDifference(actions, [
.didMakeDB,
.didStartAuthHandler,
.didStartMessageListener,
])
store.send(.stop)
}
func testStartWithMessengerCreated() {
var actions: [Action] = []
let store = TestStore(
initialState: AppState(),
reducer: appReducer,
environment: .unimplemented
)
let mainQueue = DispatchQueue.test
let bgQueue = DispatchQueue.test
var didMakeDB = 0
var messengerDidLoad = 0
store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { false }
store.environment.dbManager.makeDB.run = { didMakeDB += 1 }
store.environment.messenger.isLoaded.run = { false }
store.environment.messenger.isCreated.run = { true }
store.environment.messenger.load.run = { messengerDidLoad += 1 }
store.environment.dbManager.makeDB.run = {
actions.append(.didMakeDB)
}
store.environment.messenger.load.run = {
actions.append(.didLoadMessenger)
}
store.environment.authHandler.run = { _ in
actions.append(.didStartAuthHandler)
return Cancellable {}
}
store.environment.messageListener.run = { _ in
actions.append(.didStartMessageListener)
return Cancellable {}
}
store.send(.start)
bgQueue.advance()
XCTAssertNoDifference(didMakeDB, 1)
XCTAssertNoDifference(messengerDidLoad, 1)
mainQueue.advance()
store.receive(.set(\.$screen, .home(HomeState()))) {
$0.screen = .home(HomeState())
}
XCTAssertNoDifference(actions, [
.didMakeDB,
.didStartAuthHandler,
.didStartMessageListener,
.didLoadMessenger,
])
store.send(.stop)
}
func testWelcomeFinished() {
var actions: [Action] = []
let store = TestStore(
initialState: AppState(
screen: .welcome(WelcomeState())
......@@ -81,33 +106,43 @@ final class AppFeatureTests: XCTestCase {
environment: .unimplemented
)
let mainQueue = DispatchQueue.test
let bgQueue = DispatchQueue.test
var messengerDidLoad = 0
store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { true }
store.environment.messenger.isLoaded.run = { false }
store.environment.messenger.isCreated.run = { true }
store.environment.messenger.load.run = { messengerDidLoad += 1 }
store.environment.messenger.load.run = {
actions.append(.didLoadMessenger)
}
store.environment.authHandler.run = { _ in
actions.append(.didStartAuthHandler)
return Cancellable {}
}
store.environment.messageListener.run = { _ in
actions.append(.didStartMessageListener)
return Cancellable {}
}
store.send(.welcome(.finished)) {
$0.screen = .loading
}
bgQueue.advance()
XCTAssertNoDifference(messengerDidLoad, 1)
mainQueue.advance()
store.receive(.set(\.$screen, .home(HomeState()))) {
$0.screen = .home(HomeState())
}
XCTAssertNoDifference(actions, [
.didStartAuthHandler,
.didStartMessageListener,
.didLoadMessenger,
])
store.send(.stop)
}
func testRestoreFinished() {
var actions: [Action] = []
let store = TestStore(
initialState: AppState(
screen: .restore(RestoreState())
......@@ -116,33 +151,43 @@ final class AppFeatureTests: XCTestCase {
environment: .unimplemented
)
let mainQueue = DispatchQueue.test
let bgQueue = DispatchQueue.test
var messengerDidLoad = 0
store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { true }
store.environment.messenger.isLoaded.run = { false }
store.environment.messenger.isCreated.run = { true }
store.environment.messenger.load.run = { messengerDidLoad += 1 }
store.environment.messenger.load.run = {
actions.append(.didLoadMessenger)
}
store.environment.authHandler.run = { _ in
actions.append(.didStartAuthHandler)
return Cancellable {}
}
store.environment.messageListener.run = { _ in
actions.append(.didStartMessageListener)
return Cancellable {}
}
store.send(.restore(.finished)) {
$0.screen = .loading
}
bgQueue.advance()
XCTAssertNoDifference(messengerDidLoad, 1)
mainQueue.advance()
store.receive(.set(\.$screen, .home(HomeState()))) {
$0.screen = .home(HomeState())
}
XCTAssertNoDifference(actions, [
.didStartAuthHandler,
.didStartMessageListener,
.didLoadMessenger,
])
store.send(.stop)
}
func testHomeDidDeleteAccount() {
var actions: [Action] = []
let store = TestStore(
initialState: AppState(
screen: .home(HomeState())
......@@ -151,25 +196,34 @@ final class AppFeatureTests: XCTestCase {
environment: .unimplemented
)
let mainQueue = DispatchQueue.test
let bgQueue = DispatchQueue.test
store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { true }
store.environment.messenger.isLoaded.run = { false }
store.environment.messenger.isCreated.run = { false }
store.environment.authHandler.run = { _ in
actions.append(.didStartAuthHandler)
return Cancellable {}
}
store.environment.messageListener.run = { _ in
actions.append(.didStartMessageListener)
return Cancellable {}
}
store.send(.home(.deleteAccount(.success))) {
$0.screen = .loading
}
bgQueue.advance()
mainQueue.advance()
store.receive(.set(\.$screen, .welcome(WelcomeState()))) {
$0.screen = .welcome(WelcomeState())
}
XCTAssertNoDifference(actions, [
.didStartAuthHandler,
.didStartMessageListener,
])
store.send(.stop)
}
func testWelcomeRestoreTapped() {
......@@ -187,6 +241,8 @@ final class AppFeatureTests: XCTestCase {
}
func testWelcomeFailed() {
let failure = "Something went wrong"
let store = TestStore(
initialState: AppState(
screen: .welcome(WelcomeState())
......@@ -195,23 +251,21 @@ final class AppFeatureTests: XCTestCase {
environment: .unimplemented
)
let failure = "Something went wrong"
store.send(.welcome(.failed(failure))) {
$0.screen = .failure(failure)
}
}
func testStartDatabaseMakeFailure() {
struct Failure: Error {}
let error = Failure()
let store = TestStore(
initialState: AppState(),
reducer: appReducer,
environment: .unimplemented
)
struct Failure: Error {}
let error = Failure()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { false }
......@@ -222,29 +276,136 @@ final class AppFeatureTests: XCTestCase {
store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
$0.screen = .failure(error.localizedDescription)
}
store.send(.stop)
}
func testStartMessengerLoadFailure() {
struct Failure: Error {}
let error = Failure()
var actions: [Action] = []
let store = TestStore(
initialState: AppState(),
reducer: appReducer,
environment: .unimplemented
)
struct Failure: Error {}
let error = Failure()
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { true }
store.environment.messenger.isLoaded.run = { false }
store.environment.messenger.isCreated.run = { true }
store.environment.messenger.load.run = { throw error }
store.environment.authHandler.run = { _ in
actions.append(.didStartAuthHandler)
return Cancellable {}
}
store.environment.messageListener.run = { _ in
actions.append(.didStartMessageListener)
return Cancellable {}
}
store.send(.start)
store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
$0.screen = .failure(error.localizedDescription)
}
XCTAssertNoDifference(actions, [
.didStartAuthHandler,
.didStartMessageListener,
])
store.send(.stop)
}
func testStartHandlersAndListeners() {
var actions: [Action] = []
var authHandlerOnError: [AuthCallbackHandler.OnError] = []
var messageListenerOnError: [MessageListenerHandler.OnError] = []
let store = TestStore(
initialState: AppState(),
reducer: appReducer,
environment: .unimplemented
)
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.dbManager.hasDB.run = { true }
store.environment.messenger.isLoaded.run = { true }
store.environment.messenger.isCreated.run = { true }
store.environment.authHandler.run = { onError in
authHandlerOnError.append(onError)
actions.append(.didStartAuthHandler)
return Cancellable {
actions.append(.didCancelAuthHandler)
}
}
store.environment.messageListener.run = { onError in
messageListenerOnError.append(onError)
actions.append(.didStartMessageListener)
return Cancellable {
actions.append(.didCancelMessageListener)
}
}
store.send(.start)
store.receive(.set(\.$screen, .home(HomeState()))) {
$0.screen = .home(HomeState())
}
XCTAssertNoDifference(actions, [
.didStartAuthHandler,
.didStartMessageListener,
])
actions = []
store.send(.start) {
$0.screen = .loading
}
store.receive(.set(\.$screen, .home(HomeState()))) {
$0.screen = .home(HomeState())
}
XCTAssertNoDifference(actions, [
.didCancelAuthHandler,
.didCancelMessageListener,
.didStartAuthHandler,
.didStartMessageListener,
])
actions = []
struct AuthError: Error {}
authHandlerOnError.first?(AuthError())
XCTAssertNoDifference(actions, [])
actions = []
struct MessageError: Error {}
messageListenerOnError.first?(MessageError())
XCTAssertNoDifference(actions, [])
actions = []
store.send(.stop)
XCTAssertNoDifference(actions, [
.didCancelAuthHandler,
.didCancelMessageListener,
])
}
}
private enum Action: Equatable {
case didMakeDB
case didStartAuthHandler
case didStartMessageListener
case didLoadMessenger
case didCancelAuthHandler
case didCancelMessageListener
}
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