Skip to content

Commit

Permalink
test: almost complete ffi wallet test (#3220)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the Title above -->

## Description
Almost complete ffi wallet test.
- The async base node connection is not there.
- The SAF test is broken (the ffi wallet doesn't change the status, but the receiver node has correct status) 

## How Has This Been Tested?
npm test -- .\features\WalletFFI.feature

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
* [x] I'm merging against the `development` branch.
* [x] I have squashed my commits into a single commit.
  • Loading branch information
Cifko authored Aug 20, 2021
1 parent 9c0f7a7 commit 980c526
Show file tree
Hide file tree
Showing 18 changed files with 1,131 additions and 270 deletions.
59 changes: 58 additions & 1 deletion integration_tests/features/WalletFFI.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@ Feature: Wallet FFI
Scenario: As a client I want to receive Tari via my Public Key while I am online
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

@long-running @broken
Scenario: As a client I want to receive Tari via my Public Key sent while I am offline when I come back online
Given I have a base node BASE
And I have wallet SENDER connected to base node BASE
And I have mining node MINER connected to base node BASE and wallet SENDER
And mining node MINER mines 4 blocks
Then I wait for wallet SENDER to have at least 1000000 uT
And I have a ffi wallet FFI_WALLET connected to base node BASE
And I stop wallet FFI_WALLET
And I wait 5 seconds
And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 100
And I wait 5 seconds
And I start wallet FFI_WALLET
And wallet SENDER detects all transactions are at least Broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT

@long-running
Scenario: As a client I want to retrieve a list of transactions I have made and received
Expand All @@ -24,12 +39,16 @@ Feature: Wallet FFI
And wallet SENDER detects all transactions are at least Broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT
And Check callbacks for finished inbound tx on ffi wallet FFI_WALLET
And I have wallet RECEIVER connected to base node BASE
And I send 1000000 uT from ffi wallet FFI_WALLET to wallet RECEIVER at fee 100
And ffi wallet FFI_WALLET has 1 broadcast transaction
And mining node MINER mines 4 blocks
Then I wait for wallet RECEIVER to have at least 1000000 uT
And Check callbacks for finished outbound tx on ffi wallet FFI_WALLET
And I have 1 received and 1 send transaction in ffi wallet FFI_WALLET
And I start STXO validation on wallet FFI_WALLET
And I start UTXO validation on wallet FFI_WALLET

# It's just calling the encrypt function, we don't test if it's actually encrypted
Scenario: As a client I want to be able to protect my wallet with a passphrase
Expand All @@ -47,6 +66,15 @@ Feature: Wallet FFI
Then I don't have contact with alias ALIAS in ffi wallet FFI_WALLET

Scenario: As a client I want to set the base node (should be persisted)
Given I have a base node BASE1
Given I have a base node BASE2
And I have a ffi wallet FFI_WALLET connected to base node BASE1
And I set base node BASE2 for ffi wallet FFI_WALLET
Then BASE2 is connected to FFI_WALLET
And I stop wallet FFI_WALLET
And I wait 5 seconds
And I start wallet FFI_WALLET
Then BASE2 is connected to FFI_WALLET

Scenario: As a client I want to see my public_key, emoji ID, address (whoami)
Given I have a base node BASE
Expand All @@ -57,16 +85,45 @@ Feature: Wallet FFI
Scenario: As a client I want to get my balance
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

@long-running
Scenario: As a client I want to cancel a transaction
Given I have a base node BASE
And I have wallet SENDER connected to base node BASE
And I have mining node MINER connected to base node BASE and wallet SENDER
And mining node MINER mines 4 blocks
Then I wait for wallet SENDER to have at least 1000000 uT
And I have a ffi wallet FFI_WALLET connected to base node BASE
And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 100
And wallet SENDER detects all transactions are at least Broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT
And I have wallet RECEIVER connected to base node BASE
And I stop wallet RECEIVER
And I send 1000000 uT from ffi wallet FFI_WALLET to wallet RECEIVER at fee 100
Then I wait for ffi wallet FFI_WALLET to have 1 pending outbound transaction
Then I cancel all transactions on ffi wallet FFI_WALLET and it will cancel 1 transaction

@long-running
Scenario: As a client I want to be able to restore my wallet from seed words
Given I have a base node BASE
And I have wallet WALLET connected to base node BASE
And I have mining node MINER connected to base node BASE and wallet WALLET
And mining node MINER mines 4 blocks
Then I wait for wallet WALLET to have at least 1000000 uT
Then I recover wallet WALLET into ffi wallet FFI_WALLET from seed words on node BASE
And I wait for recovery of wallet FFI_WALLET to finish
And I wait for ffi wallet FFI_WALLET to have at least 1000000 uT

Scenario: AS a client I want to be able to initiate TXO and TX validation with the specifed base node.
Scenario: As a client I want to be able to initiate TXO and TX validation with the specifed base node.
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

Scenario: As a client I want async feedback about the progress of sending and receiving a transaction
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

Scenario: As a client I want async feedback about my connection status to the specifed Base Node

Scenario: As a client I want async feedback about the wallet restoration process
# As a client I want to be able to restore my wallet from seed words

Scenario: As a client I want async feedback about TXO and TX validation processes
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"
118 changes: 113 additions & 5 deletions integration_tests/features/support/steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -3365,17 +3365,19 @@ Then(
"I wait for ffi wallet {word} to have at least {int} uT",
{ timeout: 60 * 1000 },
async function (name, amount) {
let success = false;
let wallet = this.getWallet(name);
let retries = 1;
let balance = 0;
const retries_limit = 12;
while (!success && retries <= retries_limit) {
if ((await this.getWallet(name).getBalance()) >= amount) {
success = true;
while (retries <= retries_limit) {
balance = await wallet.getBalance();
if (balance >= amount) {
break;
}
await sleep(5000);
++retries;
}
expect(success).to.be.true;
expect(balance, "Balance is not enough").to.be.greaterThanOrEqual(amount);
}
);

Expand Down Expand Up @@ -3501,3 +3503,109 @@ Then(
}
}
);

When(
"I set base node {word} for ffi wallet {word}",
async function (node, wallet_name) {
let wallet = this.getWallet(wallet_name);
let peer = this.nodes[node].peerAddress().split("::");
await wallet.addBaseNodePeer(peer[0], peer[1]);
}
);

Then(
"I wait for ffi wallet {word} to have {int} pending outbound transaction(s)",
{ timeout: 120 * 1000 },
async function (wallet_name, count) {
let wallet = this.getWallet(wallet_name);
let broadcast = await wallet.getOutboundTransactionsCount();
let retries = 1;
const retries_limit = 24;
while (broadcast != count && retries <= retries_limit) {
await sleep(5000);
broadcast = await wallet.getOutboundTransactionsCount();
++retries;
}
expect(broadcast, "Number of pending messages mismatch").to.be.equal(count);
}
);

Then(
"I cancel all transactions on ffi wallet {word} and it will cancel {int} transaction",
async function (wallet_name, count) {
const wallet = this.getWallet(wallet_name);
expect(
await wallet.cancelAllOutboundTransactions(),
"Number of cancelled transactions"
).to.be.equal(count);
}
);

Then(
"I recover wallet {word} into ffi wallet {word} from seed words on node {word}",
{ timeout: 20 * 1000 },
async function (wallet_name, ffi_wallet_name, node) {
let wallet = this.getWallet(wallet_name);
const seed_words_text = wallet.getSeedWords();
await wallet.stop();
await sleep(1000);
let ffi_wallet = await this.createAndAddFFIWallet(
ffi_wallet_name,
seed_words_text
);
let peer = this.nodes[node].peerAddress().split("::");
await ffi_wallet.addBaseNodePeer(peer[0], peer[1]);
await ffi_wallet.startRecovery(peer[0]);
}
);

Then(
"I wait for recovery of wallet {word} to finish",
{ timeout: 600 * 1000 },
async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
while (wallet.recoveryInProgress) {
await sleep(1000);
}
expect(wallet.recoveryProgress[1]).to.be.greaterThan(0);
expect(wallet.recoveryProgress[0]).to.be.equal(wallet.recoveryProgress[1]);
}
);

Then("I start STXO validation on wallet {word}", async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
await wallet.startStxoValidation();
while (!wallet.stxo_validation_complete) {
await sleep(1000);
}
expect(wallet.stxo_validation_result).to.be.equal(0);
});

