2023-02-02 08:58:12 -08:00
|
|
|
//
|
|
|
|
// FsBlockStorageTests.swift
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 12/15/22.
|
|
|
|
//
|
|
|
|
import XCTest
|
|
|
|
@testable import TestUtils
|
|
|
|
@testable import ZcashLightClientKit
|
|
|
|
|
|
|
|
var logger = OSLogger(logLevel: .debug)
|
|
|
|
|
2023-05-21 09:48:29 -07:00
|
|
|
final class FsBlockStorageTests: ZcashTestCase {
|
2023-02-02 08:58:12 -08:00
|
|
|
let testFileManager = FileManager()
|
|
|
|
var fsBlockDb: URL!
|
2023-03-31 10:10:35 -07:00
|
|
|
var rustBackend: ZcashRustBackendWelding!
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
override func setUpWithError() throws {
|
|
|
|
try super.setUpWithError()
|
|
|
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
2023-03-31 10:10:35 -07:00
|
|
|
self.fsBlockDb = testTempDirectory.appendingPathComponent("FsBlockDb-\(Int.random(in: 0 ... .max))")
|
2023-02-02 08:58:12 -08:00
|
|
|
try self.testFileManager.createDirectory(at: self.fsBlockDb, withIntermediateDirectories: false)
|
2023-03-31 10:10:35 -07:00
|
|
|
|
|
|
|
rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .testnet)
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
override func tearDownWithError() throws {
|
|
|
|
try super.tearDownWithError()
|
2023-03-31 10:10:35 -07:00
|
|
|
rustBackend = nil
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
func testLatestHeightEmptyCache() async throws {
|
2023-02-02 08:58:12 -08:00
|
|
|
let emptyCache: FSCompactBlockRepository = .emptyTemporaryCache
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await emptyCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let latestHeight = await emptyCache.latestHeight()
|
|
|
|
XCTAssertEqual(latestHeight, .empty())
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
func testRewindEmptyCacheDoesNothing() async throws {
|
2023-02-02 08:58:12 -08:00
|
|
|
let emptyCache: FSCompactBlockRepository = .emptyTemporaryCache
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await emptyCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
try await emptyCache.rewind(to: 1000000)
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenBlockIsStoredItFollowsTheDescribedFormat() async throws {
|
|
|
|
let blockNameFixture = "This-is-a-fixture"
|
|
|
|
|
|
|
|
let freshCache = FSCompactBlockRepository(
|
2023-03-31 10:10:35 -07:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-02-02 08:58:12 -08:00
|
|
|
metadataStore: .mock,
|
|
|
|
blockDescriptor: ZcashCompactBlockDescriptor(
|
|
|
|
height: { _ in nil },
|
|
|
|
describe: { _ in blockNameFixture },
|
|
|
|
compare: { _, _ in nil }
|
|
|
|
),
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await freshCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let fakeBlock = StubBlockCreator.createRandomDataBlock(with: 1234)!
|
|
|
|
|
|
|
|
try await freshCache.write(blocks: [fakeBlock])
|
|
|
|
|
|
|
|
let blockFilename = freshCache.blocksDirectory
|
|
|
|
.appendingPathComponent(blockNameFixture)
|
|
|
|
.path
|
|
|
|
|
|
|
|
XCTAssertTrue(FileManager.default.isReadableFile(atPath: blockFilename))
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWhenBlockIsStoredItFollowsTheFilenameConvention() async throws {
|
|
|
|
let freshCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-02-02 08:58:12 -08:00
|
|
|
metadataStore: .mock,
|
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await freshCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let fakeBlock = StubBlockCreator.createRandomDataBlock(with: 1234)!
|
|
|
|
let fakeBlockHash = fakeBlock.meta.hash.toHexStringTxId()
|
|
|
|
|
|
|
|
try await freshCache.write(blocks: [fakeBlock])
|
|
|
|
|
|
|
|
let blockFilename = freshCache.blocksDirectory
|
|
|
|
.appendingPathComponent(
|
|
|
|
"\(1234)-\(fakeBlockHash)-compactblock"
|
|
|
|
)
|
|
|
|
.path
|
|
|
|
|
|
|
|
XCTAssertTrue(FileManager.default.isReadableFile(atPath: blockFilename))
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRewindDeletesTheRightBlocks() async throws {
|
|
|
|
let contentProvider = DirectoryListingProviders.defaultSorted
|
|
|
|
let freshCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-02-02 08:58:12 -08:00
|
|
|
metadataStore: .mock,
|
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: contentProvider,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await freshCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let blockRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
|
|
|
|
|
|
|
|
let fakeBlocks = StubBlockCreator.createBlockRange(blockRange)!
|
|
|
|
|
|
|
|
let rewindHeight = BlockHeight(1500)
|
|
|
|
|
|
|
|
try await freshCache.write(blocks: fakeBlocks)
|
|
|
|
|
|
|
|
let contents = try contentProvider.listContents(of: freshCache.blocksDirectory)
|
|
|
|
|
|
|
|
XCTAssertEqual(contents.count, blockRange.count)
|
|
|
|
|
|
|
|
guard let firstStoredBlock = contents.first else {
|
|
|
|
XCTFail("no stored block")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
guard let filename = try firstStoredBlock.resourceValues(forKeys: [URLResourceKey.nameKey]).name else {
|
|
|
|
XCTFail("no filename")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
XCTAssertEqual(ZcashCompactBlockDescriptor.live.height(filename), 1000)
|
|
|
|
|
|
|
|
guard let lastStoredBlock = contents.last else {
|
|
|
|
XCTFail("no stored block")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
XCTAssertEqual(ZcashCompactBlockDescriptor.live.height(lastStoredBlock.lastPathComponent), 2000)
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
try await freshCache.rewind(to: rewindHeight)
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let afterRewindContents = try contentProvider.listContents(of: freshCache.blocksDirectory)
|
|
|
|
|
|
|
|
XCTAssertEqual(afterRewindContents.count, 501)
|
|
|
|
|
|
|
|
guard let firstStoredBlockAfterRewind = afterRewindContents.first else {
|
|
|
|
XCTFail("no stored block")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
XCTAssertEqual(ZcashCompactBlockDescriptor.live.height(firstStoredBlockAfterRewind.lastPathComponent), 1000)
|
|
|
|
|
|
|
|
guard let lastStoredBlockAfterRewind = afterRewindContents.last else {
|
|
|
|
XCTFail("no stored block")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
XCTAssertEqual(ZcashCompactBlockDescriptor.live.height(lastStoredBlockAfterRewind.lastPathComponent), 1500)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testGetLatestHeight() async throws {
|
|
|
|
let freshCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
2023-02-02 08:58:12 -08:00
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await freshCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let blockRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
|
|
|
|
|
|
|
|
let fakeBlocks = StubBlockCreator.createBlockRange(blockRange)!
|
|
|
|
|
|
|
|
try await freshCache.write(blocks: fakeBlocks)
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let latestHeight = await freshCache.latestHeight()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
XCTAssertEqual(latestHeight, 2000)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testBlockDescriptorFiltersBlocksGreaterThan() throws {
|
|
|
|
let cacheList = [
|
|
|
|
"1000-DEADBEEF-block",
|
|
|
|
"1001-DEADBEEF1-block",
|
|
|
|
"1002-DEADBEEF2-block",
|
|
|
|
"1003-DEADBEEF3-block",
|
|
|
|
"1004-DEADBEEF4-block",
|
|
|
|
"1005-DEADBEEF5-block",
|
|
|
|
"1006-DEADBEEF6-block",
|
|
|
|
"1007-DEADBEEF7-block",
|
|
|
|
"1008-DEADBEEF8-block",
|
|
|
|
"1009-DEADBEEF9-block",
|
|
|
|
"1010-DEADBEEFA-block"
|
|
|
|
]
|
|
|
|
|
|
|
|
XCTAssertEqual(
|
|
|
|
try cacheList.filter { try $0.filterGreaterThan(1006, with: .live) },
|
|
|
|
[
|
|
|
|
"1007-DEADBEEF7-block",
|
|
|
|
"1008-DEADBEEF8-block",
|
|
|
|
"1009-DEADBEEF9-block",
|
|
|
|
"1010-DEADBEEFA-block"
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testBlockDescriptorFiltersThrowsIfFileDescriptorFails() throws {
|
|
|
|
let cacheList = [
|
|
|
|
"1000-DEADBEEF-block",
|
|
|
|
"1001-DEADBEEF1-block",
|
|
|
|
"1002-DEADBEEF2-block",
|
|
|
|
"1003-DEADBEEF3-block",
|
|
|
|
"1004-DEADBEEF4-block",
|
|
|
|
"1005-DEADBEEF5-block",
|
|
|
|
"a-DEADBEEF6-block",
|
|
|
|
"1007-DEADBEEF7-block",
|
|
|
|
"1008-DEADBEEF8-block",
|
|
|
|
"1009-DEADBEEF9-block",
|
|
|
|
"1010-DEADBEEFA-block"
|
|
|
|
]
|
|
|
|
|
|
|
|
XCTAssertThrowsError(try cacheList.filter { try $0.filterGreaterThan(1006, with: .live) })
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRewindBlockSelectTheProperFilesByName() throws {
|
|
|
|
let cacheList = try [
|
|
|
|
"1000-DEADBEEF-block",
|
|
|
|
"1001-DEADBEEF1-block",
|
|
|
|
"1002-DEADBEEF2-block",
|
|
|
|
"1003-DEADBEEF3-block",
|
|
|
|
"1004-DEADBEEF4-block",
|
|
|
|
"1005-DEADBEEF5-block",
|
|
|
|
"1006-DEADBEEF6-block",
|
|
|
|
"1007-DEADBEEF7-block",
|
|
|
|
"1008-DEADBEEF8-block",
|
|
|
|
"1009-DEADBEEF9-block",
|
|
|
|
"1010-DEADBEEFA-block"
|
|
|
|
].map { filename in
|
|
|
|
var url = self.fsBlockDb.appendingPathComponent(filename)
|
|
|
|
guard self.testFileManager.createFile(atPath: url.path, contents: nil) else {
|
|
|
|
XCTFail("couldn't create file at \(url.absoluteString)")
|
2023-04-24 14:15:20 -07:00
|
|
|
throw "couldn't create file at \(url.path)"
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
var resourceValues = URLResourceValues()
|
|
|
|
resourceValues.name = filename
|
|
|
|
|
|
|
|
try url.setResourceValues(resourceValues)
|
|
|
|
|
|
|
|
return url
|
|
|
|
}
|
|
|
|
|
|
|
|
let expectedDeleteList = try [
|
|
|
|
"1007-DEADBEEF7-block",
|
|
|
|
"1008-DEADBEEF8-block",
|
|
|
|
"1009-DEADBEEF9-block",
|
|
|
|
"1010-DEADBEEFA-block"
|
|
|
|
].reversed().map { filename in
|
|
|
|
var url = self.fsBlockDb.appendingPathComponent(filename)
|
|
|
|
var resourceValues = URLResourceValues()
|
|
|
|
resourceValues.name = filename
|
|
|
|
try url.setResourceValues(resourceValues)
|
|
|
|
return url
|
|
|
|
}
|
|
|
|
|
|
|
|
XCTAssertEqual(
|
|
|
|
try FSCompactBlockRepository.filterBlockFiles(from: cacheList, toRewind: 1006, with: .live),
|
|
|
|
expectedDeleteList
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testClearTheCache() async throws {
|
|
|
|
let fsBlockCache = FSCompactBlockRepository(
|
2023-03-31 10:10:35 -07:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
|
|
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
2023-02-02 08:58:12 -08:00
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.naive,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await fsBlockCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
guard let stubBlocks = StubBlockCreator.createBlockRange(1000 ... 1010) else {
|
|
|
|
XCTFail("Something Happened. Creating Stub blocks failed")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
try await fsBlockCache.write(blocks: stubBlocks)
|
2023-03-27 05:26:47 -07:00
|
|
|
var latestHeight = await fsBlockCache.latestHeight()
|
|
|
|
XCTAssertEqual(latestHeight, 1010)
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
try await fsBlockCache.clear()
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
latestHeight = await fsBlockCache.latestHeight()
|
|
|
|
XCTAssertEqual(latestHeight, .empty())
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
func testCreateDoesntFailWhenAlreadyCreated() async throws {
|
2023-02-02 08:58:12 -08:00
|
|
|
let freshCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-02-02 08:58:12 -08:00
|
|
|
metadataStore: .mock,
|
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await freshCache.create()
|
|
|
|
try await freshCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
|
2023-05-11 04:13:20 -07:00
|
|
|
func testStoringTenSandblastedBlocks() async throws {
|
2023-02-02 08:58:12 -08:00
|
|
|
let realCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
2023-02-02 08:58:12 -08:00
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await realCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
guard let sandblastedBlocks = try SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
|
|
|
XCTFail("failed to create sandblasted blocks")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
try await realCache.write(blocks: sandblastedBlocks)
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let latestHeight = await realCache.latestHeight()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
XCTAssertEqual(latestHeight, 19)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStoringTenSandblastedBlocksFailsAndThrows() async throws {
|
|
|
|
let realCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
2023-02-02 08:58:12 -08:00
|
|
|
blockDescriptor: .live,
|
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
2023-03-22 05:47:32 -07:00
|
|
|
fileWriter: FSBlockFileWriter(writeToURL: { _, _ in throw FixtureError.arbitraryError }),
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await realCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
guard let sandblastedBlocks = try SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
|
|
|
XCTFail("failed to create sandblasted blocks")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
try await realCache.write(blocks: sandblastedBlocks)
|
|
|
|
XCTFail("This call should have failed")
|
|
|
|
} catch {
|
2023-03-29 11:28:24 -07:00
|
|
|
if let error = error as? ZcashError, case let .blockRepositoryWriteBlock(url, _) = error {
|
|
|
|
XCTAssertEqual(url, sandblastedBlocks[0])
|
|
|
|
} else {
|
|
|
|
XCTFail("Unexpected error thrown: \(error)")
|
|
|
|
}
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStoringTenSandblastedBlocksAndRewindFiveThenStoreThemBack() async throws {
|
|
|
|
let realCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
2023-02-02 08:58:12 -08:00
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await realCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
guard let sandblastedBlocks = try SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
|
|
|
XCTFail("failed to create sandblasted blocks")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let startTime = Date()
|
|
|
|
try await realCache.write(blocks: sandblastedBlocks)
|
|
|
|
let endTime = Date()
|
|
|
|
|
|
|
|
let timePassed = startTime.distance(to: endTime)
|
|
|
|
|
|
|
|
XCTAssertLessThan(timePassed, 0.5)
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let latestHeight = await realCache.latestHeight()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
XCTAssertEqual(latestHeight, 19)
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
try await realCache.rewind(to: 14)
|
2023-02-02 08:58:12 -08:00
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let rewoundHeight = await realCache.latestHeight()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
XCTAssertEqual(rewoundHeight, 14)
|
|
|
|
|
|
|
|
let blockSlice = [ZcashCompactBlock](sandblastedBlocks[5...])
|
|
|
|
try await realCache.write(blocks: blockSlice)
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let newLatestHeight = await realCache.latestHeight()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
XCTAssertEqual(newLatestHeight, 19)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testMetadataStoreThrowsWhenRustThrows() async {
|
|
|
|
guard let sandblastedBlocks = try? SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
|
|
|
XCTFail("failed to create sandblasted blocks")
|
|
|
|
return
|
|
|
|
}
|
2023-03-31 10:10:35 -07:00
|
|
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend)
|
2023-04-24 14:15:20 -07:00
|
|
|
await mockBackend.rustBackendMock.setWriteBlocksMetadataBlocksThrowableError(ZcashError.rustWriteBlocksMetadataAllocationProblem)
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
do {
|
2023-03-22 05:47:32 -07:00
|
|
|
try await FSMetadataStore.saveBlocksMeta(
|
|
|
|
sandblastedBlocks,
|
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
rustBackend: mockBackend.rustBackendMock,
|
2023-03-22 05:47:32 -07:00
|
|
|
logger: logger
|
|
|
|
)
|
2023-04-24 14:15:20 -07:00
|
|
|
} catch ZcashError.rustWriteBlocksMetadataAllocationProblem {
|
2023-02-02 08:58:12 -08:00
|
|
|
// this is fine
|
|
|
|
} catch {
|
2023-04-24 14:15:20 -07:00
|
|
|
XCTFail("Expected `CompactBlockRepositoryError.failedToWriteMetadata` but found: \(error)")
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
func testMetadataStoreThrowsWhenRewindFails() async {
|
2023-02-02 08:58:12 -08:00
|
|
|
let expectedHeight = BlockHeight(1000)
|
|
|
|
|
2023-04-24 14:15:20 -07:00
|
|
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend)
|
|
|
|
await mockBackend.rustBackendMock.setRewindCacheToHeightHeightThrowableError(ZcashError.rustRewindToHeight(Int32(expectedHeight), "oops"))
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
do {
|
|
|
|
try await FSMetadataStore.live(
|
2023-02-02 08:58:12 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
rustBackend: mockBackend.rustBackendMock,
|
2023-03-22 05:47:32 -07:00
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
.rewindToHeight(expectedHeight)
|
2023-03-30 03:49:28 -07:00
|
|
|
XCTFail("rewindToHeight should fail")
|
|
|
|
} catch {
|
2023-04-24 14:15:20 -07:00
|
|
|
guard let error = error as? ZcashError else {
|
|
|
|
XCTFail("Expected ZcashError. Found \(error)")
|
2023-02-02 08:58:12 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:15:20 -07:00
|
|
|
switch error {
|
|
|
|
case let .rustRewindToHeight(height, _):
|
|
|
|
XCTAssertEqual(BlockHeight(height), expectedHeight)
|
2023-02-02 08:58:12 -08:00
|
|
|
default:
|
2023-04-24 14:15:20 -07:00
|
|
|
XCTFail("Expected `ZcashError.rustRewindToHeight`. Found \(error)")
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-06 01:00:15 -08:00
|
|
|
// Disabled for now becasue we are not getting consistent results on GA Ci
|
|
|
|
func disable_testPerformanceExample() async throws {
|
2023-02-02 08:58:12 -08:00
|
|
|
// NOTE: performance tests don't work with async code. Thanks Apple!
|
|
|
|
let freshCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: testTempDirectory,
|
2023-03-31 10:10:35 -07:00
|
|
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
2023-02-02 08:58:12 -08:00
|
|
|
blockDescriptor: .live,
|
2023-03-22 05:47:32 -07:00
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
|
|
|
logger: logger
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
try await freshCache.create()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let blockRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
|
|
|
|
|
|
|
|
let fakeBlocks = try SandblastSimulator().sandblast(with: blockRange)!
|
|
|
|
|
|
|
|
let startTime = Date()
|
|
|
|
try await freshCache.write(blocks: fakeBlocks)
|
|
|
|
let endTime = Date()
|
|
|
|
|
2023-03-27 05:26:47 -07:00
|
|
|
let latestHeight = await freshCache.latestHeight()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
XCTAssertEqual(latestHeight, 2000)
|
|
|
|
|
|
|
|
let total = startTime.distance(to: endTime)
|
|
|
|
// let totalKiloBytes = fakeBlocks.map { $0.data.count }.reduce(0, +) / 1024 // 245055
|
|
|
|
XCTAssertGreaterThan(1.5, total)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension FSCompactBlockRepository {
|
|
|
|
static var emptyTemporaryCache: FSCompactBlockRepository {
|
|
|
|
FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: URL(fileURLWithPath: NSString(
|
2023-02-02 08:58:12 -08:00
|
|
|
string: NSTemporaryDirectory()
|
|
|
|
).appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))")),
|
|
|
|
metadataStore: .mock,
|
|
|
|
blockDescriptor: ZcashCompactBlockDescriptor(
|
|
|
|
height: { _ in BlockHeight() },
|
|
|
|
describe: { _ in "123456-deadbeef-block" },
|
|
|
|
compare: { _, _ in nil }
|
|
|
|
),
|
|
|
|
contentProvider: SortedDirectoryContentProvider(
|
|
|
|
fileManager: FileManager.default,
|
|
|
|
sorting: { _, _ in false }
|
2023-03-22 05:47:32 -07:00
|
|
|
),
|
|
|
|
logger: OSLogger(logLevel: .debug)
|
2023-02-02 08:58:12 -08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum FixtureError: Error, Equatable {
|
|
|
|
case arbitraryError
|
|
|
|
}
|
|
|
|
|
|
|
|
extension FSMetadataStore {
|
2023-03-27 05:26:47 -07:00
|
|
|
static let mock = FSMetadataStore(
|
|
|
|
saveBlocksMeta: { _ in },
|
|
|
|
rewindToHeight: { _ in },
|
2023-03-31 10:10:35 -07:00
|
|
|
initFsBlockDbRoot: { },
|
2023-03-27 05:26:47 -07:00
|
|
|
latestHeight: { .empty() }
|
|
|
|
)
|
2023-02-02 08:58:12 -08:00
|
|
|
}
|