harness: add libeufin-bank integration test

This commit is contained in:
Florian Dold 2023-09-24 21:03:22 +02:00
parent bdd906c887
commit 7b93938e71
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
28 changed files with 552 additions and 80 deletions

View File

@ -25,7 +25,7 @@ import {
ExchangeService, ExchangeService,
FakebankService, FakebankService,
MerchantService, MerchantService,
getPayto, generateRandomPayto,
} from "./harness/harness.js"; } from "./harness/harness.js";
/** /**
@ -82,7 +82,7 @@ export async function runEnvFull(t: GlobalTestState): Promise<void> {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),
@ -91,7 +91,7 @@ export async function runEnvFull(t: GlobalTestState): Promise<void> {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),

View File

@ -565,7 +565,7 @@ class BankServiceBase {
protected globalTestState: GlobalTestState, protected globalTestState: GlobalTestState,
protected bankConfig: BankConfig, protected bankConfig: BankConfig,
protected configFile: string, protected configFile: string,
) { } ) {}
} }
export interface HarnessExchangeBankAccount { export interface HarnessExchangeBankAccount {
@ -580,7 +580,8 @@ export interface HarnessExchangeBankAccount {
*/ */
export class FakebankService export class FakebankService
extends BankServiceBase extends BankServiceBase
implements BankServiceHandle { implements BankServiceHandle
{
proc: ProcessWrapper | undefined; proc: ProcessWrapper | undefined;
http = createPlatformHttpLib({ enableThrottling: false }); http = createPlatformHttpLib({ enableThrottling: false });
@ -664,7 +665,7 @@ export class FakebankService
return { return {
accountName: accountName, accountName: accountName,
accountPassword: password, accountPassword: password,
accountPaytoUri: getPayto(accountName), accountPaytoUri: generateRandomPayto(accountName),
wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/accounts/${accountName}/taler-wire-gateway/`, wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/accounts/${accountName}/taler-wire-gateway/`,
}; };
} }
@ -702,6 +703,140 @@ export class FakebankService
} }
} }
/**
* Implementation of the bank service using the "taler-fakebank-run" tool.
*/
export class LibeufinBankService
extends BankServiceBase
implements BankServiceHandle
{
proc: ProcessWrapper | undefined;
http = createPlatformHttpLib({ enableThrottling: false });
// We store "created" accounts during setup and
// register them after startup.
private accounts: {
accountName: string;
accountPassword: string;
}[] = [];
/**
* Create a new fakebank service handle.
*
* First generates the configuration for the fakebank and
* then creates a fakebank handle, but doesn't start the fakebank
* service yet.
*/
static async create(
gc: GlobalTestState,
bc: BankConfig,
): Promise<LibeufinBankService> {
const config = new Configuration();
const testDir = bc.overrideTestDir ?? gc.testDir;
setTalerPaths(config, testDir + "/talerhome");
config.setString("libeufin-bankdb", "config", bc.database);
config.setString("libeufin-bank", "currency", bc.currency);
config.setString("libeufin-bank", "port", `${bc.httpPort}`);
config.setString("libeufin-bank", "serve", "tcp");
config.setString(
"libeufin-bank",
"DEFAULT_CUSTOMER_DEBT_LIMIT",
`${bc.currency}:500`,
);
config.setString(
"libeufin-bank",
"DEFAULT_ADMIN_DEBT_LIMIT",
`${bc.currency}:999999`,
);
config.setString(
"libeufin-bank",
"registration_bonus",
`${bc.currency}:100`,
);
config.setString("libeufin-bank", "registration_bonus_enabled", `yes`);
config.setString("libeufin-bank", "max_auth_token_duration", "1h");
const cfgFilename = testDir + "/bank.conf";
config.write(cfgFilename, { excludeDefaults: true });
return new LibeufinBankService(gc, bc, cfgFilename);
}
static fromExistingConfig(
gc: GlobalTestState,
opts: { overridePath?: string },
): FakebankService {
const testDir = opts.overridePath ?? gc.testDir;
const cfgFilename = testDir + `/bank.conf`;
const config = Configuration.load(cfgFilename);
const bc: BankConfig = {
allowRegistrations:
config.getYesNo("libeufin-bank", "allow_registrations").orUndefined() ??
true,
currency: config.getString("libeufin-bank", "currency").required(),
database: config
.getString("libeufin-bankdb", "config")
.required(),
httpPort: config.getNumber("libeufin-bank", "port").required(),
maxDebt: config
.getString("libeufin-bank", "DEFAULT_CUSTOMER_DEBT_LIMIT")
.required(),
};
return new FakebankService(gc, bc, cfgFilename);
}
setSuggestedExchange(e: ExchangeServiceInterface) {
if (!!this.proc) {
throw Error("Can't set suggested exchange while bank is running.");
}
const config = Configuration.load(this.configFile);
config.setString("libeufin-bank", "suggested_withdrawal_exchange", e.baseUrl);
config.write(this.configFile, { excludeDefaults: true });
}
get baseUrl(): string {
return `http://localhost:${this.bankConfig.httpPort}/`;
}
get bankAccessApiBaseUrl(): string {
return this.baseUrl;
}
get port() {
return this.bankConfig.httpPort;
}
async start(): Promise<void> {
logger.info("starting libeufin-bank");
if (this.proc) {
logger.info("libeufin-bank already running, not starting again");
return;
}
await sh(
this.globalTestState,
"libeufin-bank-dbinit",
`libeufin-bank dbinit -r -c "${this.configFile}"`,
);
this.proc = this.globalTestState.spawnService(
"libeufin-bank",
["serve", "-c", this.configFile],
"libeufin-bank-httpd",
);
await this.pingUntilAvailable();
const bankClient = new TalerCorebankApiClient(this.bankAccessApiBaseUrl);
for (const acc of this.accounts) {
await bankClient.registerAccount(acc.accountName, acc.accountPassword);
}
}
async pingUntilAvailable(): Promise<void> {
const url = `http://localhost:${this.bankConfig.httpPort}/config`;
await pingProc(this.proc, url, "libeufin-bank");
}
}
// Use libeufin bank instead of pybank. // Use libeufin bank instead of pybank.
const useLibeufinBank = false; const useLibeufinBank = false;
@ -1011,7 +1146,7 @@ export class ExchangeService implements ExchangeServiceInterface {
private exchangeConfig: ExchangeConfig, private exchangeConfig: ExchangeConfig,
private configFilename: string, private configFilename: string,
private keyPair: EddsaKeyPair, private keyPair: EddsaKeyPair,
) { } ) {}
get name() { get name() {
return this.exchangeConfig.name; return this.exchangeConfig.name;
@ -1367,7 +1502,7 @@ export class MerchantService implements MerchantServiceInterface {
private globalState: GlobalTestState, private globalState: GlobalTestState,
private merchantConfig: MerchantConfig, private merchantConfig: MerchantConfig,
private configFilename: string, private configFilename: string,
) { } ) {}
private currentTimetravelOffsetMs: number | undefined; private currentTimetravelOffsetMs: number | undefined;
@ -1495,7 +1630,7 @@ export class MerchantService implements MerchantServiceInterface {
return await this.addInstanceWithWireAccount({ return await this.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
auth: { auth: {
method: "external", method: "external",
}, },
@ -1658,6 +1793,7 @@ export async function runTestWithState(
e.message, e.message,
`error detail: ${j2s(e.errorDetail)}`, `error detail: ${j2s(e.errorDetail)}`,
); );
console.error(e.stack);
} else { } else {
console.error("FATAL: test failed with exception", e); console.error("FATAL: test failed with exception", e);
} }
@ -1705,7 +1841,7 @@ export class WalletService {
constructor( constructor(
private globalState: GlobalTestState, private globalState: GlobalTestState,
private opts: WalletServiceOptions, private opts: WalletServiceOptions,
) { } ) {}
get socketPath() { get socketPath() {
const unixPath = path.join( const unixPath = path.join(
@ -1814,7 +1950,7 @@ export class WalletClient {
return client.call(operation, payload); return client.call(operation, payload);
} }
constructor(private args: WalletClientArgs) { } constructor(private args: WalletClientArgs) {}
async connect(): Promise<void> { async connect(): Promise<void> {
const waiter = this.waiter; const waiter = this.waiter;
@ -1881,9 +2017,11 @@ export class WalletCli {
? `--crypto-worker=${cliOpts.cryptoWorkerType}` ? `--crypto-worker=${cliOpts.cryptoWorkerType}`
: ""; : "";
const logName = `wallet-${self.name}`; const logName = `wallet-${self.name}`;
const command = `taler-wallet-cli ${self.timetravelArg ?? "" const command = `taler-wallet-cli ${
} ${cryptoWorkerArg} --no-throttle -LTRACE --skip-defaults --wallet-db '${self.dbfile self.timetravelArg ?? ""
}' api '${op}' ${shellWrap(JSON.stringify(payload))}`; } ${cryptoWorkerArg} --no-throttle -LTRACE --skip-defaults --wallet-db '${
self.dbfile
}' api '${op}' ${shellWrap(JSON.stringify(payload))}`;
const resp = await sh(self.globalTestState, logName, command); const resp = await sh(self.globalTestState, logName, command);
logger.info("--- wallet core response ---"); logger.info("--- wallet core response ---");
logger.info(resp); logger.info(resp);
@ -1966,7 +2104,7 @@ export class WalletCli {
} }
} }
export function getRandomIban(salt: string | null = null): string { export function generateRandomTestIban(salt: string | null = null): string {
function getBban(salt: string | null): string { function getBban(salt: string | null): string {
if (!salt) return Math.random().toString().substring(2, 6); if (!salt) return Math.random().toString().substring(2, 6);
let hashed = hash(stringToBytes(salt)); let hashed = hash(stringToBytes(salt));
@ -1998,9 +2136,9 @@ export function getWireMethodForTest(): string {
* Generate a payto address, whose authority depends * Generate a payto address, whose authority depends
* on whether the banking is served by euFin or Pybank. * on whether the banking is served by euFin or Pybank.
*/ */
export function getPayto(label: string): string { export function generateRandomPayto(label: string): string {
if (useLibeufinBank) if (useLibeufinBank)
return `payto://iban/SANDBOXX/${getRandomIban( return `payto://iban/SANDBOXX/${generateRandomTestIban(
label, label,
)}?receiver-name=${label}`; )}?receiver-name=${label}`;
return `payto://x-taler-bank/localhost/${label}`; return `payto://x-taler-bank/localhost/${label}`;

View File

@ -56,7 +56,7 @@ import {
WalletClient, WalletClient,
WalletService, WalletService,
WithAuthorization, WithAuthorization,
getPayto, generateRandomPayto,
setupDb, setupDb,
setupSharedDb, setupSharedDb,
} from "./harness.js"; } from "./harness.js";
@ -236,7 +236,7 @@ export async function useSharedTestkudosEnvironment(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),
@ -245,7 +245,7 @@ export async function useSharedTestkudosEnvironment(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),
@ -368,7 +368,7 @@ export async function createSimpleTestkudosEnvironmentV2(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),
@ -377,7 +377,7 @@ export async function createSimpleTestkudosEnvironmentV2(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),
@ -512,13 +512,13 @@ export async function createFaultInjectedMerchantTestkudosEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -30,7 +30,7 @@ import {
ExchangeService, ExchangeService,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
getPayto, generateRandomPayto,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -88,13 +88,13 @@ export async function runBankApiTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -23,7 +23,7 @@ import {
TransactionMinorState, TransactionMinorState,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { GlobalTestState, getPayto } from "../harness/harness.js"; import { GlobalTestState, generateRandomPayto } from "../harness/harness.js";
import { import {
createSimpleTestkudosEnvironmentV2, createSimpleTestkudosEnvironmentV2,
withdrawViaBankV2, withdrawViaBankV2,
@ -75,7 +75,7 @@ export async function runDepositTest(t: GlobalTestState) {
WalletApiOperation.CreateDepositGroup, WalletApiOperation.CreateDepositGroup,
{ {
amount: "TESTKUDOS:10", amount: "TESTKUDOS:10",
depositPaytoUri: getPayto("foo"), depositPaytoUri: generateRandomPayto("foo"),
transactionId: depositTxId, transactionId: depositTxId,
}, },
); );

View File

@ -36,7 +36,7 @@ import {
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
WalletCli, WalletCli,
getPayto, generateRandomPayto,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -105,13 +105,13 @@ export async function runExchangeManagementTest(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -35,7 +35,7 @@ import { makeNoFeeCoinConfig } from "../harness/denomStructures.js";
import { import {
BankService, BankService,
ExchangeService, ExchangeService,
getPayto, generateRandomPayto,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
setupDb, setupDb,
@ -151,13 +151,13 @@ export async function runExchangeTimetravelTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -23,7 +23,7 @@ import {
ExchangeService, ExchangeService,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
getPayto, generateRandomPayto,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
import { import {
@ -142,7 +142,7 @@ export async function createMyTestkudosEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -34,7 +34,7 @@ import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
import { import {
BankService, BankService,
ExchangeService, ExchangeService,
getPayto, generateRandomPayto,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
setupDb, setupDb,
@ -162,7 +162,7 @@ export async function createKycTestkudosEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),
@ -171,7 +171,7 @@ export async function createKycTestkudosEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),
), ),

View File

@ -0,0 +1,222 @@
/*
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 {
TalerCorebankApiClient,
CreditDebitIndicator,
WireGatewayApiClient,
createEddsaKeyPair,
encodeCrock,
Logger,
j2s,
NotificationType,
TransactionMajorState,
TransactionMinorState,
} from "@gnu-taler/taler-util";
import { defaultCoinConfig } from "../harness/denomStructures.js";
import {
ExchangeService,
GlobalTestState,
LibeufinBankService,
MerchantService,
generateRandomPayto,
generateRandomTestIban,
setupDb,
} from "../harness/harness.js";
import { createWalletDaemonWithClient } from "../harness/helpers.js";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
const logger = new Logger("test-libeufin-bank.ts");
/**
* Run test for the basic functionality of libeufin-bank.
*/
export async function runLibeufinBankTest(t: GlobalTestState) {
// Set up test environment
const db = await setupDb(t);
const bank = await LibeufinBankService.create(t, {
currency: "TESTKUDOS",
httpPort: 8082,
database: db.connStr,
allowRegistrations: true,
});
const exchange = ExchangeService.create(t, {
name: "testexchange-1",
currency: "TESTKUDOS",
httpPort: 8081,
database: db.connStr,
});
const merchant = await MerchantService.create(t, {
name: "testmerchant-1",
currency: "TESTKUDOS",
httpPort: 8083,
database: db.connStr,
});
const exchangeIban = generateRandomTestIban();
const exchangeBankUsername = "exchange";
const exchangeBankPw = "mypw";
const exchangePlainPayto = `payto://iban/${exchangeIban}`;
const exchangeExtendedPayto = `payto://iban/${exchangeIban}?receiver-name=Exchange`;
const wireGatewayApiBaseUrl = new URL(
"accounts/exchange/taler-wire-gateway/",
bank.baseUrl,
).href;
logger.info("creating bank account for the exchange");
exchange.addBankAccount("1", {
wireGatewayApiBaseUrl,
accountName: exchangeBankUsername,
accountPassword: exchangeBankPw,
accountPaytoUri: exchangeExtendedPayto,
});
bank.setSuggestedExchange(exchange);
await bank.start();
await bank.pingUntilAvailable();
exchange.addOfferedCoins(defaultCoinConfig);
await exchange.start();
await exchange.pingUntilAvailable();
merchant.addExchange(exchange);
await merchant.start();
await merchant.pingUntilAvailable();
await merchant.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
paytoUris: [generateRandomPayto("merchant-default")],
});
await merchant.addInstanceWithWireAccount({
id: "minst1",
name: "minst1",
paytoUris: [generateRandomPayto("minst1")],
});
const { walletClient } = await createWalletDaemonWithClient(t, {
name: "wallet",
});
console.log("setup done!");
const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl);
// register exchange bank account
await bankClient.registerAccountExtended({
name: "Exchange",
password: exchangeBankPw,
username: exchangeBankUsername,
is_taler_exchange: true,
internal_payto_uri: exchangePlainPayto,
});
const bankUser = await bankClient.registerAccount("user1", "pw1");
bankClient.setAuth({
username: "user1",
password: "pw1",
});
// Make sure that registering twice results in a 409 Conflict
// {
// const e = await t.assertThrowsTalerErrorAsync(async () => {
// await bankClient.registerAccount("user1", "pw2");
// });
// t.assertTrue(e.errorDetail.httpStatusCode === 409);
// }
let balResp = await bankClient.getAccountBalance(bankUser.username);
console.log(balResp);
// Check that we got the sign-up bonus.
t.assertAmountEquals(balResp.balance.amount, "TESTKUDOS:100");
t.assertTrue(
balResp.balance.credit_debit_indicator === CreditDebitIndicator.Credit,
);
const res = createEddsaKeyPair();
const wireGatewayApiClient = new WireGatewayApiClient(wireGatewayApiBaseUrl, {
auth: {
username: exchangeBankUsername,
password: exchangeBankPw,
},
});
await wireGatewayApiClient.adminAddIncoming({
amount: "TESTKUDOS:115",
debitAccountPayto: bankUser.accountPaytoUri,
reservePub: encodeCrock(res.eddsaPub),
});
balResp = await bankClient.getAccountBalance(bankUser.username);
t.assertAmountEquals(balResp.balance.amount, "TESTKUDOS:15");
t.assertTrue(
balResp.balance.credit_debit_indicator === CreditDebitIndicator.Debit,
);
const wop = await bankClient.createWithdrawalOperation(
bankUser.username,
"TESTKUDOS:10",
);
const r1 = await walletClient.client.call(
WalletApiOperation.GetWithdrawalDetailsForUri,
{
talerWithdrawUri: wop.taler_withdraw_uri,
},
);
console.log(j2s(r1));
const r2 = await walletClient.client.call(
WalletApiOperation.AcceptBankIntegratedWithdrawal,
{
exchangeBaseUrl: exchange.baseUrl,
talerWithdrawUri: wop.taler_withdraw_uri,
},
);
await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
transactionId: r2.transactionId,
txState: {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.BankConfirmTransfer,
},
});
await bankClient.confirmWithdrawalOperation(bankUser.username, {
withdrawalOperationId: wop.withdrawal_id,
});
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
}
runLibeufinBankTest.suites = ["fakebank"];

View File

@ -33,7 +33,7 @@ import {
import { import {
BankService, BankService,
ExchangeService, ExchangeService,
getPayto, generateRandomPayto,
GlobalTestState, GlobalTestState,
harnessHttpLib, harnessHttpLib,
MerchantService, MerchantService,
@ -112,13 +112,13 @@ export async function createConfusedMerchantTestkudosEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -22,7 +22,7 @@ import {
ExchangeService, ExchangeService,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
getPayto, generateRandomPayto,
harnessHttpLib, harnessHttpLib,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -78,7 +78,7 @@ export async function runMerchantInstancesDeleteTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
auth: { auth: {
method: "external", method: "external",
}, },
@ -88,7 +88,7 @@ export async function runMerchantInstancesDeleteTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "myinst", id: "myinst",
name: "Second Instance", name: "Second Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
auth: { auth: {
method: "external", method: "external",
}, },

View File

@ -22,7 +22,7 @@ import {
ExchangeService, ExchangeService,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
getPayto, generateRandomPayto,
harnessHttpLib, harnessHttpLib,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -74,7 +74,7 @@ export async function runMerchantInstancesUrlsTest(t: GlobalTestState) {
name: "My Default Instance", name: "My Default Instance",
accounts: [ accounts: [
{ {
payto_uri: getPayto("bar"), payto_uri: generateRandomPayto("bar"),
}, },
], ],
auth: { auth: {
@ -97,7 +97,7 @@ export async function runMerchantInstancesUrlsTest(t: GlobalTestState) {
name: "My Second Instance", name: "My Second Instance",
accounts: [ accounts: [
{ {
payto_uri: getPayto("bar"), payto_uri: generateRandomPayto("bar"),
}, },
], ],
auth: { auth: {

View File

@ -23,7 +23,7 @@ import {
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
setupDb, setupDb,
getPayto, generateRandomPayto,
harnessHttpLib, harnessHttpLib,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -78,7 +78,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
auth: { auth: {
method: "external", method: "external",
}, },
@ -88,7 +88,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
auth: { auth: {
method: "external", method: "external",
}, },
@ -98,7 +98,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "myinst", id: "myinst",
name: "Second Instance", name: "Second Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
auth: { auth: {
method: "external", method: "external",
}, },

View File

@ -39,7 +39,7 @@ import {
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
WalletCli, WalletCli,
getPayto, generateRandomPayto,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -116,7 +116,7 @@ export async function runPaymentFaultTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl());

View File

@ -25,7 +25,7 @@ import {
ExchangeService, ExchangeService,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
getPayto, generateRandomPayto,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
import { import {
@ -87,13 +87,13 @@ async function setupTest(t: GlobalTestState): Promise<{
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -27,7 +27,7 @@ import {
setupDb, setupDb,
BankService, BankService,
delayMs, delayMs,
getPayto, generateRandomPayto,
WalletClient, WalletClient,
} from "../harness/harness.js"; } from "../harness/harness.js";
import { import {
@ -125,13 +125,13 @@ async function createTestEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -32,7 +32,7 @@ import { makeNoFeeCoinConfig } from "../harness/denomStructures.js";
import { import {
BankService, BankService,
ExchangeService, ExchangeService,
getPayto, generateRandomPayto,
GlobalTestState, GlobalTestState,
MerchantService, MerchantService,
setupDb, setupDb,
@ -97,13 +97,13 @@ export async function runTimetravelAutorefreshTest(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "minst1", id: "minst1",
name: "minst1", name: "minst1",
paytoUris: [getPayto("minst1")], paytoUris: [generateRandomPayto("minst1")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -32,7 +32,7 @@ import {
MerchantService, MerchantService,
WalletClient, WalletClient,
WalletService, WalletService,
getRandomIban, generateRandomTestIban,
setupDb, setupDb,
} from "../harness/harness.js"; } from "../harness/harness.js";
@ -94,7 +94,7 @@ export async function runWalletNotificationsTest(t: GlobalTestState) {
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [ paytoUris: [
`payto://iban/SANDBOXX/${getRandomIban(label)}?receiver-name=${label}`, `payto://iban/SANDBOXX/${generateRandomTestIban(label)}?receiver-name=${label}`,
], ],
defaultWireTransferDelay: Duration.toTalerProtocolDuration( defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }), Duration.fromSpec({ minutes: 1 }),

View File

@ -32,7 +32,7 @@ import {
MerchantService, MerchantService,
setupDb, setupDb,
WalletCli, WalletCli,
getPayto, generateRandomPayto,
} from "../harness/harness.js"; } from "../harness/harness.js";
import { SimpleTestEnvironment } from "../harness/helpers.js"; import { SimpleTestEnvironment } from "../harness/helpers.js";
@ -94,7 +94,7 @@ export async function createMyEnvironment(
await merchant.addInstanceWithWireAccount({ await merchant.addInstanceWithWireAccount({
id: "default", id: "default",
name: "Default Instance", name: "Default Instance",
paytoUris: [getPayto("merchant-default")], paytoUris: [generateRandomPayto("merchant-default")],
}); });
console.log("setup done!"); console.log("setup done!");

View File

@ -41,12 +41,12 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) {
// Create a withdrawal operation // Create a withdrawal operation
const bankAccessApiClient = new TalerCorebankApiClient( const corebankApiClient = new TalerCorebankApiClient(
bank.bankAccessApiBaseUrl, bank.bankAccessApiBaseUrl,
); );
const user = await bankAccessApiClient.createRandomBankUser(); const user = await corebankApiClient.createRandomBankUser();
bankAccessApiClient.setAuth(user); corebankApiClient.setAuth(user);
const wop = await bankAccessApiClient.createWithdrawalOperation( const wop = await corebankApiClient.createWithdrawalOperation(
user.username, user.username,
"TESTKUDOS:10", "TESTKUDOS:10",
); );
@ -129,7 +129,7 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) {
// Confirm it // Confirm it
await bankAccessApiClient.confirmWithdrawalOperation(user.username, { await corebankApiClient.confirmWithdrawalOperation(user.username, {
withdrawalOperationId: wop.withdrawal_id, withdrawalOperationId: wop.withdrawal_id,
}); });

View File

@ -92,6 +92,7 @@ import { runWithdrawalFeesTest } from "./test-withdrawal-fees.js";
import { runWithdrawalHugeTest } from "./test-withdrawal-huge.js"; import { runWithdrawalHugeTest } from "./test-withdrawal-huge.js";
import { runWithdrawalManualTest } from "./test-withdrawal-manual.js"; import { runWithdrawalManualTest } from "./test-withdrawal-manual.js";
import { runWalletGenDbTest } from "./test-wallet-gendb.js"; import { runWalletGenDbTest } from "./test-wallet-gendb.js";
import { runLibeufinBankTest } from "./test-libeufin-bank.js";
/** /**
* Test runner. * Test runner.
@ -173,6 +174,7 @@ const allTests: TestMainFunction[] = [
runStoredBackupsTest, runStoredBackupsTest,
runPaymentExpiredTest, runPaymentExpiredTest,
runWalletGenDbTest, runWalletGenDbTest,
runLibeufinBankTest,
]; ];
export interface TestRunSpec { export interface TestRunSpec {

View File

@ -264,7 +264,7 @@ export class TalerCorebankApiClient {
const resp = await this.httpLib.fetch(url.href, { const resp = await this.httpLib.fetch(url.href, {
headers: this.makeAuthHeader(), headers: this.makeAuthHeader(),
}); });
return await resp.json(); return readSuccessResponseJsonOrThrow(resp, codecForAny());
} }
async getTransactions(username: string): Promise<void> { async getTransactions(username: string): Promise<void> {
@ -295,6 +295,30 @@ export class TalerCorebankApiClient {
return await readSuccessResponseJsonOrThrow(resp, codecForAny()); return await readSuccessResponseJsonOrThrow(resp, codecForAny());
} }
async registerAccountExtended(req: RegisterAccountRequest): Promise<void> {
const url = new URL("accounts", this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body: req,
});
if (
resp.status !== 200 &&
resp.status !== 201 &&
resp.status !== 202 &&
resp.status !== 204
) {
logger.error(`unexpected status ${resp.status} from POST ${url.href}`);
logger.error(`${j2s(await resp.json())}`);
throw TalerError.fromDetail(
TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
{
httpStatusCode: resp.status,
},
);
}
}
/** /**
* Register a new account and return information about it. * Register a new account and return information about it.
* *
@ -311,7 +335,13 @@ export class TalerCorebankApiClient {
name: username, name: username,
}, },
}); });
if (resp.status !== 200 && resp.status !== 202 && resp.status !== 204) { if (
resp.status !== 200 &&
resp.status !== 201 &&
resp.status !== 202 &&
resp.status !== 204
) {
logger.error(`unexpected status ${resp.status} from POST ${url.href}`);
logger.error(`${j2s(await resp.json())}`); logger.error(`${j2s(await resp.json())}`);
throw TalerError.fromDetail( throw TalerError.fromDetail(
TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
@ -320,8 +350,13 @@ export class TalerCorebankApiClient {
}, },
); );
} }
// FIXME: Corebank should directly return this info!
const infoUrl = new URL(`accounts/${username}`, this.baseUrl); const infoUrl = new URL(`accounts/${username}`, this.baseUrl);
const infoResp = await this.httpLib.fetch(infoUrl.href); const infoResp = await this.httpLib.fetch(infoUrl.href, {
headers: {
Authorization: makeBasicAuthHeader(username, password),
},
});
// FIXME: Validate! // FIXME: Validate!
const acctInfo: AccountData = await readSuccessResponseJsonOrThrow( const acctInfo: AccountData = await readSuccessResponseJsonOrThrow(
infoResp, infoResp,

View File

@ -143,9 +143,9 @@ export function expandPath(path: string): string {
export function pathsub( export function pathsub(
x: string, x: string,
lookup: (s: string, depth: number) => string | undefined, lookup: (s: string, depth: number) => string | undefined,
depth = 0, recursionDepth = 0,
): string { ): string {
if (depth >= 128) { if (recursionDepth >= 128) {
throw Error("recursion in path substitution"); throw Error("recursion in path substitution");
} }
let s = x; let s = x;
@ -201,7 +201,7 @@ export function pathsub(
} else { } else {
const m = /^[a-zA-Z-_][a-zA-Z0-9-_]*/.exec(s.substring(l + 1)); const m = /^[a-zA-Z-_][a-zA-Z0-9-_]*/.exec(s.substring(l + 1));
if (m && m[0]) { if (m && m[0]) {
const r = lookup(m[0], depth + 1); const r = lookup(m[0], recursionDepth + 1);
if (r !== undefined) { if (r !== undefined) {
s = s.substring(0, l) + r + s.substring(l + 1 + m[0].length); s = s.substring(0, l) + r + s.substring(l + 1 + m[0].length);
l = l + r.length; l = l + r.length;

View File

@ -73,7 +73,13 @@ import {
codecForAbsoluteTime, codecForAbsoluteTime,
codecForTimestamp, codecForTimestamp,
} from "./time.js"; } from "./time.js";
import { OrderShortInfo, TransactionType } from "./transactions-types.js"; import {
OrderShortInfo,
TransactionMajorState,
TransactionMinorState,
TransactionState,
TransactionType,
} from "./transactions-types.js";
/** /**
* Identifier for a transaction in the wallet. * Identifier for a transaction in the wallet.
@ -2715,3 +2721,8 @@ export interface WalletContractData {
maxDepositFee: AmountString; maxDepositFee: AmountString;
minimumAge?: number; minimumAge?: number;
} }
export interface TestingWaitTransactionRequest {
transactionId: string;
txState: TransactionState;
}

View File

@ -23,6 +23,7 @@ import {
ConfirmPayResultType, ConfirmPayResultType,
Duration, Duration,
IntegrationTestV2Args, IntegrationTestV2Args,
j2s,
Logger, Logger,
NotificationType, NotificationType,
RegisterAccountRequest, RegisterAccountRequest,
@ -31,6 +32,7 @@ import {
TestPayResult, TestPayResult,
TransactionMajorState, TransactionMajorState,
TransactionMinorState, TransactionMinorState,
TransactionState,
TransactionType, TransactionType,
WithdrawTestBalanceRequest, WithdrawTestBalanceRequest,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
@ -494,6 +496,49 @@ async function waitUntilPendingReady(
cancelNotifs(); cancelNotifs();
} }
/**
* Wait until a transaction is in a particular state.
*/
export async function waitTransactionState(
ws: InternalWalletState,
transactionId: string,
txState: TransactionState,
): Promise<void> {
logger.info(
`starting waiting for ${transactionId} to be in ${JSON.stringify(
txState,
)})`,
);
ws.ensureTaskLoopRunning();
let p: OpenedPromise<void> | undefined = undefined;
const cancelNotifs = ws.addNotificationListener((notif) => {
if (!p) {
return;
}
if (notif.type === NotificationType.TransactionStateTransition) {
p.resolve();
}
});
while (1) {
p = openPromise();
const tx = await getTransactionById(ws, {
transactionId,
});
if (
tx.txState.major === txState.major &&
tx.txState.minor === txState.minor
) {
break;
}
// Wait until transaction state changed
await p.promise;
}
logger.info(
`done waiting for ${transactionId} to be in ${JSON.stringify(txState)}`,
);
cancelNotifs();
}
export async function runIntegrationTest2( export async function runIntegrationTest2(
ws: InternalWalletState, ws: InternalWalletState,
args: IntegrationTestV2Args, args: IntegrationTestV2Args,

View File

@ -104,6 +104,7 @@ import {
TestPayArgs, TestPayArgs,
TestPayResult, TestPayResult,
TestingSetTimetravelRequest, TestingSetTimetravelRequest,
TestingWaitTransactionRequest,
Transaction, Transaction,
TransactionByIdRequest, TransactionByIdRequest,
TransactionsRequest, TransactionsRequest,
@ -214,6 +215,7 @@ export enum WalletApiOperation {
ValidateIban = "validateIban", ValidateIban = "validateIban",
TestingWaitTransactionsFinal = "testingWaitTransactionsFinal", TestingWaitTransactionsFinal = "testingWaitTransactionsFinal",
TestingWaitRefreshesFinal = "testingWaitRefreshesFinal", TestingWaitRefreshesFinal = "testingWaitRefreshesFinal",
TestingWaitTransactionState = "testingWaitTransactionState",
TestingSetTimetravel = "testingSetTimetravel", TestingSetTimetravel = "testingSetTimetravel",
GetScopedCurrencyInfo = "getScopedCurrencyInfo", GetScopedCurrencyInfo = "getScopedCurrencyInfo",
ListStoredBackups = "listStoredBackups", ListStoredBackups = "listStoredBackups",
@ -1004,6 +1006,15 @@ export type TestingWaitRefreshesFinal = {
response: EmptyObject; response: EmptyObject;
}; };
/**
* Wait until a transaction is in a particular state.
*/
export type TestingWaitTransactionStateOp = {
op: WalletApiOperation.TestingWaitTransactionState;
request: TestingWaitTransactionRequest;
response: EmptyObject;
};
/** /**
* Set a coin as (un-)suspended. * Set a coin as (un-)suspended.
* Suspended coins won't be used for payments. * Suspended coins won't be used for payments.
@ -1108,6 +1119,7 @@ export type WalletOperations = {
[WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal; [WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal;
[WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinal; [WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinal;
[WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp; [WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp;
[WalletApiOperation.TestingWaitTransactionState]: TestingWaitTransactionStateOp;
[WalletApiOperation.GetScopedCurrencyInfo]: GetScopedCurrencyInfoOp; [WalletApiOperation.GetScopedCurrencyInfo]: GetScopedCurrencyInfoOp;
[WalletApiOperation.CreateStoredBackup]: CreateStoredBackupsOp; [WalletApiOperation.CreateStoredBackup]: CreateStoredBackupsOp;
[WalletApiOperation.ListStoredBackups]: ListStoredBackupsOp; [WalletApiOperation.ListStoredBackups]: ListStoredBackupsOp;

View File

@ -127,6 +127,7 @@ import {
codecForRecoverStoredBackupRequest, codecForRecoverStoredBackupRequest,
codecForTestingSetTimetravelRequest, codecForTestingSetTimetravelRequest,
setDangerousTimetravel, setDangerousTimetravel,
TestingWaitTransactionRequest,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
@ -250,6 +251,7 @@ import {
runIntegrationTest, runIntegrationTest,
runIntegrationTest2, runIntegrationTest2,
testPay, testPay,
waitTransactionState,
waitUntilDone, waitUntilDone,
waitUntilRefreshesDone, waitUntilRefreshesDone,
withdrawTestBalance, withdrawTestBalance,
@ -1414,6 +1416,11 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
const resp = await getBackupRecovery(ws); const resp = await getBackupRecovery(ws);
return resp; return resp;
} }
case WalletApiOperation.TestingWaitTransactionState: {
const req = payload as TestingWaitTransactionRequest;
await waitTransactionState(ws, req.transactionId, req.txState);
return {};
}
case WalletApiOperation.GetScopedCurrencyInfo: { case WalletApiOperation.GetScopedCurrencyInfo: {
// Ignore result, just validate in this mock implementation // Ignore result, just validate in this mock implementation
codecForGetCurrencyInfoRequest().decode(payload); codecForGetCurrencyInfoRequest().decode(payload);