From 66c7c84f6ff34bf47dfe08b5ff73c0a9fdced129 Mon Sep 17 00:00:00 2001 From: Lukas Korba Date: Mon, 4 Sep 2023 10:38:10 +0200 Subject: [PATCH] [#1227] Check continuation of UpdateChainTip repeated call - My assumption was right, the way State Machine is done requires .celarCache to be called with every "restart" - I was able to reproduce errors when clearCache wasn't called so the updateChainTipAction needed to be updated to prepare clean conditions for the scan suggest ranges - tests updated --- .../Block/Actions/UpdateChainTipAction.swift | 5 ++- .../UpdateChainTipActionTests.swift | 38 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift b/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift index 2560d357..47026f95 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift @@ -9,11 +9,13 @@ import Foundation final class UpdateChainTipAction { let rustBackend: ZcashRustBackendWelding + let downloader: BlockDownloader let service: LightWalletService let logger: Logger init(container: DIContainer) { service = container.resolve(LightWalletService.self) + downloader = container.resolve(BlockDownloader.self) rustBackend = container.resolve(ZcashRustBackendWelding.self) logger = container.resolve(Logger.self) } @@ -36,8 +38,9 @@ extension UpdateChainTipAction: Action { // Update chain tip can be called from different contexts if await context.prevState == .updateSubtreeRoots || now - lastChainTipUpdateTime > 600 { + await downloader.stopDownload() try await updateChainTip(context, time: now) - await context.update(state: .processSuggestedScanRanges) + await context.update(state: .clearCache) } else if await context.prevState == .enhance { await context.update(state: .download) } diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift index b11b6e4a..80277416 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift @@ -26,10 +26,12 @@ final class UpdateChainTipActionTests: ZcashTestCase { func testUpdateChainTipAction_UpdateChainTipTimeTriggered() async throws { let loggerMock = LoggerMock() - - loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } + let blockDownloaderMock = BlockDownloaderMock() - let updateChainTipAction = await setupAction(loggerMock) + loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } + blockDownloaderMock.stopDownloadClosure = { } + + let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock) do { let context = ActionContextMock.default() @@ -39,7 +41,9 @@ final class UpdateChainTipActionTests: ZcashTestCase { let nextContext = try await updateChainTipAction.run(with: context) { _ in } - let acResult = nextContext.checkStateIs(.processSuggestedScanRanges) + XCTAssertTrue(blockDownloaderMock.stopDownloadCallsCount == 1, "downloader.stopDownload() is expected to be called exactly once.") + + let acResult = nextContext.checkStateIs(.clearCache) XCTAssertTrue(acResult == .true, "Check of state failed with '\(acResult)'") } catch { XCTFail("testUpdateChainTipAction_UpdateChainTipTimeTriggered is not expected to fail. \(error)") @@ -48,10 +52,12 @@ final class UpdateChainTipActionTests: ZcashTestCase { func testUpdateChainTipAction_UpdateChainTipPrevActionTriggered() async throws { let loggerMock = LoggerMock() - - loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } + let blockDownloaderMock = BlockDownloaderMock() - let updateChainTipAction = await setupAction(loggerMock) + loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } + blockDownloaderMock.stopDownloadClosure = { } + + let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock) do { let context = ActionContextMock.default() @@ -61,7 +67,9 @@ final class UpdateChainTipActionTests: ZcashTestCase { let nextContext = try await updateChainTipAction.run(with: context) { _ in } - let acResult = nextContext.checkStateIs(.processSuggestedScanRanges) + XCTAssertTrue(blockDownloaderMock.stopDownloadCallsCount == 1, "downloader.stopDownload() is expected to be called exactly once.") + + let acResult = nextContext.checkStateIs(.clearCache) XCTAssertTrue(acResult == .true, "Check of state failed with '\(acResult)'") } catch { XCTFail("testUpdateChainTipAction_UpdateChainTipPrevActionTriggered is not expected to fail. \(error)") @@ -70,10 +78,12 @@ final class UpdateChainTipActionTests: ZcashTestCase { func testUpdateChainTipAction_UpdateChainTipSkipped() async throws { let loggerMock = LoggerMock() - - loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } + let blockDownloaderMock = BlockDownloaderMock() - let updateChainTipAction = await setupAction(loggerMock) + loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } + blockDownloaderMock.stopDownloadClosure = { } + + let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock) do { let context = ActionContextMock.default() @@ -83,6 +93,8 @@ final class UpdateChainTipActionTests: ZcashTestCase { let nextContext = try await updateChainTipAction.run(with: context) { _ in } + XCTAssertFalse(blockDownloaderMock.stopDownloadCalled, "downloader.stopDownload() is not expected to be called.") + let acResult = nextContext.checkStateIs(.download) XCTAssertTrue(acResult == .true, "Check of state failed with '\(acResult)'") } catch { @@ -91,7 +103,8 @@ final class UpdateChainTipActionTests: ZcashTestCase { } private func setupAction( - _ loggerMock: LoggerMock = LoggerMock() + _ loggerMock: LoggerMock = LoggerMock(), + _ blockDownloaderMock: BlockDownloaderMock = BlockDownloaderMock() ) async -> UpdateChainTipAction { let config: CompactBlockProcessor.Configuration = .standard( for: ZcashNetworkBuilder.network(for: underlyingNetworkType), walletBirthday: 0 @@ -119,6 +132,7 @@ final class UpdateChainTipActionTests: ZcashTestCase { mockContainer.mock(type: ZcashRustBackendWelding.self, isSingleton: true) { _ in rustBackendMock } mockContainer.mock(type: LightWalletService.self, isSingleton: true) { _ in serviceMock } mockContainer.mock(type: Logger.self, isSingleton: true) { _ in loggerMock } + mockContainer.mock(type: BlockDownloader.self, isSingleton: true) { _ in blockDownloaderMock } return UpdateChainTipAction(container: mockContainer) }