[#586] secantTests.AppInitializationTests Tests fail on CI (#587)

- Publisher used instead of .task/.run
- fixed all tests

Convert WalletConfigProvider to Combine
This commit is contained in:
Lukas Korba 2023-02-28 18:02:31 +01:00 committed by GitHub
parent 75150da3a4
commit 2ddce23427
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 145 additions and 63 deletions

View File

@ -320,7 +320,6 @@
3448CB3228E47666006ADEDB /* NotEnoughFreeSpaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */; };
3448CB3728E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */; };
346715A528E2027D0035F7C4 /* CheckCircleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346715A428E2027D0035F7C4 /* CheckCircleStore.swift */; };
346715A828E20FE40035F7C4 /* TransactionConfirmationSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346715A728E20FE40035F7C4 /* TransactionConfirmationSnapshotTests.swift */; };
3469F18229ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3469F18129ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift */; };
346D41E428DF0B8600963F36 /* CheckCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346D41E328DF0B8600963F36 /* CheckCircle.swift */; };
34BF09092927C98000222134 /* Memo+toString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BF09082927C98000222134 /* Memo+toString.swift */; };
@ -383,13 +382,13 @@
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99827CF704D00649636 /* ImportWalletStore.swift */; };
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */; };
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99B27CF704D00649636 /* ImportWalletView.swift */; };
9E2E097B29ADEFDA00018C2A /* AppInitializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E391131284644580073DD9A /* AppInitializationTests.swift */; };
9E2F1C842809B606004E65FE /* DebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C832809B606004E65FE /* DebugMenu.swift */; };
9E2F1C8C280ED6A7004E65FE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8B280ED6A7004E65FE /* LaunchScreen.storyboard */; };
9E2F1C8F280EDE09004E65FE /* Drawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8E280EDE09004E65FE /* Drawer.swift */; };
9E37A2B827C8F59F00AE57B3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9E37A2B727C8F59F00AE57B3 /* Localizable.strings */; };
9E391124283E4CAC0073DD9A /* ImportWalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E391123283E4CAC0073DD9A /* ImportWalletTests.swift */; };
9E39112E283F91600073DD9A /* ZatoshiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E39112D283F91600073DD9A /* ZatoshiTests.swift */; };
9E391132284644580073DD9A /* AppInitializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E391131284644580073DD9A /* AppInitializationTests.swift */; };
9E3911392848AD500073DD9A /* HomeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911382848AD500073DD9A /* HomeTests.swift */; };
9E39114A2848EEB90073DD9A /* UserPreferencesStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911442848EEB90073DD9A /* UserPreferencesStorage.swift */; };
9E39114C2848EEB90073DD9A /* DatabaseFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911462848EEB90073DD9A /* DatabaseFiles.swift */; };
@ -646,7 +645,6 @@
3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFreeSpaceView.swift; sourceTree = "<group>"; };
3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFeeSpaceSnapshots.swift; sourceTree = "<group>"; };
346715A428E2027D0035F7C4 /* CheckCircleStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircleStore.swift; sourceTree = "<group>"; };
346715A728E20FE40035F7C4 /* TransactionConfirmationSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionConfirmationSnapshotTests.swift; sourceTree = "<group>"; };
3469F18129ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFlowFeatureFlagTests.swift; sourceTree = "<group>"; };
346D41E328DF0B8600963F36 /* CheckCircle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircle.swift; sourceTree = "<group>"; };
34BF09082927C98000222134 /* Memo+toString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Memo+toString.swift"; sourceTree = "<group>"; };
@ -3020,7 +3018,6 @@
9E9ECC9A28589E150099D5A2 /* RecoveryPhraseValidationFlowSnapshotTests.swift in Sources */,
9E0F574B2980260D005304FA /* LoggerTests.swift in Sources */,
9EAFEB822805793200199FC9 /* RootTests.swift in Sources */,
9E391132284644580073DD9A /* AppInitializationTests.swift in Sources */,
9E9ECC9928589E150099D5A2 /* RecoveryPhraseDisplaySnapshotTests.swift in Sources */,
9E391124283E4CAC0073DD9A /* ImportWalletTests.swift in Sources */,
9E5BF63F2819542C00BA3F17 /* WalletEventsTests.swift in Sources */,
@ -3030,6 +3027,7 @@
9E207C362966EC77003E2C9B /* AddressDetailsSnapshotTests.swift in Sources */,
9E3911392848AD500073DD9A /* HomeTests.swift in Sources */,
9E9ECC9C28589E150099D5A2 /* OnboardingSnapshotTests.swift in Sources */,
9E2E097B29ADEFDA00018C2A /* AppInitializationTests.swift in Sources */,
9E9ECC9728589E150099D5A2 /* HomeSnapshotTests.swift in Sources */,
9E207C392966EF87003E2C9B /* AddressDetailsTests.swift in Sources */,
9EF8135C27ECC25E0075AF48 /* WalletStorageTests.swift in Sources */,
@ -3526,7 +3524,7 @@
repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture";
requirement = {
kind = exactVersion;
version = 0.50.2;
version = 0.51.0;
};
};
9E2AC0FD27D8EC120042AA47 /* XCRemoteSwiftPackageReference "MnemonicSwift" */ = {

View File

@ -77,8 +77,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift.git",
"state" : {
"revision" : "783ed8ddcde07ac0332a5ec4647b665f82e95b78",
"version" : "1.14.0"
"revision" : "a20cac0cad4e0da457de687c45cb55aee9a45e19",
"version" : "1.14.1"
}
},
{
@ -185,8 +185,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-composable-architecture",
"state" : {
"revision" : "a99024bbd171d85a92bccbcea23e7c66f05dc12b",
"version" : "0.50.2"
"revision" : "cd22f6a1b3a6210e1e365cbfa8706dbb1736ca27",
"version" : "0.51.0"
}
},
{
@ -221,8 +221,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-identified-collections",
"state" : {
"revision" : "fd34c544ad27f3ba6b19142b348005bfa85b6005",
"version" : "0.6.0"
"revision" : "ad3932d28c2e0a009a0167089619526709ef6497",
"version" : "0.7.0"
}
},
{
@ -248,8 +248,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-extras.git",
"state" : {
"revision" : "98378d1fe56527761c180f70b2d66a7b2307fc39",
"version" : "1.16.0"
"revision" : "d75ed708d00353acf173ca23018b6bd46f949464",
"version" : "1.17.0"
}
},
{
@ -257,8 +257,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-http2.git",
"state" : {
"revision" : "22757ac305f3d44d2b99ba541193ff1d64e77d00",
"version" : "1.24.1"
"revision" : "860622124b01cc1863b4e65dc449b6b457ca5704",
"version" : "1.25.1"
}
},
{

View File

@ -6,6 +6,7 @@
//
import Foundation
import Combine
struct WalletConfigProvider {
/// Objects that fetches flags configuration from some source. It can be fetched from user defaults or some backend API for example. It depends
@ -28,7 +29,17 @@ struct WalletConfigProvider {
/// configuration.
///
/// Merged configuration is stored in cache.
func load() async -> WalletConfig {
func load() -> AnyPublisher<WalletConfig, Never> {
let publisher = PassthroughSubject<WalletConfig, Never>()
Task {
let config = await load()
publisher.send(config)
publisher.send(completion: .finished)
}
return publisher.eraseToAnyPublisher()
}
private func load() async -> WalletConfig {
let configuration: WalletConfig
do {
configuration = try await configSourceProvider.load()
@ -49,7 +60,17 @@ struct WalletConfigProvider {
}
// This is used only in debug menu to change configuration for specific flag
func update(featureFlag: FeatureFlag, isEnabled: Bool) async {
func update(featureFlag: FeatureFlag, isEnabled: Bool) -> AnyPublisher<Void, Never> {
let publisher = PassthroughSubject<Void, Never>()
Task {
await update(featureFlag: featureFlag, isEnabled: isEnabled)
publisher.send(Void())
publisher.send(completion: .finished)
}
return publisher.eraseToAnyPublisher()
}
private func update(featureFlag: FeatureFlag, isEnabled: Bool) async {
guard let provider = configSourceProvider as? UserDefaultsWalletConfigStorage else {
LoggerProxy.debug("This is now only support with UserDefaultsWalletConfigStorage as configurationProvider.")
return

View File

@ -7,6 +7,7 @@
import ComposableArchitecture
import Foundation
import Combine
extension DependencyValues {
var walletConfigProvider: WalletConfigProviderClient {
@ -16,6 +17,6 @@ extension DependencyValues {
}
struct WalletConfigProviderClient {
let load: () async -> WalletConfig
let update: (FeatureFlag, Bool) async -> Void
let load: () -> AnyPublisher<WalletConfig, Never>
let update: (FeatureFlag, Bool) -> AnyPublisher<Void, Never>
}

View File

@ -20,9 +20,9 @@ extension WalletConfigProviderClient: DependencyKey {
static func live(walletConfigProvider: WalletConfigProvider = WalletConfigProviderClient.defaultWalletConfigProvider) -> Self {
Self(
load: { return await walletConfigProvider.load() },
load: { walletConfigProvider.load() },
update: { flag, isEnabled in
await walletConfigProvider.update(featureFlag: flag, isEnabled: isEnabled)
return walletConfigProvider.update(featureFlag: flag, isEnabled: isEnabled)
}
)
}

View File

@ -7,17 +7,18 @@
import ComposableArchitecture
import XCTestDynamicOverlay
import Combine
extension WalletConfigProviderClient: TestDependencyKey {
static let testValue = Self(
load: XCTUnimplemented("\(Self.self).load", placeholder: WalletConfig.default),
load: XCTUnimplemented("\(Self.self).load", placeholder: Just(WalletConfig.default).eraseToAnyPublisher()),
update: XCTUnimplemented("\(Self.self).update")
)
}
extension WalletConfigProviderClient {
static let noOp = Self(
load: { WalletConfig.default },
update: { _, _ in }
load: { Just(WalletConfig.default).eraseToAnyPublisher() },
update: { _, _ in Just(Void()).eraseToAnyPublisher() }
)
}

View File

@ -119,7 +119,7 @@ extension RootReducer {
return .none
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation,
.sandbox, .welcome, .binding, .nukeWalletFailed, .nukeWalletSucceeded, .debug:
.sandbox, .welcome, .binding, .nukeWalletFailed, .nukeWalletSucceeded, .debug, .walletConfigLoaded:
return .none
}

View File

@ -28,7 +28,8 @@ extension RootReducer {
enum DebugAction: Equatable {
case updateFlag(FeatureFlag, Bool)
case flagUpdated(WalletConfig)
case flagUpdated
case walletConfigLoaded(WalletConfig)
}
// swiftlint:disable:next cyclomatic_complexity function_body_length
@ -41,13 +42,17 @@ extension RootReducer {
.eraseToEffect()
case .initialization(.checkWalletConfig):
return .run { send in
let walletConfig = await walletConfigProvider.load()
if walletConfig == WalletConfig.default {
await send(.initialization(.initialSetups))
} else {
await send(.initialization(.walletConfigChanged(walletConfig)))
}
return walletConfigProvider.load()
.receive(on: mainQueue)
.map(RootReducer.Action.walletConfigLoaded)
.eraseToEffect()
.cancellable(id: WalletConfigCancelId.self, cancelInFlight: true)
case .walletConfigLoaded(let walletConfig):
if walletConfig == WalletConfig.default {
return EffectTask(value: .initialization(.initialSetups))
} else {
return EffectTask(value: .initialization(.walletConfigChanged(walletConfig)))
}
case .initialization(.walletConfigChanged(let walletConfig)):
@ -276,13 +281,20 @@ extension RootReducer {
return .none
case let .debug(.updateFlag(flag, isEnabled)):
return .run { send in
await walletConfigProvider.update(flag, !isEnabled)
let walletConfig = await walletConfigProvider.load()
await send(.debug(.flagUpdated(walletConfig)))
}
return walletConfigProvider.update(flag, !isEnabled)
.receive(on: mainQueue)
.map { _ in return Action.debug(.flagUpdated) }
.eraseToEffect()
.cancellable(id: WalletConfigCancelId.self, cancelInFlight: true)
case let .debug(.flagUpdated(walletConfig)):
case .debug(.flagUpdated):
return walletConfigProvider.load()
.receive(on: mainQueue)
.map { Action.debug(.walletConfigLoaded($0)) }
.eraseToEffect()
.cancellable(id: WalletConfigCancelId.self, cancelInFlight: true)
case let .debug(.walletConfigLoaded(walletConfig)):
updateStateAfterConfigUpdate(state: &state, config: walletConfig)
return .none
}

View File

@ -7,22 +7,24 @@ typealias RootViewStore = ViewStore<RootReducer.State, RootReducer.Action>
struct RootReducer: ReducerProtocol {
enum CancelId {}
enum SynchronizerCancelId {}
enum WalletConfigCancelId {}
struct State: Equatable {
var appInitializationState: InitializationState = .uninitialized
var destinationState: DestinationState
var walletConfig: WalletConfig
var homeState: HomeReducer.State
var onboardingState: OnboardingFlowReducer.State
var phraseValidationState: RecoveryPhraseValidationFlowReducer.State
var phraseDisplayState: RecoveryPhraseDisplayReducer.State
var sandboxState: SandboxReducer.State
var storedWallet: StoredWallet?
var walletConfig: WalletConfig
var welcomeState: WelcomeReducer.State
}
enum Action: Equatable, BindableAction {
case binding(BindingAction<RootReducer.State>)
case debug(DebugAction)
case destination(DestinationAction)
case home(HomeReducer.Action)
case initialization(InitializationAction)
@ -32,20 +34,20 @@ struct RootReducer: ReducerProtocol {
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
case phraseValidation(RecoveryPhraseValidationFlowReducer.Action)
case sandbox(SandboxReducer.Action)
case walletConfigLoaded(WalletConfig)
case welcome(WelcomeReducer.Action)
case debug(DebugAction)
}
@Dependency(\.crashReporter) var crashReporter
@Dependency(\.databaseFiles) var databaseFiles
@Dependency(\.deeplink) var deeplink
@Dependency(\.derivationTool) var derivationTool
@Dependency(\.walletConfigProvider) var walletConfigProvider
@Dependency(\.mainQueue) var mainQueue
@Dependency(\.mnemonic) var mnemonic
@Dependency(\.randomRecoveryPhrase) var randomRecoveryPhrase
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
@Dependency(\.userStoredPreferences) var userStoredPreferences
@Dependency(\.walletConfigProvider) var walletConfigProvider
@Dependency(\.walletStorage) var walletStorage
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
@ -169,7 +171,6 @@ extension RootReducer.State {
static var placeholder: Self {
.init(
destinationState: .placeholder,
walletConfig: .default,
homeState: .placeholder,
onboardingState: .init(
walletConfig: .default,
@ -180,6 +181,7 @@ extension RootReducer.State {
phrase: .placeholder
),
sandboxState: .placeholder,
walletConfig: .default,
welcomeState: .placeholder
)
}

View File

@ -65,7 +65,6 @@ class AppInitializationTests: XCTestCase {
let appState = RootReducer.State(
destinationState: .placeholder,
walletConfig: .default,
homeState: .placeholder,
onboardingState: .init(
walletConfig: .default,
@ -76,6 +75,7 @@ class AppInitializationTests: XCTestCase {
phrase: recoveryPhrase
),
sandboxState: .placeholder,
walletConfig: .default,
welcomeState: .placeholder
)
@ -84,10 +84,12 @@ class AppInitializationTests: XCTestCase {
reducer: RootReducer()
)
let testQueue = DispatchQueue.test
store.dependencies.databaseFiles = .noOp
store.dependencies.databaseFiles.areDbFilesPresentFor = { _ in true }
store.dependencies.derivationTool = .liveValue
store.dependencies.mainQueue = .immediate
store.dependencies.mainQueue = .immediate// testQueue.eraseToAnyScheduler()
store.dependencies.mnemonic = .mock
store.dependencies.randomRecoveryPhrase = recoveryPhraseRandomizer
store.dependencies.walletStorage.exportWallet = { .placeholder }
@ -97,16 +99,24 @@ class AppInitializationTests: XCTestCase {
// Root of the test, the app finished the launch process and triggers the checks and initializations.
await store.send(.initialization(.appDelegate(.didFinishLaunching)))
await testQueue.advance(by: 0.02)
await store.receive(.initialization(.checkWalletConfig))
await store.receive(.walletConfigLoaded(WalletConfig.default))
await store.receive(.initialization(.initialSetups))
await testQueue.advance(by: 0.02)
await store.receive(.initialization(.configureCrashReporter))
await store.receive(.initialization(.checkWalletInitialization))
await store.receive(.initialization(.respondToWalletInitializationState(.initialized)))
await testQueue.advance(by: 3.00)
await store.receive(.initialization(.initializeSDK)) { state in
state.storedWallet = .placeholder
}
@ -141,6 +151,8 @@ class AppInitializationTests: XCTestCase {
await store.receive(.initialization(.checkWalletConfig))
await store.receive(.walletConfigLoaded(WalletConfig.default))
await store.receive(.initialization(.initialSetups))
await store.receive(.initialization(.configureCrashReporter))
@ -171,6 +183,8 @@ class AppInitializationTests: XCTestCase {
await store.receive(.initialization(.checkWalletConfig))
await store.receive(.walletConfigLoaded(WalletConfig.default))
await store.receive(.initialization(.initialSetups))
await store.receive(.initialization(.configureCrashReporter))

View File

@ -96,9 +96,9 @@ class RootTests: XCTestCase {
let store = TestStore(
initialState: .placeholder,
reducer: RootReducer()
) {
$0.mainQueue = Self.testScheduler.eraseToAnyScheduler()
}
)
store.dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
store.send(.initialization(.respondToWalletInitializationState(.uninitialized)))

View File

@ -5,74 +5,82 @@
// Created by Michal Fousek on 23.02.2023.
//
import Combine
import XCTest
@testable import secant_testnet
class WalletConfigProviderTests: XCTestCase {
var cancellables: [AnyCancellable] = []
override func setUp() {
super.setUp()
UserDefaultsWalletConfigStorage().clearAll()
}
override func tearDown() {
super.tearDown()
cancellables = []
}
func testTestFlagsAreDisabledByDefault() {
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag1))
XCTAssertFalse(WalletConfig.default.isEnabled(.testFlag2))
}
func testLoadFlagsFromProvider() async {
let provider = WalletConfigSourceProviderMock() {
let sourceProvider = WalletConfigSourceProviderMock() {
return WalletConfig(flags: [.testFlag1: true, .testFlag2: false])
}
let manager = WalletConfigProvider(configSourceProvider: provider, cache: UserDefaultsWalletConfigStorage())
let configuration = await manager.load()
let provider = WalletConfigProvider(configSourceProvider: sourceProvider, cache: UserDefaultsWalletConfigStorage())
let configuration = await loadWalletConfig(provider)
XCTAssertTrue(configuration.isEnabled(.testFlag1))
XCTAssertFalse(configuration.isEnabled(.testFlag2))
}
func testLoadFlagsFromCache() async {
let provider = WalletConfigSourceProviderMock() { throw NSError(domain: "whatever", code: 21) }
let sourceProvider = WalletConfigSourceProviderMock() { throw NSError(domain: "whatever", code: 21) }
let cache = WalletConfigProviderCacheMock(cachedFlags: [.testFlag1: false, .testFlag2: true])
let manager = WalletConfigProvider(configSourceProvider: provider, cache: cache)
let configuration = await manager.load()
let provider = WalletConfigProvider(configSourceProvider: sourceProvider, cache: cache)
let configuration = await loadWalletConfig(provider)
XCTAssertFalse(configuration.isEnabled(.testFlag1))
XCTAssertTrue(configuration.isEnabled(.testFlag2))
}
func testLoadDefaultFlags() async {
let provider = WalletConfigSourceProviderMock() { throw NSError(domain: "whatever", code: 21) }
let sourceProvider = WalletConfigSourceProviderMock() { throw NSError(domain: "whatever", code: 21) }
let cache = WalletConfigProviderCacheMock(cachedFlags: [:])
let manager = WalletConfigProvider(configSourceProvider: provider, cache: cache)
let configuration = await manager.load()
let provider = WalletConfigProvider(configSourceProvider: sourceProvider, cache: cache)
let configuration = await loadWalletConfig(provider)
XCTAssertFalse(configuration.isEnabled(.testFlag1))
XCTAssertFalse(configuration.isEnabled(.testFlag2))
}
func testAllTheFlagsAreAlwaysReturned() async {
let provider = WalletConfigSourceProviderMock() {
let sourceProvider = WalletConfigSourceProviderMock() {
return WalletConfig(flags: [.testFlag1: true])
}
let manager = WalletConfigProvider(configSourceProvider: provider, cache: UserDefaultsWalletConfigStorage())
let configuration = await manager.load()
let provider = WalletConfigProvider(configSourceProvider: sourceProvider, cache: UserDefaultsWalletConfigStorage())
let configuration = await loadWalletConfig(provider)
XCTAssertTrue(configuration.isEnabled(.testFlag1))
XCTAssertFalse(configuration.isEnabled(.testFlag2))
}
func testProvidedFlagsAreCached() async {
let provider = WalletConfigSourceProviderMock() {
let sourceProvider = WalletConfigSourceProviderMock() {
return WalletConfig(flags: [.testFlag1: true, .testFlag2: false])
}
let cache: WalletConfigProviderCache = UserDefaultsWalletConfigProviderCache()
let manager = WalletConfigProvider(configSourceProvider: provider, cache: cache)
_ = await manager.load()
let provider = WalletConfigProvider(configSourceProvider: sourceProvider, cache: cache)
_ = await loadWalletConfig(provider)
guard let cachedConfiguration = await cache.load() else {
return XCTFail("No cached configuration.")
@ -81,6 +89,31 @@ class WalletConfigProviderTests: XCTestCase {
XCTAssertTrue(cachedConfiguration.isEnabled(.testFlag1))
XCTAssertFalse(cachedConfiguration.isEnabled(.testFlag2))
}
private func loadWalletConfig(_ provider: WalletConfigProvider) async -> WalletConfig {
let expectation = XCTestExpectation()
expectation.expectedFulfillmentCount = 2
var configuration: WalletConfig!
await withCheckedContinuation { continuation in
provider.load()
.sink(
receiveCompletion: { _ in
expectation.fulfill()
continuation.resume()
},
receiveValue: {
configuration = $0
expectation.fulfill()
}
)
.store(in: &cancellables)
}
wait(for: [expectation], timeout: 1)
return configuration
}
}
struct WalletConfigSourceProviderMock: WalletConfigSourceProvider {