diff --git a/packages/taler-wallet-cli/src/env1.ts b/packages/taler-wallet-cli/src/env1.ts index eb7da352c..aec0b7b8f 100644 --- a/packages/taler-wallet-cli/src/env1.ts +++ b/packages/taler-wallet-cli/src/env1.ts @@ -22,8 +22,8 @@ import { CoinConfig, defaultCoinConfig } from "./harness/denomStructures.js"; import { GlobalTestState, setupDb, - FakeBankService, ExchangeService, + FakebankService, } from "./harness/harness.js"; /** @@ -35,9 +35,11 @@ import { export async function runEnv1(t: GlobalTestState): Promise { const db = await setupDb(t); - const bank = await FakeBankService.create(t, { + const bank = await FakebankService.create(t, { currency: "TESTKUDOS", httpPort: 8082, + allowRegistrations: true, + database: db.connStr, }); const exchange = ExchangeService.create(t, { diff --git a/packages/taler-wallet-cli/src/harness/harness.ts b/packages/taler-wallet-cli/src/harness/harness.ts index 0e7238b9a..ca0ea1f2f 100644 --- a/packages/taler-wallet-cli/src/harness/harness.ts +++ b/packages/taler-wallet-cli/src/harness/harness.ts @@ -775,11 +775,21 @@ class LibEuFinBankService extends BankServiceBase implements BankServiceHandle { /** * Implementation of the bank service using the "taler-fakebank-run" tool. */ -class FakebankService extends BankServiceBase implements BankServiceHandle { +export class FakebankService + extends BankServiceBase + implements BankServiceHandle +{ proc: ProcessWrapper | undefined; http = new NodeHttpLib(); + // We store "created" accounts during setup and + // register them after startup. + private accounts: { + accountName: string; + accountPassword: string; + }[] = []; + static async create( gc: GlobalTestState, bc: BankConfig, @@ -791,6 +801,7 @@ class FakebankService extends BankServiceBase implements BankServiceHandle { config.setString("bank", "serve", "http"); config.setString("bank", "max_debt_bank", `${bc.currency}:999999`); config.setString("bank", "max_debt", bc.maxDebt ?? `${bc.currency}:100`); + config.setString("bank", "ram_limit", `${1024}`); const cfgFilename = gc.testDir + "/bank.conf"; config.write(cfgFilename); @@ -798,6 +809,9 @@ class FakebankService extends BankServiceBase implements BankServiceHandle { } setSuggestedExchange(e: ExchangeServiceInterface, exchangePayto: string) { + if (!!this.proc) { + throw Error("Can't set suggested exchange while bank is running."); + } const config = Configuration.load(this.configFile); config.setString("bank", "suggested_exchange", e.baseUrl); config.write(this.configFile); @@ -816,10 +830,10 @@ class FakebankService extends BankServiceBase implements BankServiceHandle { accountName: string, password: string, ): Promise { - // FIXME: Is there a better place to do this initialization? - await this.start(); - await this.pingUntilAvailable(); - await BankApi.registerAccount(this, accountName, password); + this.accounts.push({ + accountName, + accountPassword: password, + }); return { accountName: accountName, accountPassword: password, @@ -833,15 +847,25 @@ class FakebankService extends BankServiceBase implements BankServiceHandle { } async start(): Promise { + logger.info("starting fakebank"); if (this.proc) { logger.info("fakebank already running, not starting again"); return; } this.proc = this.globalTestState.spawnService( "taler-fakebank-run", - ["-c", this.configFile], + [ + "-c", + this.configFile, + "--signup-bonus", + `${this.bankConfig.currency}:100`, + ], "bank", ); + await this.pingUntilAvailable(); + for (const acc of this.accounts) { + await BankApi.registerAccount(this, acc.accountName, acc.accountPassword); + } } async pingUntilAvailable(): Promise { @@ -853,86 +877,8 @@ class FakebankService extends BankServiceBase implements BankServiceHandle { // Use libeufin bank instead of pybank. const useLibeufinBank = false; -/** - * Return a euFin or a pyBank implementation of - * the exported BankService class. This allows - * to "dynamically export" such class depending - * on a particular env variable. - */ -function getBankServiceImpl(): { - prototype: typeof FakebankService.prototype; - create: typeof FakebankService.create; -} { - if (useLibeufinBank) - return { - prototype: LibEuFinBankService.prototype, - create: LibEuFinBankService.create, - }; - return { - prototype: FakebankService.prototype, - create: FakebankService.create, - }; -} - -export type BankService = FakebankService; -export const BankService = getBankServiceImpl(); - -export class FakeBankService { - proc: ProcessWrapper | undefined; - - static fromExistingConfig(gc: GlobalTestState): FakeBankService { - const cfgFilename = gc.testDir + "/bank.conf"; - logger.info("reading fakebank config from", cfgFilename); - const config = Configuration.load(cfgFilename); - const bc: FakeBankConfig = { - currency: config.getString("taler", "currency").required(), - httpPort: config.getNumber("bank", "http_port").required(), - }; - return new FakeBankService(gc, bc, cfgFilename); - } - - static async create( - gc: GlobalTestState, - bc: FakeBankConfig, - ): Promise { - const config = new Configuration(); - setTalerPaths(config, gc.testDir + "/talerhome"); - config.setString("taler", "currency", bc.currency); - config.setString("bank", "http_port", `${bc.httpPort}`); - config.setString("bank", "ram_limit", `${1024}`); - const cfgFilename = gc.testDir + "/bank.conf"; - config.write(cfgFilename); - return new FakeBankService(gc, bc, cfgFilename); - } - - get baseUrl(): string { - return `http://localhost:${this.bankConfig.httpPort}/`; - } - - get port() { - return this.bankConfig.httpPort; - } - - private constructor( - private globalTestState: GlobalTestState, - private bankConfig: FakeBankConfig, - private configFile: string, - ) {} - - async start(): Promise { - this.proc = this.globalTestState.spawnService( - "taler-fakebank-run", - ["-c", this.configFile], - "fakebank", - ); - } - - async pingUntilAvailable(): Promise { - // Fakebank doesn't have "/config", so we ping just "/". - const url = `http://localhost:${this.bankConfig.httpPort}/`; - await pingProc(this.proc, url, "bank"); - } -} +export type BankService = BankServiceHandle; +export const BankService = FakebankService; export interface ExchangeConfig { name: string; diff --git a/packages/taler-wallet-cli/src/harness/libeufin.ts b/packages/taler-wallet-cli/src/harness/libeufin.ts index 7356a6273..bc210d132 100644 --- a/packages/taler-wallet-cli/src/harness/libeufin.ts +++ b/packages/taler-wallet-cli/src/harness/libeufin.ts @@ -691,8 +691,8 @@ export class LibeufinCli { ): Promise { const stdout = await sh( this.globalTestState, - "libeufin-cli-submitpayment", - `libeufin-cli accounts submit-payment` + + "libeufin-cli-submitpayments", + `libeufin-cli accounts submit-payments` + ` --payment-uuid=${paymentUuid}` + ` ${details.nexusBankAccountName}`, { diff --git a/packages/taler-wallet-cli/src/integrationtests/test-bank-api.ts b/packages/taler-wallet-cli/src/integrationtests/test-bank-api.ts index 31113aa1f..ab7ea1132 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-bank-api.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-bank-api.ts @@ -43,10 +43,10 @@ export async function runBankApiTest(t: GlobalTestState) { const db = await setupDb(t); const bank = await BankService.create(t, { - allowRegistrations: true, currency: "TESTKUDOS", - database: db.connStr, httpPort: 8082, + database: db.connStr, + allowRegistrations: true, }); const exchange = ExchangeService.create(t, { diff --git a/packages/taler-wallet-cli/src/integrationtests/test-forced-selection.ts b/packages/taler-wallet-cli/src/integrationtests/test-forced-selection.ts index 302e3364a..91be11a82 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-forced-selection.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-forced-selection.ts @@ -17,17 +17,9 @@ /** * Imports. */ -import { - ConfirmPayResultType, - j2s, - PreparePayResultType, -} from "@gnu-taler/taler-util"; -import { Wallet, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { - GlobalTestState, - MerchantPrivateApi, - WithAuthorization, -} from "../harness/harness.js"; +import { j2s } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironment } from "../harness/helpers.js"; /** diff --git a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-abort-bank.ts b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-abort-bank.ts index 0125b3b41..bf2dc0133 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-abort-bank.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-abort-bank.ts @@ -54,6 +54,7 @@ export async function runWithdrawalAbortBankTest(t: GlobalTestState) { // Abort it await BankApi.abortWithdrawalOperation(bank, user, wop); + //await BankApi.confirmWithdrawalOperation(bank, user, wop); // Withdraw diff --git a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts index 5860aaf88..ec6e54e6c 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts @@ -22,7 +22,7 @@ import { WalletCli, setupDb, ExchangeService, - FakeBankService, + FakebankService, } from "../harness/harness.js"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js"; @@ -36,9 +36,12 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) { const db = await setupDb(t); - const bank = await FakeBankService.create(t, { + const bank = await FakebankService.create(t, { currency: "TESTKUDOS", httpPort: 8082, + allowRegistrations: true, + // Not used by fakebank + database: db.connStr, }); const exchange = ExchangeService.create(t, { diff --git a/packages/taler-wallet-core/src/bank-api-client.ts b/packages/taler-wallet-core/src/bank-api-client.ts index c2de65982..8f82d7e7f 100644 --- a/packages/taler-wallet-core/src/bank-api-client.ts +++ b/packages/taler-wallet-core/src/bank-api-client.ts @@ -106,7 +106,7 @@ export namespace BankApi { const url = new URL("testing/register", bank.bankAccessApiBaseUrl); const resp = await bank.http.postJson(url.href, { username, password }); let paytoUri = `payto://x-taler-bank/localhost/${username}`; - if (resp.status !== 200 && resp.status !== 202) { + if (resp.status !== 200 && resp.status !== 202 && resp.status !== 204) { logger.error(`${j2s(await resp.json())}`); throw TalerError.fromDetail( TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, @@ -209,7 +209,7 @@ export namespace BankApi { ): Promise { const url = new URL( `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/abort`, - bank.baseUrl, + bank.bankAccessApiBaseUrl, ); const resp = await bank.http.postJson( url.href, diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index 8d28c62f7..a5aa1106f 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -90,16 +90,21 @@ export async function withdrawTestBalance( ws: InternalWalletState, req: WithdrawTestBalanceRequest, ): Promise { - const bankBaseUrl = req.bankBaseUrl; const amount = req.amount; const exchangeBaseUrl = req.exchangeBaseUrl; - const bankUser = await registerRandomBankUser(ws.http, bankBaseUrl); + logger.trace( + `Registered bank user, bank access base url ${req.bankAccessApiBaseUrl}`, + ); + const bankUser = await registerRandomBankUser( + ws.http, + req.bankAccessApiBaseUrl, + ); logger.trace(`Registered bank user ${JSON.stringify(bankUser)}`); const wresp = await createDemoBankWithdrawalUri( ws.http, - bankBaseUrl, + req.bankAccessApiBaseUrl, bankUser, amount, ); @@ -112,7 +117,7 @@ export async function withdrawTestBalance( await confirmBankWithdrawalUri( ws.http, - bankBaseUrl, + req.bankAccessApiBaseUrl, bankUser, wresp.withdrawal_id, ); @@ -133,13 +138,13 @@ function getMerchantAuthHeader(m: MerchantBackendInfo): Record { */ export async function createDemoBankWithdrawalUri( http: HttpRequestLibrary, - bankBaseUrl: string, + bankAccessApiBaseUrl: string, bankUser: BankUser, amount: AmountString, ): Promise { const reqUrl = new URL( `accounts/${bankUser.username}/withdrawals`, - bankBaseUrl, + bankAccessApiBaseUrl, ).href; const resp = await http.postJson( reqUrl, @@ -161,13 +166,13 @@ export async function createDemoBankWithdrawalUri( async function confirmBankWithdrawalUri( http: HttpRequestLibrary, - bankBaseUrl: string, + bankAccessApiBaseUrl: string, bankUser: BankUser, withdrawalId: string, ): Promise { const reqUrl = new URL( `accounts/${bankUser.username}/withdrawals/${withdrawalId}/confirm`, - bankBaseUrl, + bankAccessApiBaseUrl, ).href; const resp = await http.postJson( reqUrl, @@ -187,9 +192,9 @@ async function confirmBankWithdrawalUri( async function registerRandomBankUser( http: HttpRequestLibrary, - bankBaseUrl: string, + bankAccessApiBaseUrl: string, ): Promise { - const reqUrl = new URL("testing/register", bankBaseUrl).href; + const reqUrl = new URL("testing/register", bankAccessApiBaseUrl).href; const randId = makeId(8); const bankUser: BankUser = { // euFin doesn't allow resource names to have upper case letters. @@ -377,7 +382,7 @@ export async function runIntegrationTest( await withdrawTestBalance(ws, { amount: Amounts.stringify(withdrawAmountTwo), bankBaseUrl: args.bankBaseUrl, - bankAccessApiBaseUrl: args.bankBaseUrl, + bankAccessApiBaseUrl: args.bankAccessApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 03ec9b61b..a33f59162 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -376,6 +376,9 @@ export async function getBankWithdrawalInfo( `withdrawal-operation/${uriResult.withdrawalOperationId}`, uriResult.bankIntegrationApiBaseUrl, ); + + logger.info(`bank withdrawal status URL: ${reqUrl.href}}`); + const resp = await http.get(reqUrl.href); const status = await readSuccessResponseJsonOrThrow( resp,