taler-typescript-core

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

commit d9e4d8ec33936c27c6f101760b29de6ecfd1075e
parent c66a050c17f817b853ab4818f9487ce95608a005
Author: Sebastian <sebasjm@gmail.com>
Date:   Mon, 21 Apr 2025 12:39:40 -0300

test for #9695

Diffstat:
Apackages/taler-harness/src/integrationtests/test-deposit-merge.ts | 295+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-harness/src/integrationtests/testrunner.ts | 2++
2 files changed, 297 insertions(+), 0 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-deposit-merge.ts b/packages/taler-harness/src/integrationtests/test-deposit-merge.ts @@ -0,0 +1,295 @@ +/* + This file is part of GNU Taler + (C) 2020 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * Imports. + */ +import { + AmountString, + Duration, + NotificationType, + TransactionIdStr, + TransactionMajorState, + TransactionMinorState, + j2s, +} from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { + GlobalTestState, + getTestHarnessPaytoForLabel, +} from "../harness/harness.js"; +import { + createSimpleTestkudosEnvironmentV3, + withdrawViaBankV3, +} from "../harness/environments.js"; + +/** + * Run test for basic, bank-integrated withdrawal and payment. + */ +export async function runDepositMergeTest(t: GlobalTestState) { + // Set up test environment + + const { walletClient, bankClient, exchange } = + await createSimpleTestkudosEnvironmentV3(t); + + // Withdraw digital cash into the wallet. + + const withdrawalResult = await withdrawViaBankV3(t, { + walletClient, + bankClient, + exchange, + amount: "TESTKUDOS:50", + }); + + await withdrawalResult.withdrawalFinishedCond; + + const depositPaytoUri = getTestHarnessPaytoForLabel("foo"); + const bal = await walletClient.call(WalletApiOperation.GetBalances, {}); + t.assertAmountEquals(bal.balances[0].available, "TESTKUDOS:49.01"); + + /** + * first deposit + */ + let d1Id: TransactionIdStr; + let d1Track: Promise<boolean>; + let d1Done: Promise<boolean>; + { + const { transactionId: depositTxId } = await walletClient.client.call( + WalletApiOperation.GenerateDepositGroupTxId, + {}, + ); + + d1Track = walletClient.waitForNotificationCond( + (n) => + n.type == NotificationType.TransactionStateTransition && + n.transactionId == depositTxId && + n.newTxState.major == TransactionMajorState.Finalizing && + n.newTxState.minor == TransactionMinorState.Track, + ); + + d1Done = walletClient.waitForNotificationCond( + (n) => + n.type == NotificationType.TransactionStateTransition && + n.transactionId == depositTxId && + n.newTxState.major == TransactionMajorState.Done, + ); + + const depositGroupResult = await walletClient.client.call( + WalletApiOperation.CreateDepositGroup, + { + amount: "TESTKUDOS:3" as AmountString, + depositPaytoUri, + transactionId: depositTxId, + }, + ); + + t.assertDeepEqual(depositGroupResult.transactionId, depositTxId); + d1Id = depositGroupResult.transactionId; + } + + await d1Track; + await exchange.stop(); + // @ts-ignore duration is not forever + exchange.setTimetravel(Duration.fromSpec({ minutes: 1 }).d_ms); + await exchange.start(); + await exchange.pingUntilAvailable(); + // total time: 1 minute + + /** + * second deposit after 1 minute + */ + let d2Id: TransactionIdStr; + let d2Track: Promise<boolean>; + let d2Done: Promise<boolean>; + { + const { transactionId: depositTxId } = await walletClient.client.call( + WalletApiOperation.GenerateDepositGroupTxId, + {}, + ); + + d2Track = walletClient.waitForNotificationCond( + (n) => + n.type == NotificationType.TransactionStateTransition && + n.transactionId == depositTxId && + n.newTxState.major == TransactionMajorState.Finalizing && + n.newTxState.minor == TransactionMinorState.Track, + ); + + d2Done = walletClient.waitForNotificationCond( + (n) => + n.type == NotificationType.TransactionStateTransition && + n.transactionId == depositTxId && + n.newTxState.major == TransactionMajorState.Done, + ); + + const depositGroupResult = await walletClient.client.call( + WalletApiOperation.CreateDepositGroup, + { + amount: "TESTKUDOS:3" as AmountString, + depositPaytoUri, + transactionId: depositTxId, + }, + ); + + t.assertDeepEqual(depositGroupResult.transactionId, depositTxId); + d2Id = depositGroupResult.transactionId; + } + + await d2Track; + await exchange.stop(); + // @ts-ignore duration is not forever + exchange.setTimetravel(Duration.fromSpec({ minutes: 2 }).d_ms); + await exchange.start(); + await exchange.pingUntilAvailable(); + // total time: 2 minute + + /** + * third deposit after 2 minute + */ + let d3Id: TransactionIdStr; + let d3Track: Promise<boolean>; + let d3Done: Promise<boolean>; + { + const { transactionId: depositTxId } = await walletClient.client.call( + WalletApiOperation.GenerateDepositGroupTxId, + {}, + ); + + d3Track = walletClient.waitForNotificationCond( + (n) => + n.type == NotificationType.TransactionStateTransition && + n.transactionId == depositTxId && + n.newTxState.major == TransactionMajorState.Finalizing && + n.newTxState.minor == TransactionMinorState.Track, + ); + + d3Done = walletClient.waitForNotificationCond( + (n) => + n.type == NotificationType.TransactionStateTransition && + n.transactionId == depositTxId && + n.newTxState.major == TransactionMajorState.Done, + ); + + const depositGroupResult = await walletClient.client.call( + WalletApiOperation.CreateDepositGroup, + { + amount: "TESTKUDOS:3" as AmountString, + depositPaytoUri, + transactionId: depositTxId, + }, + ); + + t.assertDeepEqual(depositGroupResult.transactionId, depositTxId); + d3Id = depositGroupResult.transactionId; + } + + await d3Track; + await exchange.stop(); + // @ts-ignore duration is not forever + exchange.setTimetravel(Duration.fromSpec({ minutes: 3 }).d_ms); + await exchange.start(); + await exchange.pingUntilAvailable(); + // total time: 3 minute + + /** + * otherwise we get ECONNRESET in tx state because of the exchange restart + */ + await walletClient.call(WalletApiOperation.RetryTransaction, { + transactionId: d1Id, + }); + await walletClient.call(WalletApiOperation.RetryTransaction, { + transactionId: d2Id, + }); + await walletClient.call(WalletApiOperation.RetryTransaction, { + transactionId: d3Id, + }); + + /** + * check deposit tx after 3 minute, all pending + */ + { + const d1Details = await walletClient.call( + WalletApiOperation.GetTransactionById, + { transactionId: d1Id }, + ); + + const d2Details = await walletClient.call( + WalletApiOperation.GetTransactionById, + { transactionId: d2Id }, + ); + + const d3Details = await walletClient.call( + WalletApiOperation.GetTransactionById, + { transactionId: d3Id }, + ); + console.log(j2s({ d3Details, d2Details, d1Details })); + + t.assertTrue(d1Details.txState.major === TransactionMajorState.Finalizing); + t.assertTrue(d1Details.txState.minor === TransactionMinorState.Track); + t.assertTrue(d2Details.txState.major === TransactionMajorState.Finalizing); + t.assertTrue(d2Details.txState.minor === TransactionMinorState.Track); + t.assertTrue(d3Details.txState.major === TransactionMajorState.Finalizing); + t.assertTrue(d3Details.txState.minor === TransactionMinorState.Track); + } + + /////////////////////////////////////////// + + await exchange.stop(); + // @ts-ignore duration is not forever + exchange.setTimetravel(Duration.fromSpec({ minutes: 6 }).d_ms); + await exchange.start(); + await exchange.pingUntilAvailable(); + // total time: 6 minute + + await walletClient.call(WalletApiOperation.RetryTransaction, { + transactionId: d1Id, + }); + await walletClient.call(WalletApiOperation.RetryTransaction, { + transactionId: d2Id, + }); + await walletClient.call(WalletApiOperation.RetryTransaction, { + transactionId: d3Id, + }); + + await d1Done; + /** + * check deposit tx after 6 minute, first one should already be wired since default + * wire deadline is 5 minutes + * + * other deposit should already be completed since it should use the same wire transfer + * + */ + { + const d1Details = await walletClient.call( + WalletApiOperation.GetTransactionById, + { transactionId: d1Id }, + ); + const d2Details = await walletClient.call( + WalletApiOperation.GetTransactionById, + { transactionId: d2Id }, + ); + const d3Details = await walletClient.call( + WalletApiOperation.GetTransactionById, + { transactionId: d3Id }, + ); + console.log(j2s({ d3Details, d2Details, d1Details })); + t.assertTrue(d1Details.txState.major === TransactionMajorState.Done); + t.assertTrue(d2Details.txState.major === TransactionMajorState.Done); + t.assertTrue(d3Details.txState.major === TransactionMajorState.Done); + } +} + +runDepositMergeTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -42,6 +42,7 @@ import { runDenomLostTest } from "./test-denom-lost.js"; import { runDenomUnofferedTest } from "./test-denom-unoffered.js"; import { runDepositFaultTest } from "./test-deposit-fault.js"; import { runDepositTest } from "./test-deposit.js"; +import { runDepositMergeTest } from "./test-deposit-merge.js"; import { runExchangeDepositTest } from "./test-exchange-deposit.js"; import { runExchangeManagementFaultTest } from "./test-exchange-management-fault.js"; import { runExchangeManagementTest } from "./test-exchange-management.js"; @@ -183,6 +184,7 @@ const allTests: TestMainFunction[] = [ runClauseSchnorrTest, runDenomUnofferedTest, runDepositTest, + runDepositMergeTest, runSimplePaymentTest, runExchangeManagementFaultTest, runExchangeTimetravelTest,