integration tests: various fixes

This commit is contained in:
Florian Dold 2022-08-25 23:35:29 +02:00
parent 499e003ff8
commit 70d0199572
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
10 changed files with 70 additions and 118 deletions

View File

@ -22,8 +22,8 @@ import { CoinConfig, defaultCoinConfig } from "./harness/denomStructures.js";
import { import {
GlobalTestState, GlobalTestState,
setupDb, setupDb,
FakeBankService,
ExchangeService, ExchangeService,
FakebankService,
} from "./harness/harness.js"; } from "./harness/harness.js";
/** /**
@ -35,9 +35,11 @@ import {
export async function runEnv1(t: GlobalTestState): Promise<void> { export async function runEnv1(t: GlobalTestState): Promise<void> {
const db = await setupDb(t); const db = await setupDb(t);
const bank = await FakeBankService.create(t, { const bank = await FakebankService.create(t, {
currency: "TESTKUDOS", currency: "TESTKUDOS",
httpPort: 8082, httpPort: 8082,
allowRegistrations: true,
database: db.connStr,
}); });
const exchange = ExchangeService.create(t, { const exchange = ExchangeService.create(t, {

View File

@ -775,11 +775,21 @@ class LibEuFinBankService extends BankServiceBase implements BankServiceHandle {
/** /**
* Implementation of the bank service using the "taler-fakebank-run" tool. * 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; proc: ProcessWrapper | undefined;
http = new NodeHttpLib(); http = new NodeHttpLib();
// We store "created" accounts during setup and
// register them after startup.
private accounts: {
accountName: string;
accountPassword: string;
}[] = [];
static async create( static async create(
gc: GlobalTestState, gc: GlobalTestState,
bc: BankConfig, bc: BankConfig,
@ -791,6 +801,7 @@ class FakebankService extends BankServiceBase implements BankServiceHandle {
config.setString("bank", "serve", "http"); config.setString("bank", "serve", "http");
config.setString("bank", "max_debt_bank", `${bc.currency}:999999`); config.setString("bank", "max_debt_bank", `${bc.currency}:999999`);
config.setString("bank", "max_debt", bc.maxDebt ?? `${bc.currency}:100`); config.setString("bank", "max_debt", bc.maxDebt ?? `${bc.currency}:100`);
config.setString("bank", "ram_limit", `${1024}`);
const cfgFilename = gc.testDir + "/bank.conf"; const cfgFilename = gc.testDir + "/bank.conf";
config.write(cfgFilename); config.write(cfgFilename);
@ -798,6 +809,9 @@ class FakebankService extends BankServiceBase implements BankServiceHandle {
} }
setSuggestedExchange(e: ExchangeServiceInterface, exchangePayto: string) { 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); const config = Configuration.load(this.configFile);
config.setString("bank", "suggested_exchange", e.baseUrl); config.setString("bank", "suggested_exchange", e.baseUrl);
config.write(this.configFile); config.write(this.configFile);
@ -816,10 +830,10 @@ class FakebankService extends BankServiceBase implements BankServiceHandle {
accountName: string, accountName: string,
password: string, password: string,
): Promise<HarnessExchangeBankAccount> { ): Promise<HarnessExchangeBankAccount> {
// FIXME: Is there a better place to do this initialization? this.accounts.push({
await this.start(); accountName,
await this.pingUntilAvailable(); accountPassword: password,
await BankApi.registerAccount(this, accountName, password); });
return { return {
accountName: accountName, accountName: accountName,
accountPassword: password, accountPassword: password,
@ -833,15 +847,25 @@ class FakebankService extends BankServiceBase implements BankServiceHandle {
} }
async start(): Promise<void> { async start(): Promise<void> {
logger.info("starting fakebank");
if (this.proc) { if (this.proc) {
logger.info("fakebank already running, not starting again"); logger.info("fakebank already running, not starting again");
return; return;
} }
this.proc = this.globalTestState.spawnService( this.proc = this.globalTestState.spawnService(
"taler-fakebank-run", "taler-fakebank-run",
["-c", this.configFile], [
"-c",
this.configFile,
"--signup-bonus",
`${this.bankConfig.currency}:100`,
],
"bank", "bank",
); );
await this.pingUntilAvailable();
for (const acc of this.accounts) {
await BankApi.registerAccount(this, acc.accountName, acc.accountPassword);
}
} }
async pingUntilAvailable(): Promise<void> { async pingUntilAvailable(): Promise<void> {
@ -853,86 +877,8 @@ class FakebankService extends BankServiceBase implements BankServiceHandle {
// Use libeufin bank instead of pybank. // Use libeufin bank instead of pybank.
const useLibeufinBank = false; const useLibeufinBank = false;
/** export type BankService = BankServiceHandle;
* Return a euFin or a pyBank implementation of export const BankService = FakebankService;
* 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<FakeBankService> {
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<void> {
this.proc = this.globalTestState.spawnService(
"taler-fakebank-run",
["-c", this.configFile],
"fakebank",
);
}
async pingUntilAvailable(): Promise<void> {
// Fakebank doesn't have "/config", so we ping just "/".
const url = `http://localhost:${this.bankConfig.httpPort}/`;
await pingProc(this.proc, url, "bank");
}
}
export interface ExchangeConfig { export interface ExchangeConfig {
name: string; name: string;

View File

@ -691,8 +691,8 @@ export class LibeufinCli {
): Promise<void> { ): Promise<void> {
const stdout = await sh( const stdout = await sh(
this.globalTestState, this.globalTestState,
"libeufin-cli-submitpayment", "libeufin-cli-submitpayments",
`libeufin-cli accounts submit-payment` + `libeufin-cli accounts submit-payments` +
` --payment-uuid=${paymentUuid}` + ` --payment-uuid=${paymentUuid}` +
` ${details.nexusBankAccountName}`, ` ${details.nexusBankAccountName}`,
{ {

View File

@ -43,10 +43,10 @@ export async function runBankApiTest(t: GlobalTestState) {
const db = await setupDb(t); const db = await setupDb(t);
const bank = await BankService.create(t, { const bank = await BankService.create(t, {
allowRegistrations: true,
currency: "TESTKUDOS", currency: "TESTKUDOS",
database: db.connStr,
httpPort: 8082, httpPort: 8082,
database: db.connStr,
allowRegistrations: true,
}); });
const exchange = ExchangeService.create(t, { const exchange = ExchangeService.create(t, {

View File

@ -17,17 +17,9 @@
/** /**
* Imports. * Imports.
*/ */
import { import { j2s } from "@gnu-taler/taler-util";
ConfirmPayResultType, import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
j2s, import { GlobalTestState } from "../harness/harness.js";
PreparePayResultType,
} from "@gnu-taler/taler-util";
import { Wallet, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import {
GlobalTestState,
MerchantPrivateApi,
WithAuthorization,
} from "../harness/harness.js";
import { createSimpleTestkudosEnvironment } from "../harness/helpers.js"; import { createSimpleTestkudosEnvironment } from "../harness/helpers.js";
/** /**

View File

@ -54,6 +54,7 @@ export async function runWithdrawalAbortBankTest(t: GlobalTestState) {
// Abort it // Abort it
await BankApi.abortWithdrawalOperation(bank, user, wop); await BankApi.abortWithdrawalOperation(bank, user, wop);
//await BankApi.confirmWithdrawalOperation(bank, user, wop);
// Withdraw // Withdraw

View File

@ -22,7 +22,7 @@ import {
WalletCli, WalletCli,
setupDb, setupDb,
ExchangeService, ExchangeService,
FakeBankService, FakebankService,
} from "../harness/harness.js"; } from "../harness/harness.js";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js"; import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@ -36,9 +36,12 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) {
const db = await setupDb(t); const db = await setupDb(t);
const bank = await FakeBankService.create(t, { const bank = await FakebankService.create(t, {
currency: "TESTKUDOS", currency: "TESTKUDOS",
httpPort: 8082, httpPort: 8082,
allowRegistrations: true,
// Not used by fakebank
database: db.connStr,
}); });
const exchange = ExchangeService.create(t, { const exchange = ExchangeService.create(t, {

View File

@ -106,7 +106,7 @@ export namespace BankApi {
const url = new URL("testing/register", bank.bankAccessApiBaseUrl); const url = new URL("testing/register", bank.bankAccessApiBaseUrl);
const resp = await bank.http.postJson(url.href, { username, password }); const resp = await bank.http.postJson(url.href, { username, password });
let paytoUri = `payto://x-taler-bank/localhost/${username}`; 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())}`); logger.error(`${j2s(await resp.json())}`);
throw TalerError.fromDetail( throw TalerError.fromDetail(
TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
@ -209,7 +209,7 @@ export namespace BankApi {
): Promise<void> { ): Promise<void> {
const url = new URL( const url = new URL(
`accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/abort`, `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/abort`,
bank.baseUrl, bank.bankAccessApiBaseUrl,
); );
const resp = await bank.http.postJson( const resp = await bank.http.postJson(
url.href, url.href,

View File

@ -90,16 +90,21 @@ export async function withdrawTestBalance(
ws: InternalWalletState, ws: InternalWalletState,
req: WithdrawTestBalanceRequest, req: WithdrawTestBalanceRequest,
): Promise<void> { ): Promise<void> {
const bankBaseUrl = req.bankBaseUrl;
const amount = req.amount; const amount = req.amount;
const exchangeBaseUrl = req.exchangeBaseUrl; 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)}`); logger.trace(`Registered bank user ${JSON.stringify(bankUser)}`);
const wresp = await createDemoBankWithdrawalUri( const wresp = await createDemoBankWithdrawalUri(
ws.http, ws.http,
bankBaseUrl, req.bankAccessApiBaseUrl,
bankUser, bankUser,
amount, amount,
); );
@ -112,7 +117,7 @@ export async function withdrawTestBalance(
await confirmBankWithdrawalUri( await confirmBankWithdrawalUri(
ws.http, ws.http,
bankBaseUrl, req.bankAccessApiBaseUrl,
bankUser, bankUser,
wresp.withdrawal_id, wresp.withdrawal_id,
); );
@ -133,13 +138,13 @@ function getMerchantAuthHeader(m: MerchantBackendInfo): Record<string, string> {
*/ */
export async function createDemoBankWithdrawalUri( export async function createDemoBankWithdrawalUri(
http: HttpRequestLibrary, http: HttpRequestLibrary,
bankBaseUrl: string, bankAccessApiBaseUrl: string,
bankUser: BankUser, bankUser: BankUser,
amount: AmountString, amount: AmountString,
): Promise<BankWithdrawalResponse> { ): Promise<BankWithdrawalResponse> {
const reqUrl = new URL( const reqUrl = new URL(
`accounts/${bankUser.username}/withdrawals`, `accounts/${bankUser.username}/withdrawals`,
bankBaseUrl, bankAccessApiBaseUrl,
).href; ).href;
const resp = await http.postJson( const resp = await http.postJson(
reqUrl, reqUrl,
@ -161,13 +166,13 @@ export async function createDemoBankWithdrawalUri(
async function confirmBankWithdrawalUri( async function confirmBankWithdrawalUri(
http: HttpRequestLibrary, http: HttpRequestLibrary,
bankBaseUrl: string, bankAccessApiBaseUrl: string,
bankUser: BankUser, bankUser: BankUser,
withdrawalId: string, withdrawalId: string,
): Promise<void> { ): Promise<void> {
const reqUrl = new URL( const reqUrl = new URL(
`accounts/${bankUser.username}/withdrawals/${withdrawalId}/confirm`, `accounts/${bankUser.username}/withdrawals/${withdrawalId}/confirm`,
bankBaseUrl, bankAccessApiBaseUrl,
).href; ).href;
const resp = await http.postJson( const resp = await http.postJson(
reqUrl, reqUrl,
@ -187,9 +192,9 @@ async function confirmBankWithdrawalUri(
async function registerRandomBankUser( async function registerRandomBankUser(
http: HttpRequestLibrary, http: HttpRequestLibrary,
bankBaseUrl: string, bankAccessApiBaseUrl: string,
): Promise<BankUser> { ): Promise<BankUser> {
const reqUrl = new URL("testing/register", bankBaseUrl).href; const reqUrl = new URL("testing/register", bankAccessApiBaseUrl).href;
const randId = makeId(8); const randId = makeId(8);
const bankUser: BankUser = { const bankUser: BankUser = {
// euFin doesn't allow resource names to have upper case letters. // euFin doesn't allow resource names to have upper case letters.
@ -377,7 +382,7 @@ export async function runIntegrationTest(
await withdrawTestBalance(ws, { await withdrawTestBalance(ws, {
amount: Amounts.stringify(withdrawAmountTwo), amount: Amounts.stringify(withdrawAmountTwo),
bankBaseUrl: args.bankBaseUrl, bankBaseUrl: args.bankBaseUrl,
bankAccessApiBaseUrl: args.bankBaseUrl, bankAccessApiBaseUrl: args.bankAccessApiBaseUrl,
exchangeBaseUrl: args.exchangeBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl,
}); });

View File

@ -376,6 +376,9 @@ export async function getBankWithdrawalInfo(
`withdrawal-operation/${uriResult.withdrawalOperationId}`, `withdrawal-operation/${uriResult.withdrawalOperationId}`,
uriResult.bankIntegrationApiBaseUrl, uriResult.bankIntegrationApiBaseUrl,
); );
logger.info(`bank withdrawal status URL: ${reqUrl.href}}`);
const resp = await http.get(reqUrl.href); const resp = await http.get(reqUrl.href);
const status = await readSuccessResponseJsonOrThrow( const status = await readSuccessResponseJsonOrThrow(
resp, resp,