diff options
Diffstat (limited to 'packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts')
-rw-r--r-- | packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts b/packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts new file mode 100644 index 000000000..21e0d384a --- /dev/null +++ b/packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts @@ -0,0 +1,264 @@ +/* + 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 { + AbsoluteTime, + AmountString, + Duration, + NotificationType, + TransactionMajorState, + TransactionMinorState, + TransactionType, + WalletNotification, + j2s, +} 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"; + +/** + * Run a test for basic peer-push payments. + */ +export async function runPeerToPeerPushTest(t: GlobalTestState) { + const { bank, exchange } = await createSimpleTestkudosEnvironmentV2(t); + + let allW1Notifications: WalletNotification[] = []; + let allW2Notifications: WalletNotification[] = []; + + const w1 = await createWalletDaemonWithClient(t, { + name: "w1", + handleNotification(wn) { + allW1Notifications.push(wn); + }, + }); + const w2 = await createWalletDaemonWithClient(t, { + name: "w2", + handleNotification(wn) { + allW2Notifications.push(wn); + }, + }); + + // Withdraw digital cash into the wallet. + + const withdrawRes = await withdrawViaBankV2(t, { + walletClient: w1.walletClient, + bank, + exchange, + amount: "TESTKUDOS:20", + }); + + await withdrawRes.withdrawalFinishedCond; + + const purse_expiration = AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + Duration.fromSpec({ days: 2 }), + ), + ); + + const checkResp0 = await w1.walletClient.call( + WalletApiOperation.CheckPeerPushDebit, + { + amount: "TESTKUDOS:5" as AmountString, + }, + ); + + t.assertAmountEquals(checkResp0.amountEffective, "TESTKUDOS:5.49"); + + { + const resp = await w1.walletClient.call( + WalletApiOperation.InitiatePeerPushDebit, + { + partialContractTerms: { + summary: "Hello World 😁😇", + amount: "TESTKUDOS:5" as AmountString, + purse_expiration, + }, + }, + ); + + console.log(resp); + } + + { + const bal = await w1.walletClient.call(WalletApiOperation.GetBalances, {}); + t.assertAmountEquals(bal.balances[0].pendingOutgoing, "TESTKUDOS:5.49"); + } + + await w1.walletClient.call(WalletApiOperation.TestingWaitRefreshesFinal, {}); + + const resp = await w1.walletClient.call( + WalletApiOperation.InitiatePeerPushDebit, + { + partialContractTerms: { + summary: "Hello World 🥺", + amount: "TESTKUDOS:5" as AmountString, + purse_expiration, + }, + }, + ); + + console.log(resp); + + const peerPushReadyCond = w1.walletClient.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.newTxState.major === TransactionMajorState.Pending && + x.newTxState.minor === TransactionMinorState.Ready && + x.transactionId === resp.transactionId, + ); + + await peerPushReadyCond; + + const txDetails = await w1.walletClient.call( + WalletApiOperation.GetTransactionById, + { + transactionId: resp.transactionId, + }, + ); + t.assertDeepEqual(txDetails.type, TransactionType.PeerPushDebit); + t.assertTrue(!!txDetails.talerUri); + + const checkResp = await w2.walletClient.call( + WalletApiOperation.PreparePeerPushCredit, + { + talerUri: txDetails.talerUri, + }, + ); + + console.log(checkResp); + + const acceptResp = await w2.walletClient.call( + WalletApiOperation.ConfirmPeerPushCredit, + { + transactionId: checkResp.transactionId, + }, + ); + + console.log(acceptResp); + + const txn1 = await w1.walletClient.call( + WalletApiOperation.GetTransactions, + {}, + ); + const txn2 = await w2.walletClient.call( + WalletApiOperation.GetTransactions, + {}, + ); + + console.log(`txn1: ${j2s(txn1)}`); + console.log(`txn2: ${j2s(txn2)}`); + + // We expect insufficient balance here! + const ex1 = await t.assertThrowsTalerErrorAsync(async () => { + await w1.walletClient.call(WalletApiOperation.InitiatePeerPushDebit, { + partialContractTerms: { + summary: "(this will fail)", + amount: "TESTKUDOS:15" as AmountString, + purse_expiration, + }, + }); + }); + + console.log("got expected exception detail", j2s(ex1.errorDetail)); + + const initiateResp2 = await w1.walletClient.call( + WalletApiOperation.InitiatePeerPushDebit, + { + partialContractTerms: { + summary: "second tx, will expire", + amount: "TESTKUDOS:5" as AmountString, + purse_expiration, + }, + }, + ); + + const peerPushReadyCond2 = w1.walletClient.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.newTxState.major === TransactionMajorState.Pending && + x.newTxState.minor === TransactionMinorState.Ready && + x.transactionId === initiateResp2.transactionId, + ); + + await peerPushReadyCond2; + + const txDetails3 = await w1.walletClient.call( + WalletApiOperation.GetTransactionById, + { + transactionId: initiateResp2.transactionId, + }, + ); + t.assertDeepEqual(txDetails3.type, TransactionType.PeerPushDebit); + t.assertTrue(!!txDetails3.talerUri); + + await w2.walletClient.call(WalletApiOperation.PreparePeerPushCredit, { + talerUri: txDetails3.talerUri, + }); + + const timetravelOffsetMs = Duration.toMilliseconds( + Duration.fromSpec({ days: 5 }), + ); + + console.log("stopping exchange to apply time-travel"); + + await exchange.stop(); + exchange.setTimetravel(timetravelOffsetMs); + await exchange.start(); + await exchange.pingUntilAvailable(); + + console.log("running expire"); + await exchange.runExpireOnce(); + console.log("done running expire"); + + console.log("purse should now be expired"); + + await w1.walletClient.call(WalletApiOperation.TestingSetTimetravel, { + offsetMs: timetravelOffsetMs, + }); + + await w2.walletClient.call(WalletApiOperation.TestingSetTimetravel, { + offsetMs: timetravelOffsetMs, + }); + + await w1.walletClient.call( + WalletApiOperation.TestingWaitTransactionsFinal, + {}, + ); + + await w2.walletClient.call( + WalletApiOperation.TestingWaitTransactionsFinal, + {}, + ); + + const txDetails2 = await w1.walletClient.call( + WalletApiOperation.GetTransactionById, + { + transactionId: initiateResp2.transactionId, + }, + ); + + console.log(`tx details 2: ${j2s(txDetails2)}`); +} + +runPeerToPeerPushTest.suites = ["wallet"]; |