[#1039] Implement ChecksBeforeSyncAction

- ChecksBeforeSyncAction tests
- all support functions in Action tests are set to private
- let _ = -> _ = refactor
- CompactBlockRepository mock added
This commit is contained in:
Lukas Korba 2023-05-22 09:20:08 +02:00 committed by Michal Fousek
parent 15c069b914
commit 23f3e70cc5
6 changed files with 276 additions and 5 deletions

View File

@ -0,0 +1,153 @@
//
// ChecksBeforeSyncActionTests.swift
//
//
// Created by Lukáš Korba on 22.05.2023.
//
import XCTest
@testable import TestUtils
@testable import ZcashLightClientKit
final class ChecksBeforeSyncActionTests: ZcashTestCase {
var underlyingDownloadedButUnscannedRange: CompactBlockRange?
var underlyingLatestScannedHeight: BlockHeight?
var underlyingLatestDownloadedBlockHeight: BlockHeight?
override func setUp() {
super.setUp()
underlyingDownloadedButUnscannedRange = nil
underlyingLatestScannedHeight = nil
underlyingLatestDownloadedBlockHeight = nil
}
func testChecksBeforeSyncAction_shouldClearBlockCacheAndUpdateInternalState_noDownloadedButUnscannedRange() async throws {
let checksBeforeSyncAction = setupAction()
let syncRanges = setupSyncRanges()
let latestScannedHeight = checksBeforeSyncAction.shouldClearBlockCacheAndUpdateInternalState(syncRange: syncRanges)
XCTAssertNil(latestScannedHeight, "latestScannedHeight is expected to be nil.")
}
func testChecksBeforeSyncAction_shouldClearBlockCacheAndUpdateInternalState_nothingToClear() async throws {
let checksBeforeSyncAction = setupAction()
underlyingDownloadedButUnscannedRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
underlyingLatestScannedHeight = BlockHeight(2000)
underlyingLatestDownloadedBlockHeight = BlockHeight(2000)
let syncRanges = setupSyncRanges()
let latestScannedHeight = checksBeforeSyncAction.shouldClearBlockCacheAndUpdateInternalState(syncRange: syncRanges)
XCTAssertNil(latestScannedHeight, "latestScannedHeight is expected to be nil.")
}
func testChecksBeforeSyncAction_shouldClearBlockCacheAndUpdateInternalState_somethingToClear() async throws {
let checksBeforeSyncAction = setupAction()
underlyingDownloadedButUnscannedRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
underlyingLatestScannedHeight = BlockHeight(2000)
underlyingLatestDownloadedBlockHeight = BlockHeight(1000)
let syncRanges = setupSyncRanges()
let latestScannedHeight = checksBeforeSyncAction.shouldClearBlockCacheAndUpdateInternalState(syncRange: syncRanges)
XCTAssertNotNil(latestScannedHeight, "latestScannedHeight is not expected to be nil.")
}
func testChecksBeforeSyncAction_NextAction_ClearStorage() async throws {
let compactBlockRepository = CompactBlockRepositoryMock()
let internalSyncProgressStorageMock = InternalSyncProgressStorageMock()
compactBlockRepository.clearClosure = { }
internalSyncProgressStorageMock.setForKeyClosure = { _, _ in }
internalSyncProgressStorageMock.synchronizeClosure = { true }
let checksBeforeSyncAction = setupAction(
compactBlockRepository,
internalSyncProgressStorageMock
)
underlyingDownloadedButUnscannedRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
underlyingLatestScannedHeight = BlockHeight(2000)
underlyingLatestDownloadedBlockHeight = BlockHeight(1000)
let syncContext = await setupActionContext()
do {
let nextContext = try await checksBeforeSyncAction.run(with: syncContext) { _ in }
XCTAssertTrue(compactBlockRepository.clearCalled, "storage.clear() is expected to be called.")
XCTAssertTrue(internalSyncProgressStorageMock.setForKeyCalled, "internalSyncProgress.set() is expected to be called.")
let nextState = await nextContext.state
XCTAssertTrue(
nextState == .fetchUTXO,
"nextContext after .checksBeforeSync is expected to be .fetchUTXO but received \(nextState)"
)
} catch {
XCTFail("testChecksBeforeSyncAction_NextAction_ClearStorage is not expected to fail. \(error)")
}
}
func testChecksBeforeSyncAction_NextAction_CreateStorage() async throws {
let compactBlockRepository = CompactBlockRepositoryMock()
let internalSyncProgressStorageMock = InternalSyncProgressStorageMock()
compactBlockRepository.createClosure = { }
let checksBeforeSyncAction = setupAction(compactBlockRepository)
let syncContext = await setupActionContext()
do {
let nextContext = try await checksBeforeSyncAction.run(with: syncContext) { _ in }
XCTAssertTrue(compactBlockRepository.createCalled, "storage.create() is expected to be called.")
XCTAssertFalse(internalSyncProgressStorageMock.setForKeyCalled, "internalSyncProgress.set() is not expected to be called.")
let nextState = await nextContext.state
XCTAssertTrue(
nextState == .fetchUTXO,
"nextContext after .checksBeforeSync is expected to be .fetchUTXO but received \(nextState)"
)
} catch {
XCTFail("testChecksBeforeSyncAction_NextAction_CreateStorage is not expected to fail. \(error)")
}
}
private func setupAction(
_ compactBlockRepositoryMock: CompactBlockRepositoryMock = CompactBlockRepositoryMock(),
_ internalSyncProgressStorageMock: InternalSyncProgressStorageMock = InternalSyncProgressStorageMock(),
_ loggerMock: LoggerMock = LoggerMock()
) -> ChecksBeforeSyncAction {
mockContainer.register(type: InternalSyncProgress.self, isSingleton: true) { di in
InternalSyncProgress(alias: .default, storage: internalSyncProgressStorageMock, logger: loggerMock)
}
mockContainer.mock(type: CompactBlockRepository.self, isSingleton: true) { _ in compactBlockRepositoryMock }
return ChecksBeforeSyncAction(
container: mockContainer
)
}
private func setupSyncRanges() -> SyncRanges {
SyncRanges(
latestBlockHeight: 0,
downloadedButUnscannedRange: underlyingDownloadedButUnscannedRange,
downloadAndScanRange: nil,
enhanceRange: nil,
fetchUTXORange: nil,
latestScannedHeight: underlyingLatestScannedHeight,
latestDownloadedBlockHeight: underlyingLatestDownloadedBlockHeight
)
}
private func setupActionContext() async -> ActionContext {
let syncContext: ActionContext = .init(state: .checksBeforeSync)
await syncContext.update(syncRanges: setupSyncRanges())
await syncContext.update(totalProgressRange: CompactBlockRange(uncheckedBounds: (1000, 2000)))
return syncContext
}
}

View File

@ -242,7 +242,7 @@ final class EnhanceActionTests: ZcashTestCase {
}
}
func setupActionContext() async -> ActionContext {
private func setupActionContext() async -> ActionContext {
let syncContext: ActionContext = .init(state: .enhance)
let syncRanges = SyncRanges(
@ -261,7 +261,7 @@ final class EnhanceActionTests: ZcashTestCase {
return syncContext
}
func setupAction(
private func setupAction(
_ blockEnhancerMock: BlockEnhancerMock = BlockEnhancerMock(),
_ transactionRepositoryMock: TransactionRepositoryMock = TransactionRepositoryMock(),
_ internalSyncProgressStorageMock: InternalSyncProgressStorageMock = InternalSyncProgressStorageMock(),

View File

@ -86,7 +86,7 @@ final class ScanActionTests: ZcashTestCase {
}
}
func setupAction(
private func setupAction(
_ blockScannerMock: BlockScannerMock,
_ transactionRepositoryMock: TransactionRepositoryMock,
_ loggerMock: LoggerMock
@ -105,7 +105,7 @@ final class ScanActionTests: ZcashTestCase {
)
}
func setupActionContext() async -> ActionContext {
private func setupActionContext() async -> ActionContext {
let syncContext: ActionContext = .init(state: .scan)
let syncRanges = SyncRanges(

View File

@ -131,7 +131,7 @@ final class ValidateServerActionTests: ZcashTestCase {
}
}
func setupAction() -> ValidateServerAction {
private func setupAction() -> ValidateServerAction {
let config: CompactBlockProcessor.Configuration = .standard(
for: ZcashNetworkBuilder.network(for: underlyingNetworkType), walletBirthday: 0
)

View File

@ -16,6 +16,7 @@ extension BlockDownloader { }
extension BlockEnhancer { }
extension BlockScanner { }
extension BlockValidator { }
extension CompactBlockRepository { }
extension InternalSyncProgressStorage { }
extension LightWalletdInfo { }
extension LightWalletService { }

View File

@ -184,6 +184,123 @@ class BlockValidatorMock: BlockValidator {
try await validateClosure!()
}
}
class CompactBlockRepositoryMock: CompactBlockRepository {
init(
) {
}
// MARK: - create
var createThrowableError: Error?
var createCallsCount = 0
var createCalled: Bool {
return createCallsCount > 0
}
var createClosure: (() async throws -> Void)?
func create() async throws {
if let error = createThrowableError {
throw error
}
createCallsCount += 1
try await createClosure!()
}
// MARK: - latestHeight
var latestHeightCallsCount = 0
var latestHeightCalled: Bool {
return latestHeightCallsCount > 0
}
var latestHeightReturnValue: BlockHeight!
var latestHeightClosure: (() async -> BlockHeight)?
func latestHeight() async -> BlockHeight {
latestHeightCallsCount += 1
if let closure = latestHeightClosure {
return await closure()
} else {
return latestHeightReturnValue
}
}
// MARK: - write
var writeBlocksThrowableError: Error?
var writeBlocksCallsCount = 0
var writeBlocksCalled: Bool {
return writeBlocksCallsCount > 0
}
var writeBlocksReceivedBlocks: [ZcashCompactBlock]?
var writeBlocksClosure: (([ZcashCompactBlock]) async throws -> Void)?
func write(blocks: [ZcashCompactBlock]) async throws {
if let error = writeBlocksThrowableError {
throw error
}
writeBlocksCallsCount += 1
writeBlocksReceivedBlocks = blocks
try await writeBlocksClosure!(blocks)
}
// MARK: - rewind
var rewindToThrowableError: Error?
var rewindToCallsCount = 0
var rewindToCalled: Bool {
return rewindToCallsCount > 0
}
var rewindToReceivedHeight: BlockHeight?
var rewindToClosure: ((BlockHeight) async throws -> Void)?
func rewind(to height: BlockHeight) async throws {
if let error = rewindToThrowableError {
throw error
}
rewindToCallsCount += 1
rewindToReceivedHeight = height
try await rewindToClosure!(height)
}
// MARK: - clear
var clearUpToThrowableError: Error?
var clearUpToCallsCount = 0
var clearUpToCalled: Bool {
return clearUpToCallsCount > 0
}
var clearUpToReceivedHeight: BlockHeight?
var clearUpToClosure: ((BlockHeight) async throws -> Void)?
func clear(upTo height: BlockHeight) async throws {
if let error = clearUpToThrowableError {
throw error
}
clearUpToCallsCount += 1
clearUpToReceivedHeight = height
try await clearUpToClosure!(height)
}
// MARK: - clear
var clearThrowableError: Error?
var clearCallsCount = 0
var clearCalled: Bool {
return clearCallsCount > 0
}
var clearClosure: (() async throws -> Void)?
func clear() async throws {
if let error = clearThrowableError {
throw error
}
clearCallsCount += 1
try await clearClosure!()
}
}
class InternalSyncProgressStorageMock: InternalSyncProgressStorage {