From 22cb8adaa6d9584ad7638b9019b6d0c3eb7158bf Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 13 Feb 2023 13:15:47 +0100 Subject: wallet-core,harness: introduce reserveIsReady flag, test tx lifeycle --- packages/taler-harness/src/harness/harness.ts | 47 ++++++++--- packages/taler-harness/src/harness/helpers.ts | 25 +++++- .../taler-harness/src/integrationtests/test-kyc.ts | 2 +- .../test-withdrawal-bank-integrated.ts | 96 +++++++++++++++++++--- 4 files changed, 143 insertions(+), 27 deletions(-) (limited to 'packages/taler-harness') diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index 275592091..0b7ba14cf 100644 --- a/packages/taler-harness/src/harness/harness.ts +++ b/packages/taler-harness/src/harness/harness.ts @@ -1169,6 +1169,29 @@ export class ExchangeService implements ExchangeServiceInterface { return !!this.exchangeWirewatchProc || !!this.exchangeHttpProc; } + /** + * Stop the wirewatch service (which runs by default). + * + * Useful for some tests. + */ + async stopWirewatch(): Promise { + const wirewatch = this.exchangeWirewatchProc; + if (wirewatch) { + wirewatch.proc.kill("SIGTERM"); + await wirewatch.wait(); + this.exchangeWirewatchProc = undefined; + } + } + + async startWirewatch(): Promise { + const wirewatch = this.exchangeWirewatchProc; + if (wirewatch) { + logger.warn("wirewatch already running"); + } else { + this.internalCreateWirewatchProc(); + } + } + async stop(): Promise { const wirewatch = this.exchangeWirewatchProc; if (wirewatch) { @@ -1332,6 +1355,19 @@ export class ExchangeService implements ExchangeServiceInterface { ); } + private internalCreateWirewatchProc() { + this.exchangeWirewatchProc = this.globalState.spawnService( + "taler-exchange-wirewatch", + [ + "-c", + this.configFilename, + "--longpoll-timeout=5s", + ...this.timetravelArgArr, + ], + `exchange-wirewatch-${this.name}`, + ); + } + async start(): Promise { if (this.isRunning()) { throw Error("exchange is already running"); @@ -1360,16 +1396,7 @@ export class ExchangeService implements ExchangeServiceInterface { `exchange-crypto-rsa-${this.name}`, ); - this.exchangeWirewatchProc = this.globalState.spawnService( - "taler-exchange-wirewatch", - [ - "-c", - this.configFilename, - "--longpoll-timeout=5s", - ...this.timetravelArgArr, - ], - `exchange-wirewatch-${this.name}`, - ); + this.internalCreateWirewatchProc(); this.exchangeHttpProc = this.globalState.spawnService( "taler-exchange-httpd", diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts index 4c2ca80a7..ad77ce6ca 100644 --- a/packages/taler-harness/src/harness/helpers.ts +++ b/packages/taler-harness/src/harness/helpers.ts @@ -209,7 +209,7 @@ export async function createSimpleTestkudosEnvironmentV2( t: GlobalTestState, coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("TESTKUDOS")), opts: EnvOptions = {}, -): Promise { +): Promise { const db = await setupDb(t); const bank = await BankService.create(t, { @@ -293,15 +293,32 @@ export async function createSimpleTestkudosEnvironmentV2( ), }); - console.log("setup done!"); + const walletService = new WalletService(t, { + name: "wallet", + useInMemoryDb: true, + }); + await walletService.start(); + await walletService.pingUntilAvailable(); - const wallet = new WalletCli(t); + const walletClient = new WalletClient({ + unixPath: walletService.socketPath, + onNotification(n) { + console.log("got notification", n); + }, + }); + await walletClient.connect(); + await walletClient.client.call(WalletApiOperation.InitWallet, { + skipDefaults: true, + }); + + console.log("setup done!"); return { commonDb: db, exchange, merchant, - wallet, + walletClient, + walletService, bank, exchangeBankAccount, }; diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index b08db66f7..490673cee 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -307,7 +307,7 @@ export async function runKycTest(t: GlobalTestState) { // Withdraw const kycNotificationCond = walletClient.waitForNotificationCond((x) => { - if (x.type === NotificationType.WithdrawalKycRequested) { + if (x.type === NotificationType.WithdrawalGroupKycRequested) { return x; } return false; diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts index dc7298e5d..c98c18db5 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts @@ -18,13 +18,13 @@ * Imports. */ import { GlobalTestState } from "../harness/harness.js"; -import { createSimpleTestkudosEnvironment } from "../harness/helpers.js"; +import { createSimpleTestkudosEnvironmentV2 } from "../harness/helpers.js"; import { WalletApiOperation, BankApi, BankAccessApi, } from "@gnu-taler/taler-wallet-core"; -import { j2s } from "@gnu-taler/taler-util"; +import { j2s, NotificationType, TransactionType, WithdrawalType } from "@gnu-taler/taler-util"; /** * Run test for basic, bank-integrated withdrawal. @@ -32,7 +32,8 @@ import { j2s } from "@gnu-taler/taler-util"; export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Set up test environment - const { wallet, bank, exchange } = await createSimpleTestkudosEnvironment(t); + const { walletClient, bank, exchange } = + await createSimpleTestkudosEnvironmentV2(t); // Create a withdrawal operation @@ -45,46 +46,117 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Hand it to the wallet - const r1 = await wallet.client.call( + const r1 = await walletClient.client.call( WalletApiOperation.GetWithdrawalDetailsForUri, { talerWithdrawUri: wop.taler_withdraw_uri, }, ); - await wallet.runPending(); - // Withdraw - const r2 = await wallet.client.call( + const withdrawalBankConfirmedCond = walletClient.waitForNotificationCond( + (x) => { + return x.type === NotificationType.WithdrawalGroupBankConfirmed; + }, + ); + + const withdrawalFinishedCond = walletClient.waitForNotificationCond((x) => { + return x.type === NotificationType.WithdrawGroupFinished; + }); + + const withdrawalReserveReadyCond = walletClient.waitForNotificationCond( + (x) => { + return x.type === NotificationType.WithdrawalGroupReserveReady; + }, + ); + + const r2 = await walletClient.client.call( WalletApiOperation.AcceptBankIntegratedWithdrawal, { exchangeBaseUrl: exchange.baseUrl, talerWithdrawUri: wop.taler_withdraw_uri, }, ); + // Do it twice to check idempotency - const r3 = await wallet.client.call( + const r3 = await walletClient.client.call( WalletApiOperation.AcceptBankIntegratedWithdrawal, { exchangeBaseUrl: exchange.baseUrl, talerWithdrawUri: wop.taler_withdraw_uri, }, ); - await wallet.runPending(); + + await exchange.stopWirewatch(); + + // Check status before withdrawal is confirmed by bank. + { + const txn = await walletClient.client.call( + WalletApiOperation.GetTransactions, + {}, + ); + console.log("transactions before confirmation:", j2s(txn)); + const tx0 = txn.transactions[0]; + t.assertTrue(tx0.type === TransactionType.Withdrawal); + t.assertTrue(tx0.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi); + t.assertTrue(tx0.withdrawalDetails.confirmed === false); + t.assertTrue(tx0.withdrawalDetails.reserveIsReady === false); + } // Confirm it await BankApi.confirmWithdrawalOperation(bank, user, wop); - await wallet.runUntilDone(); + await withdrawalBankConfirmedCond; + + // Check status after withdrawal is confirmed by bank, + // but before funds are wired to the exchange. + { + const txn = await walletClient.client.call( + WalletApiOperation.GetTransactions, + {}, + ); + console.log("transactions after confirmation:", j2s(txn)); + const tx0 = txn.transactions[0]; + t.assertTrue(tx0.type === TransactionType.Withdrawal); + t.assertTrue(tx0.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi); + t.assertTrue(tx0.withdrawalDetails.confirmed === true); + t.assertTrue(tx0.withdrawalDetails.reserveIsReady === false); + } + + await exchange.startWirewatch(); + + await withdrawalReserveReadyCond; + + // Check status after funds were wired. + { + const txn = await walletClient.client.call( + WalletApiOperation.GetTransactions, + {}, + ); + console.log("transactions after reserve ready:", j2s(txn)); + const tx0 = txn.transactions[0]; + t.assertTrue(tx0.type === TransactionType.Withdrawal); + t.assertTrue(tx0.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi); + t.assertTrue(tx0.withdrawalDetails.confirmed === true); + t.assertTrue(tx0.withdrawalDetails.reserveIsReady === true); + } + + await withdrawalFinishedCond; // Check balance - const balResp = await wallet.client.call(WalletApiOperation.GetBalances, {}); + const balResp = await walletClient.client.call( + WalletApiOperation.GetBalances, + {}, + ); t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available); - const txn = await wallet.client.call(WalletApiOperation.GetTransactions, {}); + const txn = await walletClient.client.call( + WalletApiOperation.GetTransactions, + {}, + ); console.log(`transactions: ${j2s(txn)}`); } -- cgit v1.2.3