Skip to content

Commit

Permalink
[trello.com/c/4QaDmVkg]: integration test for BtcWalletService
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisBenua committed Jan 15, 2025
1 parent b663d52 commit 21e3727
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Adamant.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@
AAFB3C932D31C3DC000CCCE9 /* BitcoinKitTransactionFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFB3C922D31C3CD000CCCE9 /* BitcoinKitTransactionFactoryProtocol.swift */; };
AAFB3C952D31C58B000CCCE9 /* BitcoinKitTransactionFactoryProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFB3C942D31C587000CCCE9 /* BitcoinKitTransactionFactoryProtocolMock.swift */; };
AAFB3C972D31CB72000CCCE9 /* UnspentTransaction+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFB3C962D31CB6B000CCCE9 /* UnspentTransaction+Equatable.swift */; };
AAFB3C992D357E1D000CCCE9 /* BtcWalletServiceIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFB3C982D357E16000CCCE9 /* BtcWalletServiceIntegrationTests.swift */; };
E90055F520EBF5DA00D0CB2D /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90055F420EBF5DA00D0CB2D /* AboutViewController.swift */; };
E90055F720EC200900D0CB2D /* SecurityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90055F620EC200900D0CB2D /* SecurityViewController.swift */; };
E90055F920ECD86800D0CB2D /* SecurityViewController+StayIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90055F820ECD86800D0CB2D /* SecurityViewController+StayIn.swift */; };
Expand Down Expand Up @@ -1104,6 +1105,7 @@
AAFB3C922D31C3CD000CCCE9 /* BitcoinKitTransactionFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinKitTransactionFactoryProtocol.swift; sourceTree = "<group>"; };
AAFB3C942D31C587000CCCE9 /* BitcoinKitTransactionFactoryProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinKitTransactionFactoryProtocolMock.swift; sourceTree = "<group>"; };
AAFB3C962D31CB6B000CCCE9 /* UnspentTransaction+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnspentTransaction+Equatable.swift"; sourceTree = "<group>"; };
AAFB3C982D357E16000CCCE9 /* BtcWalletServiceIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BtcWalletServiceIntegrationTests.swift; sourceTree = "<group>"; };
AD258997F050B24C0051CC8D /* Pods-Adamant.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Adamant.release.xcconfig"; path = "Target Support Files/Pods-Adamant/Pods-Adamant.release.xcconfig"; sourceTree = "<group>"; };
ADDFD2FA17E41CCBD11A1733 /* Pods-Adamant.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Adamant.debug.xcconfig"; path = "Target Support Files/Pods-Adamant/Pods-Adamant.debug.xcconfig"; sourceTree = "<group>"; };
E90055F420EBF5DA00D0CB2D /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2245,6 +2247,7 @@
AA33BEB02D303C470083E59C /* Wallets */ = {
isa = PBXGroup;
children = (
AAFB3C982D357E16000CCCE9 /* BtcWalletServiceIntegrationTests.swift */,
AA33BEB12D303C5F0083E59C /* BtcWalletServiceTests.swift */,
);
path = Wallets;
Expand Down Expand Up @@ -3856,6 +3859,7 @@
buildActionMask = 2147483647;
files = (
AAFB3C972D31CB72000CCCE9 /* UnspentTransaction+Equatable.swift in Sources */,
AAFB3C992D357E1D000CCCE9 /* BtcWalletServiceIntegrationTests.swift in Sources */,
AAFB3C8F2D31C119000CCCE9 /* WalletServiceError+Equatable.swift in Sources */,
AA33BEB92D3044760083E59C /* BtcApiServiceProtocolMock.swift in Sources */,
AA33BEB22D303C730083E59C /* BtcWalletServiceTests.swift in Sources */,
Expand Down
119 changes: 119 additions & 0 deletions AdamantTests/Modules/Wallets/BtcWalletServiceIntegrationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// BtcWalletServiceIntegrationTests.swift
// Adamant
//
// Created by Christian Benua on 13.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

import XCTest
@testable import Adamant
import Swinject
import BitcoinKit
import CommonKit

final class BtcWalletServiceIntegrationTests: XCTestCase {

private var apiCoreMock: APICoreProtocolMock!
private var btcApiServiceProtocolMock: BtcApiServiceProtocolMock!
private var sut: BtcWalletService!

override func setUp() {
super.setUp()
apiCoreMock = APICoreProtocolMock()
btcApiServiceProtocolMock = BtcApiServiceProtocolMock()
btcApiServiceProtocolMock.api = BtcApiCore(apiCore: apiCoreMock)

sut = BtcWalletService()
sut.addressConverter = AddressConverterFactory().make(network: .mainnetBTC)
sut.btcApiService = btcApiServiceProtocolMock
sut.btcTransactionFactory = BitcoinKitTransactionFactory()
}

override func tearDown() {
apiCoreMock = nil
btcApiServiceProtocolMock = nil
sut = nil
super.tearDown()
}

func test_createAndSendTransaction_createsValidTxIdAndHash() async throws {
// given
sut.setWalletForTests(try makeWallet())
let data = Constants.unspentTranscationsData
await apiCoreMock.isolated { mock in
mock.stubbedSendRequestBasicGenericResult = APIResponseModel(result: .success(data), data: data, code: 200)
}

// when 1
let result = await Result(catchingAsync: {
try await self.sut.createTransaction(
recipient: "1K4hFg49PaEt5pHCym7yb5B446Vb3roSMp",
amount: 0.00009,
fee: 0.00002159542,
comment: nil
)
})

// then 1
let transaction = try XCTUnwrap(result.value)
XCTAssertEqual(transaction.serialized().hex, Constants.expectedTransactionHex)
XCTAssertEqual(transaction.txID, Constants.expectedTransactionID)

// given 2
let txData = try XCTUnwrap(transaction.txID.data(using: .utf8))
await apiCoreMock.isolated { mock in
mock.stubbedSendRequestBasicGenericResult = APIResponseModel(result: .success(txData), data: txData, code: 200)
}

// when 2
let result2 = await Result {
try await self.sut.sendTransaction(transaction)
}
// then 3
XCTAssertNil(result2.error)
await apiCoreMock.isolated { mock in
XCTAssertEqual(mock.invokedSendRequestBasicGenericCount, 2)
}
}

private func makeWallet() throws -> BtcWallet {
let privateKeyData = Constants.passphrase
.data(using: .utf8)!
.sha256()
let privateKey = PrivateKey(
data: privateKeyData,
network: .mainnetBTC,
isPublicKeyCompressed: true
)
return try BtcWallet(
unicId: "BTCBTC",
privateKey: privateKey,
addressConverter: AddressConverterFactory().make(network: .mainnetBTC)
)
}
}

private enum Constants {

static let passphrase = "village lunch say patrol glow first hurt shiver name method dolphin dead"

static let expectedTransactionID = "e9e99b0d38e3b3fc362a3a9a2809807af179cbaaff59ae7f9ddb3ed30a4f9582"

static let expectedTransactionHex = "0100000001a0d73e3bd0aa2025d91eabd8512d5e19ad80752892f415480f75b97966b06f0e010000006a47304402200f8908e3a4b1c3ab181fa875c15dc8816ec29298a74e78122000d4e08bced3a2022016767a16bb9ea315a9ea9a8536d39bd3e6e8dce3594cf5b17c4576f7bfc39140012102cd3dcbdfc1b77e54b3a8f273310806ab56b0c2463c2f1677c7694a89a713e0d0ffffffff0228230000000000001976a914c6251d0e16c0e1946b745b69caa3a7c36014381088ac38560200000000001976a91457f6f900ac7a7e3ccab712326cd7b85638fc15a888ac00000000"

static let unspentTranscationsData = unspentTranscationsRawJSON.data(using: .utf8)!

static let unspentTranscationsRawJSON: String = """
[{
"txid":"0e6fb06679b9750f4815f492287580ad195e2d51d8ab1ed92520aad03b3ed7a0",
"vout":1,
"status":{
"confirmed":true,
"block_height":879091,
"block_hash":"00000000000000000001e0da09b0792ff69dcd98af264b1750cbf9ef2deab73d",
"block_time":1736786953},
"value":164303
}]
"""
}
41 changes: 41 additions & 0 deletions AdamantTests/Modules/Wallets/BtcWalletServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,41 @@ final class BtcWalletServiceTests: XCTestCase {
)
}

func test_sendTransaction_failIfTxIdCorrupted() async throws {
// given
let txData = try XCTUnwrap(Constants.anotherTransactionId.data(using: .utf8))
await apiCoreMock.isolated { mock in
mock.stubbedSendRequestBasicGenericResult = APIResponseModel(result: .success(txData), data: txData, code: 200)
}

// when
let result = await Result {
try await self.sut.sendTransaction(BitcoinKit.Transaction.deserialize(Data(hex: Constants.transactionHex)!))
}

// then
XCTAssertEqual(
result.error as? WalletServiceError,
WalletServiceError.remoteServiceError(message: Constants.anotherTransactionId)
)
}

func test_sendTransaction_successIfTxIdMatches() async throws {
// given
let txData = try XCTUnwrap(Constants.transactionId.data(using: .utf8))
await apiCoreMock.isolated { mock in
mock.stubbedSendRequestBasicGenericResult = APIResponseModel(result: .success(txData), data: txData, code: 200)
}

// when
let result = await Result {
try await self.sut.sendTransaction(BitcoinKit.Transaction.deserialize(Data(hex: Constants.transactionHex)!))
}

// then
XCTAssertNil(result.error)
}

private func makeWallet(address: String = Constants.btcAddress) throws -> BtcWallet {
let privateKeyData = "my long passphrase"
.data(using: .utf8)!
Expand Down Expand Up @@ -230,6 +265,12 @@ private enum Constants {

static let lockingScript2 = Data([118, 169, 20, 189, 45, 218, 220, 109, 190, 133, 34, 44, 61, 83, 31, 41, 204, 37, 209, 62, 168, 11, 45, 136, 172])

static let transactionId = "8b2654793f94539e5c66b87dee6d0908fb9728eb25c90396e25286c6d4b8a371"

static let anotherTransactionId = String("8b2654793f94539e5c66b87dee6d0908fb9728eb25c90396e25286c6d4b8a371".reversed())

static let transactionHex = "0100000001a0d73e3bd0aa2025d91eabd8512d5e19ad80752892f415480f75b97966b06f0e010000006a473044022072c8ecd3143e663520807c496dba3dc8010478f3cae09fcb65995be29737a55702206d23617cad2f88a3bd28757be956c731dbde06615fb9bb9fabf2d55e6a8f67ba0121037ec9f6126013088b3d1e8f844f3e755144756a4e9a7da6b0094c189f55031934ffffffff0228230000000000001976a914c6251d0e16c0e1946b745b69caa3a7c36014381088ac38560200000000001976a914931ef5cbdad28723ba9596de5da1145ae969a71888ac00000000"

static let expectedTransaction = BitcoinKit.Transaction(
version: 1,
inputs: [
Expand Down

0 comments on commit 21e3727

Please sign in to comment.