ZcashLightClientKit/Tests/DarksideTests/Z2TReceiveTests.swift

236 lines
8.3 KiB
Swift

//
// Z2TReceiveTests.swift
// ZcashLightClientKit-Unit-Tests
//
// Created by Francisco Gindre on 8/4/21.
//
import XCTest
@testable import TestUtils
@testable import ZcashLightClientKit
// swiftlint:disable force_unwrapping implicitly_unwrapped_optional
class Z2TReceiveTests: XCTestCase {
// swiftlint:disable:next line_length
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" // TODO: Parameterize this from environment?
let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" // TODO: Parameterize this from environment
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175
var coordinator: TestCoordinator!
var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent")
var foundTransactionsExpectation = XCTestExpectation(description: "found transactions")
let branchID = "2bb40e60"
let chainName = "main"
let network = DarksideWalletDNetwork()
override func setUpWithError() throws {
try super.setUpWithError()
wait { [self] in
self.coordinator = try await TestCoordinator(
seed: self.seedPhrase,
walletBirthday: self.birthday,
channelProvider: ChannelProvider(),
network: self.network
)
try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName)
}
}
override func tearDownWithError() throws {
try super.tearDownWithError()
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
}
func subscribeToFoundTransactions() {
NotificationCenter.default.addObserver(
self,
selector: #selector(foundTransactions(_:)),
name: .synchronizerFoundTransactions,
object: nil
)
}
@objc func foundTransactions(_ notification: Notification) {
guard notification.userInfo?[SDKSynchronizer.NotificationKeys.foundTransactions] != nil else {
XCTFail("found transactions notification is empty")
return
}
self.foundTransactionsExpectation.fulfill()
}
func testSendingZ2TWithMemoFails() async throws {
subscribeToFoundTransactions()
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
let receivedTxHeight: BlockHeight = 663188
/*
2. applyStaged(received_Tx_height)
*/
try coordinator.applyStaged(blockheight: receivedTxHeight)
sleep(2)
let preTxExpectation = XCTestExpectation(description: "pre receive")
/*
3. sync up to received_Tx_height
*/
try await withCheckedThrowingContinuation { continuation in
do {
try coordinator.sync(completion: { synchronizer in
preTxExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
let sendExpectation = XCTestExpectation(description: "sendToAddress")
let sendAmount = Zatoshi(10000)
/*
4. create transaction
*/
do {
let _ = try await coordinator.synchronizer.sendToAddress(
spendingKey: coordinator.spendingKeys!.first!,
zatoshi: sendAmount,
toAddress: try! Recipient(testRecipientAddress, network: self.network.networkType),
memo: try Memo(string: "test transaction")
)
XCTFail("Should have thrown error")
} catch {
sendExpectation.fulfill()
if case let SynchronizerError.generalError(message) = error {
XCTAssertEqual(message, "Memos can't be sent to transparent addresses.")
} else {
XCTFail("expected SynchronizerError.genericError(\"Memos can't be sent to transparent addresses.\") but received \(error.localizedDescription)")
}
return
}
}
func testFoundTransactions() async throws {
subscribeToFoundTransactions()
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
let receivedTxHeight: BlockHeight = 663188
/*
2. applyStaged(received_Tx_height)
*/
try coordinator.applyStaged(blockheight: receivedTxHeight)
sleep(2)
let preTxExpectation = XCTestExpectation(description: "pre receive")
/*
3. sync up to received_Tx_height
*/
try await withCheckedThrowingContinuation { continuation in
do {
try coordinator.sync(completion: { synchronizer in
preTxExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
let sendExpectation = XCTestExpectation(description: "sendToAddress")
var pendingEntity: PendingTransactionEntity?
var testError: Error?
let sendAmount = Zatoshi(10000)
/*
4. create transaction
*/
do {
let pending = try await coordinator.synchronizer.sendToAddress(
spendingKey: coordinator.spendingKeys!.first!,
zatoshi: sendAmount,
toAddress: try! Recipient(testRecipientAddress, network: self.network.networkType),
memo: nil
)
pendingEntity = pending
sendExpectation.fulfill()
} catch {
testError = error
}
wait(for: [sendExpectation], timeout: 12)
guard pendingEntity != nil else {
XCTFail("error sending to address. Error: \(String(describing: testError))")
return
}
/*
5. stage 10 empty blocks
*/
try coordinator.stageBlockCreate(height: receivedTxHeight + 1, count: 10)
let sentTxHeight = receivedTxHeight + 1
/*
6. stage sent tx at sentTxHeight
*/
guard let sentTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("sent transaction not present on Darksidewalletd")
return
}
try coordinator.stageTransaction(sentTx, at: sentTxHeight)
/*
6a. applyheight(sentTxHeight + 1 )
*/
try coordinator.applyStaged(blockheight: sentTxHeight + 1)
sleep(2)
self.foundTransactionsExpectation = XCTestExpectation(description: "inbound expectation")
/*
7. sync to sentTxHeight + 1
*/
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
try await withCheckedThrowingContinuation { continuation in
do {
try coordinator.sync(completion: { synchronizer in
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
XCTAssertEqual(pMinedHeight, sentTxHeight)
sentTxSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5)
}
func handleError(_ error: Error?) {
_ = try? coordinator.stop()
guard let testError = error else {
XCTFail("failed with nil error")
return
}
XCTFail("Failed with error: \(testError)")
}
}