Then("I start UTXO validation on wallet {word}", async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
await wallet.startUtxoValidation();
while (!wallet.utxo_validation_complete) {
await sleep(1000);
}
expect(wallet.utxo_validation_result).to.be.equal(0);
});

Then(
"Check callbacks for finished inbound tx on ffi wallet {word}",
async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
expect(wallet.receivedTransaction).to.be.greaterThanOrEqual(1);
expect(wallet.transactionBroadcast).to.be.greaterThanOrEqual(1);
wallet.clearCallbackCounters();
}
);

Then(
"Check callbacks for finished outbound tx on ffi wallet {word}",
async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
expect(wallet.receivedTransactionReply).to.be.greaterThanOrEqual(1);
expect(wallet.transactionBroadcast).to.be.greaterThanOrEqual(1);
wallet.clearCallbackCounters();
}
);
8 changes: 6 additions & 2 deletions integration_tests/features/support/world.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class CustomWorld {
this.walletPubkeys[name] = walletInfo.public_key;
}

async createAndAddFFIWallet(name) {
async createAndAddFFIWallet(name, seed_words) {
const wallet = new WalletFFIClient(name);
await wallet.startNew();
await wallet.startNew(seed_words);
this.walletsFFI[name] = wallet;
this.walletPubkeys[name] = await wallet.getPublicKey();
return wallet;
Expand Down Expand Up @@ -230,6 +230,10 @@ class CustomWorld {
client.isWallet = true;
return client;
}
let ffi_wallet = this.walletsFFI[name.trim()];
if (ffi_wallet) {
return ffi_wallet;
}
return null;
}

Expand Down
29 changes: 29 additions & 0 deletions integration_tests/helpers/ffi/byteVector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const WalletFFI = require("./walletFFI");

class ByteVector {
#byte_vector_ptr;

constructor(byte_vector_ptr) {
this.#byte_vector_ptr = byte_vector_ptr;
}

static async fromBuffer(buffer) {
let buf = Buffer.from(buffer, "utf-8"); // get the bytes
let len = buf.length; // get the length
return new ByteVector(await WalletFFI.byteVectorCreate(buf, len));
}

getLength() {
return WalletFFI.byteVectorGetLength(this.#byte_vector_ptr);
}

getAt(position) {
return WalletFFI.byteVectorGetAt(this.#byte_vector_ptr, position);
}

destroy() {
return WalletFFI.byteVectorDestroy(this.#byte_vector_ptr);
}
}

module.exports = ByteVector;
23 changes: 23 additions & 0 deletions integration_tests/helpers/ffi/completedTransaction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const WalletFFI = require("./walletFFI");

class CompletedTransaction {
#tari_completed_transaction_ptr;

constructor(tari_completed_transaction_ptr) {
this.#tari_completed_transaction_ptr = tari_completed_transaction_ptr;
}

isOutbound() {
return WalletFFI.completedTransactionIsOutbound(
this.#tari_completed_transaction_ptr
);
}

destroy() {
return WalletFFI.completedTransactionDestroy(
this.#tari_completed_transaction_ptr
);
}
}

module.exports = CompletedTransaction;
39 changes: 39 additions & 0 deletions integration_tests/helpers/ffi/completedTransactions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const CompletedTransaction = require("./completedTransaction");
const WalletFFI = require("./walletFFI");

class CompletedTransactions {
#tari_completed_transactions_ptr;

constructor(tari_completed_transactions_ptr) {
this.#tari_completed_transactions_ptr = tari_completed_transactions_ptr;
}

static async fromWallet(wallet) {
return new CompletedTransactions(
await WalletFFI.walletGetCompletedTransactions(wallet)
);
}

getLength() {
return WalletFFI.completedTransactionsGetLength(
this.#tari_completed_transactions_ptr
);
}

async getAt(position) {
return new CompletedTransaction(
await WalletFFI.completedTransactionsGetAt(
this.#tari_completed_transactions_ptr,
position
)
);
}

destroy() {
return WalletFFI.completedTransactionsDestroy(
this.#tari_completed_transactions_ptr
);
}
}

module.exports = CompletedTransactions;
33 changes: 33 additions & 0 deletions integration_tests/helpers/ffi/contact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const PublicKey = require("./publicKey");
const WalletFFI = require("./walletFFI");

class Contact {
#tari_contact_ptr;

constructor(tari_contact_ptr) {
this.#tari_contact_ptr = tari_contact_ptr;
}

getPtr() {
return this.#tari_contact_ptr;
}

async getAlias() {
const alias = await WalletFFI.contactGetAlias(this.#tari_contact_ptr);
const result = alias.readCString();
await WalletFFI.stringDestroy(alias);
return result;
}

async getPubkey() {
return new PublicKey(
await WalletFFI.contactGetPublicKey(this.#tari_contact_ptr)
);
}

destroy() {
return WalletFFI.contactDestroy(this.#tari_contact_ptr);
}
}

module.exports = Contact;
Loading

0 comments on commit 980c526

Please sign in to comment.