ZcashLightClientKit/Tests/OfflineTests/PendingTransactionRepositor...

182 lines
5.8 KiB
Swift
Raw Normal View History

//
// PendingTransactionRepositoryTests.swift
// ZcashLightClientKit-Unit-Tests
//
// Created by Francisco Gindre on 11/27/19.
//
import XCTest
2022-02-28 09:03:20 -08:00
@testable import TestUtils
@testable import ZcashLightClientKit
2021-09-23 06:26:41 -07:00
class PendingTransactionRepositoryTests: XCTestCase {
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
let recipient = SaplingAddress(validatedEncoding: "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6")
2021-09-23 06:26:41 -07:00
var pendingRepository: PendingTransactionRepository!
override func setUp() {
2021-09-23 06:26:41 -07:00
super.setUp()
cleanUpDb()
let pendingDbProvider = SimpleConnectionProvider(path: try! TestDbBuilder.pendingTransactionsDbURL().absoluteString)
- [#679] Implementation of the File-system based block cache (#679) Closes https://github.com/zcash/ZcashLightClientKit/issues/697 Closes https://github.com/zcash/ZcashLightClientKit/issues/720 Closes https://github.com/zcash/ZcashLightClientKit/issues/587 Closes https://github.com/zcash/ZcashLightClientKit/issues/667 Closes https://github.com/zcash/ZcashLightClientKit/issues/443 Closes https://github.com/zcash/ZcashLightClientKit/issues/754 - [#790] Fix ShieldFundsTests Closes #790 Removes comments on `ShieldFundsTests` since those issues have been fixed Depends on zcash-light-client-ffi changes that adopt newer versions of librustzcash crates `zcash_primitives 0.10`, `zcash_client_backend 0.7`, `zcash_proofs 0.10`, `zcash_client_sqlite 0.5.0`. Also allows wallets to define a shielding_threshold and will set foundations to customize minimum confirmations for balances, spends and shielding operations. **Test Bootstrapping** - `ZcashCompactBlockDescriptor`: struct that holds functions to describe blocks as filenames and compare those filenames `ZcashCompactBlockDescriptor.live` has the actual implementation but it can be replaced by mocks if needed on Tests main implementations are held under `FSCompactBlockRepository.filenameDescription` and `FSCompactBlockRepository.filenameComparison` on a separate extention `DirectoryListingProviders` provide two default implementations of listing a directory deterministically. `FileManager` does not define a sorting and needs to be done in-memory by calling `.sorted()` on the resulting collection. If this is a big toll on performance it can be changed to a POSIX implementation but this is good for now. `ZcashCompactBlockDescriptor` adds a `height` helper function to turn a filename into the height of the block stored. Implemented `func latestHeight() throws -> BlockHeight ` that returns the blockheight by querying the cache directory in a sorted fashion and getting the last value and turning the filename into a `BlockHeight` Added `Meta` struct to ZcashCompactBlock. Tests implemented: - `filterBlockFiles` - `testClearTheCache` - `testLatestHeightEmptyCacheThrows` - `testLatestHeightEmptyCacheThrowsAsync` - `testRewindEmptyCacheDoesNothing` - `testRewindEmptyCacheDoesNothingAsync` - `testWhenBlockIsStoredItFollowsTheDescribedFormat` - `testWhenBlockIsStoredItFollowsTheFilenameConvention` - `testGetLatestHeight` - `testRewindDeletesTheRightBlocks` test - `testPerformanceExample` test. This isn't a real performance test because the API doesn't work with async/await yet adopts `shield_funds` shielding threshold parameter Implements `initBlockMetadataDb` and fix tests Renames dbCache parameter to `fsBlockDbRoot`. Builds but tests don't pass. Removes cacheDb uses from code. Testing utilities still persist. Added needed information in MIGRATING and CHANGELOG. Added helper to perform deletion of legacy db and creation a the new file system backed cache. Renames parameters and changes code where needed. Network Constants turned into `enum` with static methods. DeletelastDownloadedBlock helper from initializer Removes CompactBlockStorage and CompactBlockEntity. Implements `latestCachedBlockHeight` on rustbackend. *Replaces dependencies on ZcashRustWelding with `FSMetadataStore`* This allows the tests to not depend in a particular implementation of either the MockRustBackend of or ZcashRustBackend. Also provides a way to test errors properly and switch implementations of critical areas like `writeBlocks`.
2023-02-02 08:58:12 -08:00
let migrations = MigrationManager(pendingDbConnection: pendingDbProvider, networkType: .testnet)
try! migrations.performMigration()
pendingRepository = PendingTransactionSQLDAO(dbProvider: pendingDbProvider)
}
override func tearDown() {
2021-09-23 06:26:41 -07:00
super.tearDown()
cleanUpDb()
2023-02-16 08:14:31 -08:00
pendingRepository = nil
}
func cleanUpDb() {
try? FileManager.default.removeItem(at: TestDbBuilder.pendingTransactionsDbURL())
}
func testCreate() {
2021-09-23 06:26:41 -07:00
let transaction = createAndStoreMockedTransaction()
2021-09-23 06:26:41 -07:00
guard let id = transaction.id, id >= 0 else {
XCTFail("failed to create mocked transaction that was just inserted")
return
}
var expectedTx: PendingTransactionEntity?
2021-09-23 06:26:41 -07:00
XCTAssertNoThrow(try { expectedTx = try pendingRepository.find(by: id) }())
guard let expected = expectedTx else {
XCTFail("failed to retrieve mocked transaction by id \(id) that was just inserted")
return
}
2021-09-23 06:26:41 -07:00
XCTAssertEqual(transaction.accountIndex, expected.accountIndex)
XCTAssertEqual(transaction.value, expected.value)
XCTAssertEqual(transaction.recipient, expected.recipient)
}
func testFindById() {
2021-09-23 06:26:41 -07:00
let transaction = createAndStoreMockedTransaction()
var expected: PendingTransactionEntity?
2021-09-23 06:26:41 -07:00
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
2021-09-23 06:26:41 -07:00
XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id) }())
XCTAssertNotNil(expected)
}
func testCancel() {
2021-09-23 06:26:41 -07:00
let transaction = createAndStoreMockedTransaction()
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
guard id >= 0 else {
XCTFail("failed to create mocked transaction that was just inserted")
return
}
2021-09-23 06:26:41 -07:00
XCTAssertNoThrow(try pendingRepository.cancel(transaction))
}
func testDelete() {
2021-09-23 06:26:41 -07:00
let transaction = createAndStoreMockedTransaction()
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
guard id >= 0 else {
XCTFail("failed to create mocked transaction that was just inserted")
return
}
2021-09-23 06:26:41 -07:00
XCTAssertNoThrow(try pendingRepository.delete(transaction))
var unexpectedTx: PendingTransactionEntity?
XCTAssertNoThrow(try { unexpectedTx = try pendingRepository.find(by: id) }())
XCTAssertNil(unexpectedTx)
}
func testGetAll() {
2021-09-23 06:26:41 -07:00
var mockTransactions: [PendingTransactionEntity] = []
for _ in 1...100 {
mockTransactions.append(createAndStoreMockedTransaction())
}
var all: [PendingTransactionEntity]?
XCTAssertNoThrow(try { all = try pendingRepository.getAll() }())
guard let allTxs = all else {
XCTFail("failed to get all transactions")
return
}
XCTAssertEqual(mockTransactions.count, allTxs.count)
}
func testUpdate() {
2021-09-23 06:26:41 -07:00
let transaction = createAndStoreMockedTransaction()
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
var stored: PendingTransactionEntity?
2021-09-23 06:26:41 -07:00
XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id) }())
guard stored != nil else {
XCTFail("failed to store tx")
return
}
2022-10-17 13:54:04 -07:00
let oldEncodeAttempts = stored!.encodeAttempts
let oldSubmitAttempts = stored!.submitAttempts
2022-10-17 13:54:04 -07:00
stored!.encodeAttempts += 1
stored!.submitAttempts += 5
XCTAssertNoThrow(try pendingRepository.update(stored!))
guard let updatedTransaction = try? pendingRepository.find(by: stored!.id!) else {
XCTFail("failed to retrieve updated transaction with id: \(stored!.id!)")
return
}
2022-10-17 13:54:04 -07:00
XCTAssertEqual(updatedTransaction.encodeAttempts, oldEncodeAttempts + 1)
XCTAssertEqual(updatedTransaction.submitAttempts, oldSubmitAttempts + 5)
XCTAssertEqual(updatedTransaction.recipient, stored!.recipient)
}
func createAndStoreMockedTransaction(with value: Zatoshi = Zatoshi(1000)) -> PendingTransactionEntity {
var transaction = mockTransaction(with: value)
var id: Int?
2021-09-23 06:26:41 -07:00
XCTAssertNoThrow(try { id = try pendingRepository.create(transaction) }())
transaction.id = Int(id ?? -1)
return transaction
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
_ = try! pendingRepository.getAll()
}
}
private func mockTransaction(with value: Zatoshi = Zatoshi(1000)) -> PendingTransactionEntity {
PendingTransaction(value: value, recipient: .address(.sapling(recipient)), memo: .empty(), account: 0)
}
}