taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 78b715dc4b302cd1a79ccf001c83a6630fcf5cf9
parent d80a79a8ea7dd60009c5b11a4f996ca58c822628
Author: Antoine A <>
Date:   Wed, 30 Apr 2025 20:05:58 +0200

harness: improve P2P tests

Diffstat:
Mpackages/taler-harness/src/integrationtests/test-peer-pull.ts | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mpackages/taler-harness/src/integrationtests/test-peer-push.ts | 143++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 179 insertions(+), 43 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-peer-pull.ts b/packages/taler-harness/src/integrationtests/test-peer-pull.ts @@ -75,8 +75,8 @@ export async function runPeerPullTest(t: GlobalTestState) { await withdrawRes.withdrawalFinishedCond; })); - async function init_peer_pull_credit(w: WalletClient, summary: string, amount: AmountString = "TESTKUDOS:2"): Promise<TransactionPeerPullCredit> { - const initiate = await w.call( + async function initPeerPullCredit(summary: string, amount: AmountString = "TESTKUDOS:2"): Promise<TransactionPeerPullCredit> { + const initiate = await wallet1.call( WalletApiOperation.InitiatePeerPullCredit, { exchangeBaseUrl: exchange.baseUrl, @@ -88,7 +88,7 @@ export async function runPeerPullTest(t: GlobalTestState) { }, ); - await w.call(WalletApiOperation.TestingWaitTransactionState, { + await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { transactionId: initiate.transactionId, txState: { major: TransactionMajorState.Pending, @@ -96,7 +96,7 @@ export async function runPeerPullTest(t: GlobalTestState) { }, }); - const tx = await w.call(WalletApiOperation.GetTransactionById, { + const tx = await wallet1.call(WalletApiOperation.GetTransactionById, { transactionId: initiate.transactionId, }); t.assertDeepEqual(tx.type, TransactionType.PeerPullCredit); @@ -137,7 +137,7 @@ export async function runPeerPullTest(t: GlobalTestState) { t.logStep("P2P pull errors"); { - const tx = await init_peer_pull_credit(wallet1, "confirm", "TESTKUDOS:1000"); + const tx = await initPeerPullCredit("confirm", "TESTKUDOS:1000"); const insufficient_balance = await t.assertThrowsTalerErrorAsync(wallet1.call( WalletApiOperation.PreparePeerPullDebit, { talerUri: tx.talerUri! } @@ -154,7 +154,7 @@ export async function runPeerPullTest(t: GlobalTestState) { t.logStep("P2P pull confirm"); { - const tx = await init_peer_pull_credit(wallet1, "confirm"); + const tx = await initPeerPullCredit("confirm"); const [prepare2, prepare3, prepare4] = await Promise.all([wallet2, wallet3, wallet4].map(w => w.call( @@ -224,7 +224,7 @@ export async function runPeerPullTest(t: GlobalTestState) { t.logStep("P2P pull self"); { - const tx = await init_peer_pull_credit(wallet1, "self"); + const tx = await initPeerPullCredit("self"); const prepare = await wallet1.call( WalletApiOperation.PreparePeerPullDebit, { talerUri: tx.talerUri! } @@ -256,7 +256,7 @@ export async function runPeerPullTest(t: GlobalTestState) { t.logStep("P2P pull conflict"); { - const tx = await init_peer_pull_credit(wallet1, "conflict"); + const tx = await initPeerPullCredit("conflict"); const [prepare2, prepare3] = await Promise.all([wallet2, wallet3].map(w => w.call( @@ -319,7 +319,7 @@ export async function runPeerPullTest(t: GlobalTestState) { t.logStep("P2P pull abort"); { - const tx = await init_peer_pull_credit(wallet1, "abort"); + const tx = await initPeerPullCredit("abort"); const [prepare2, prepare3] = await Promise.all([wallet2, wallet3].map(w => w.call( @@ -365,9 +365,46 @@ export async function runPeerPullTest(t: GlobalTestState) { t.assertTrue(aborted_contract.errorDetail.code === TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION); } + t.logStep("P2P pull abort before create purse"); + { + // Make sure the reserve can't be created. + // This will test the case where the transaction is aborted + // before the purse could even have been created. + await exchange.stop(); + const initiate = await wallet1.call( + WalletApiOperation.InitiatePeerPullCredit, + { + exchangeBaseUrl: exchange.baseUrl, + partialContractTerms: { + summary: "abort before purse creation", + amount: "TESTKUDOS:5", + purse_expiration, + }, + }, + ); + await wallet1.call(WalletApiOperation.AbortTransaction, { + transactionId: initiate.transactionId, + }); + await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: initiate.transactionId, + txState: { + major: TransactionMajorState.Aborting, + minor: TransactionMinorState.DeletePurse, + }, + }); + // Restart the exchange for the remainder of the test + await exchange.start(); + await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: initiate.transactionId, + txState: { + major: TransactionMajorState.Aborted, + }, + }); + } + t.logStep("P2P pull expire"); { - const tx = await init_peer_pull_credit(wallet1, "expire"); + const tx = await initPeerPullCredit("expire"); const [prepare2, prepare3] = await Promise.all([wallet2, wallet3].map(w => w.call( @@ -382,9 +419,7 @@ export async function runPeerPullTest(t: GlobalTestState) { await exchange.stop(); exchange.setTimetravel(timetravelOffsetMs); - await exchange.start(); - await exchange.pingUntilAvailable(); - await exchange.runExpireOnce(); + await Promise.all([exchange.start(), exchange.runExpireOnce()]); await Promise.all([wallet1, wallet2, wallet3].map(w => w.call(WalletApiOperation.TestingSetTimetravel, { @@ -423,6 +458,24 @@ export async function runPeerPullTest(t: GlobalTestState) { )); t.assertTrue(expired_purse.errorDetail.code === TalerErrorCode.WALLET_PEER_PULL_DEBIT_PURSE_GONE); } + + await t.runSpanAsync("P2P pull delete", async () => { + const delAll = async (w: WalletClient) => { + const txn1 = await w.call(WalletApiOperation.GetTransactionsV2, { + includeAll: true, + }); + for (const txn of txn1.transactions) { + await w.call(WalletApiOperation.DeleteTransaction, { + transactionId: txn.transactionId, + }); + } + const txn2 = await w.call(WalletApiOperation.GetTransactionsV2, { + includeAll: true, + }); + t.assertDeepEqual(txn2.transactions.length, 0); + }; + await Promise.all([wallet1, wallet2, wallet3, wallet4].map(delAll)) + }); } runPeerPullTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/test-peer-push.ts b/packages/taler-harness/src/integrationtests/test-peer-push.ts @@ -68,7 +68,6 @@ export async function runPeerPushTest(t: GlobalTestState) { await withdrawRes.withdrawalFinishedCond; async function initPeerPushDebit( - w: WalletClient, summary: string, amount: AmountString = "TESTKUDOS:5", ): Promise<TransactionPeerPushDebit> { @@ -149,13 +148,13 @@ export async function runPeerPushTest(t: GlobalTestState) { // FIXME this should fail with a proper error code t.assertTrue( unknown_purse.errorDetail.code === - TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, + TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, ); } t.logStep("P2P push confirm"); { - const tx = await initPeerPushDebit(wallet1, "confirm"); + const tx = await initPeerPushDebit("confirm"); // Check balance update { @@ -178,14 +177,12 @@ export async function runPeerPushTest(t: GlobalTestState) { t.assertTrue(prepare2.transactionId === idempotent.transactionId); } - await Promise.all([ - wallet2.call(WalletApiOperation.ConfirmPeerPushCredit, { - transactionId: prepare2.transactionId, - }), - wallet3.call(WalletApiOperation.ConfirmPeerPushCredit, { - transactionId: prepare3.transactionId, - }), - ]); + await wallet2.call(WalletApiOperation.ConfirmPeerPushCredit, { + transactionId: prepare2.transactionId, + }); + await wallet3.call(WalletApiOperation.ConfirmPeerPushCredit, { + transactionId: prepare3.transactionId, + }); // Idempotent await Promise.all([ @@ -258,9 +255,104 @@ export async function runPeerPushTest(t: GlobalTestState) { // FIXME this should also fail } + t.logStep("P2P pull self"); + { + const tx = await initPeerPushDebit("self"); + const prepare = await wallet1.call( + WalletApiOperation.PreparePeerPushCredit, + { talerUri: tx.talerUri! } + ); + await wallet1.call(WalletApiOperation.ConfirmPeerPushCredit, { + transactionId: prepare.transactionId, + }) + await Promise.all([ + wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: tx.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + ]); + + // Check scan after completion + const idempotent = await wallet1.call(WalletApiOperation.PreparePeerPushCredit, + { talerUri: tx.talerUri! } + ); + t.assertTrue(prepare.transactionId === idempotent.transactionId); + } + + t.logStep("P2P pull conflict"); + { + const tx = await initPeerPushDebit("conflict"); + + const [prepare2, prepare3] = await Promise.all([wallet2, wallet3].map(w => + w.call( + WalletApiOperation.PreparePeerPushCredit, + { talerUri: tx.talerUri! } + )) + ); + + await exchange.stop(); + + await Promise.all([ + wallet2.call(WalletApiOperation.ConfirmPeerPushCredit, { + transactionId: prepare2.transactionId, + }), + wallet3.call(WalletApiOperation.ConfirmPeerPushCredit, { + transactionId: prepare3.transactionId, + }), + ]); + + await exchange.start() + await Promise.all([ + wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: tx.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + Promise.race([ + Promise.all([ + wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Aborted, + }, + }), + ]), + Promise.all([ + wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Aborted, + }, + }), + wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + ]) + ]) + ]); + } + t.logStep("P2P push abort"); { - const tx = await initPeerPushDebit(wallet1, "abort"); + const tx = await initPeerPushDebit("abort"); const [prepare2, prepare3] = await Promise.all( [wallet2, wallet3].map((w) => @@ -298,9 +390,6 @@ export async function runPeerPushTest(t: GlobalTestState) { }, }), ]); - - const bal = await wallet1.call(WalletApiOperation.GetBalances, {}); - t.assertAmountEquals(bal.balances[0].available, "TESTKUDOS:189.99"); } await t.runSpanAsync("P2P push abort before create purse", async () => { @@ -308,21 +397,21 @@ export async function runPeerPushTest(t: GlobalTestState) { // This will test the case where the transaction is aborted // before the purse could even have been created. await exchange.stop(); - const initResp = await wallet1.call( + const initiate = await wallet1.call( WalletApiOperation.InitiatePeerPushDebit, { partialContractTerms: { - summary: "foo", + summary: "abort before purse creation", amount: "TESTKUDOS:5", purse_expiration: purseExpiration, }, }, ); await wallet1.call(WalletApiOperation.AbortTransaction, { - transactionId: initResp.transactionId, + transactionId: initiate.transactionId, }); await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: initResp.transactionId, + transactionId: initiate.transactionId, txState: { major: TransactionMajorState.Aborting, minor: TransactionMinorState.DeletePurse, @@ -331,7 +420,7 @@ export async function runPeerPushTest(t: GlobalTestState) { // Restart the exchange for the remainder of the test await exchange.start(); await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: initResp.transactionId, + transactionId: initiate.transactionId, txState: { major: TransactionMajorState.Aborted, }, @@ -340,7 +429,7 @@ export async function runPeerPushTest(t: GlobalTestState) { t.logStep("P2P push expire"); { - const tx = await initPeerPushDebit(wallet1, "expire"); + const tx = await initPeerPushDebit("expire"); const [prepare2, prepare3] = await Promise.all( [wallet2, wallet3].map((w) => @@ -356,9 +445,7 @@ export async function runPeerPushTest(t: GlobalTestState) { await exchange.stop(); exchange.setTimetravel(timetravelOffsetMs); - await exchange.start(); - await exchange.pingUntilAvailable(); - await exchange.runExpireOnce(); + await Promise.all([exchange.start(), exchange.runExpireOnce()]); await Promise.all( [wallet1, wallet2, wallet3].map((w) => @@ -398,7 +485,7 @@ export async function runPeerPushTest(t: GlobalTestState) { // Test deleting p2p transaction. // Tests against a regression. - await t.runSpanAsync("delete-transactions", async () => { + await t.runSpanAsync("P2P push delete", async () => { const delAll = async (w: WalletClient) => { const txn1 = await w.call(WalletApiOperation.GetTransactionsV2, { includeAll: true, @@ -413,12 +500,8 @@ export async function runPeerPushTest(t: GlobalTestState) { }); t.assertDeepEqual(txn2.transactions.length, 0); }; - await delAll(wallet1); - await delAll(wallet2); - await delAll(wallet3); - await delAll(wallet4); + await Promise.all([wallet1, wallet2, wallet3, wallet4].map(delAll)) }); } runPeerPushTest.suites = ["wallet"]; -runPeerPushTest.timeoutMs = 120000;