diff options
3 files changed, 192 insertions, 4 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-peer-repair.ts b/packages/taler-harness/src/integrationtests/test-peer-repair.ts new file mode 100644 index 000000000..77e47b01e --- /dev/null +++ b/packages/taler-harness/src/integrationtests/test-peer-repair.ts @@ -0,0 +1,178 @@ +/* + This file is part of GNU Taler + (C) 2023 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 { + AbsoluteTime, + Duration, + NotificationType, + TransactionMajorState, + TransactionMinorState, + WalletNotification, +} from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { GlobalTestState } from "../harness/harness.js"; +import { + createSimpleTestkudosEnvironmentV2, + createWalletDaemonWithClient, + withdrawViaBankV2, +} from "../harness/helpers.js"; +import * as fs from "node:fs"; + +export async function runPeerRepairTest(t: GlobalTestState) { + // Set up test environment + + const { bank, exchange } = await createSimpleTestkudosEnvironmentV2(t); + + let allW1Notifications: WalletNotification[] = []; + let allW2Notifications: WalletNotification[] = []; + + let w1 = await createWalletDaemonWithClient(t, { + name: "w1", + persistent: true, + handleNotification(wn) { + allW1Notifications.push(wn); + }, + }); + const w2 = await createWalletDaemonWithClient(t, { + name: "w2", + handleNotification(wn) { + allW2Notifications.push(wn); + }, + }); + + // Withdraw digital cash into the wallet. + let wallet1 = w1.walletClient; + const wallet2 = w2.walletClient; + + const withdrawalDoneCond = wallet1.waitForNotificationCond( + (x) => x.type === NotificationType.WithdrawGroupFinished, + ); + + await withdrawViaBankV2(t, { + walletClient: wallet1, + bank, + exchange, + amount: "TESTKUDOS:5", + }); + + await withdrawalDoneCond; + const w1DbPath = w1.walletService.dbPath; + const w1DbCopyPath = w1.walletService.dbPath + ".copy"; + fs.copyFileSync(w1DbPath, w1DbCopyPath); + + const purse_expiration = AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + Duration.fromSpec({ days: 2 }), + ), + ); + + const resp1 = await wallet1.client.call( + WalletApiOperation.InitiatePeerPushDebit, + { + exchangeBaseUrl: exchange.baseUrl, + partialContractTerms: { + summary: "Hello World", + amount: "TESTKUDOS:3", + purse_expiration, + }, + }, + ); + + const peerPushDebitReady1Cond = wallet1.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.transactionId === resp1.transactionId && + x.newTxState.major === TransactionMajorState.Pending && + x.newTxState.minor === TransactionMinorState.Ready + ); + + await peerPushDebitReady1Cond; + + const resp2 = await wallet2.client.call( + WalletApiOperation.PreparePeerPushCredit, + { + talerUri: resp1.talerUri, + }, + ); + + const peerPushCreditDone1Cond = wallet2.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.transactionId === resp2.transactionId && + x.newTxState.major === TransactionMajorState.Done, + ); + + const peerPushDebitDone1Cond = wallet1.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.transactionId === resp1.transactionId && + x.newTxState.major === TransactionMajorState.Done, + ); + + await wallet2.client.call( + WalletApiOperation.ConfirmPeerPushCredit, + { + peerPushPaymentIncomingId: resp2.peerPushPaymentIncomingId, + }, + ); + + await peerPushCreditDone1Cond; + await peerPushDebitDone1Cond; + + w1.walletClient.remoteWallet?.close(); + await w1.walletService.stop(); + + fs.copyFileSync(w1DbCopyPath, w1DbPath); + + console.log(`copied back to ${w1DbPath}`); + + w1 = await createWalletDaemonWithClient(t, { + name: "w1", + persistent: true, + handleNotification(wn) { + allW1Notifications.push(wn); + }, + }); + wallet1 = w1.walletClient; + + const initResp2 = await wallet1.client.call( + WalletApiOperation.InitiatePeerPushDebit, + { + exchangeBaseUrl: exchange.baseUrl, + partialContractTerms: { + summary: "Hello World", + amount: "TESTKUDOS:3", + purse_expiration, + }, + }, + ); + + const peerPushDebitReady2Cond = wallet1.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.transactionId === resp1.transactionId && + x.newTxState.major === TransactionMajorState.Pending && + x.newTxState.minor === TransactionMinorState.Ready + ); + + await peerPushDebitReady2Cond; +} + +runPeerRepairTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts b/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts index 1e33afa34..aed3fe8db 100644 --- a/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts +++ b/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts @@ -22,15 +22,14 @@ import { Duration, j2s, NotificationType, + TransactionMajorState, WalletNotification, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState, WalletCli } from "../harness/harness.js"; +import { GlobalTestState } from "../harness/harness.js"; import { - createSimpleTestkudosEnvironment, createSimpleTestkudosEnvironmentV2, createWalletDaemonWithClient, - withdrawViaBank, withdrawViaBankV2, } from "../harness/helpers.js"; @@ -106,7 +105,15 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) { // FIXME: The wallet should emit a more appropriate notification here. // Yes, it's technically a withdrawal. const peerPullCreditDoneCond = wallet1.waitForNotificationCond( - (x) => x.type === NotificationType.WithdrawGroupFinished, + (x) => x.type === NotificationType.TransactionStateTransition && + x.transactionId === resp.transactionId && + x.newTxState.major === TransactionMajorState.Done, + ); + + const peerPullDebitDoneCond = wallet2.waitForNotificationCond( + (x) => x.type === NotificationType.TransactionStateTransition && + x.transactionId === checkResp.transactionId && + x.newTxState.major === TransactionMajorState.Done, ); await wallet2.client.call(WalletApiOperation.ConfirmPeerPullDebit, { @@ -114,6 +121,7 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) { }); await peerPullCreditDoneCond; + await peerPullDebitDoneCond; const txn1 = await wallet1.client.call( WalletApiOperation.GetTransactions, diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts index c76ce1b18..0f64ae94f 100644 --- a/packages/taler-harness/src/integrationtests/testrunner.ts +++ b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -101,6 +101,7 @@ import { runWithdrawalFeesTest } from "./test-withdrawal-fees.js"; import { runWalletBalanceTest } from "./test-wallet-balance.js"; import { runPaymentTemplateTest } from "./test-payment-template.js"; import { runExchangeDepositTest } from "./test-exchange-deposit.js"; +import { runPeerRepairTest } from "./test-peer-repair.js"; /** * Test runner. @@ -170,6 +171,7 @@ const allTests: TestMainFunction[] = [ runPaymentTransientTest, runPaymentZeroTest, runPayPaidTest, + runPeerRepairTest, runWalletBalanceTest, runPaywallFlowTest, runPeerToPeerPullTest, |