aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-integrationtests/src/harness.ts235
-rw-r--r--packages/taler-integrationtests/src/helpers.ts9
-rw-r--r--packages/taler-integrationtests/src/test-bank-api.ts122
-rw-r--r--packages/taler-integrationtests/src/test-exchange-management.ts6
-rw-r--r--packages/taler-integrationtests/src/test-payment-fault.ts8
-rw-r--r--packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts8
-rw-r--r--packages/taler-integrationtests/src/test-withdrawal-manual.ts6
7 files changed, 299 insertions, 95 deletions
diff --git a/packages/taler-integrationtests/src/harness.ts b/packages/taler-integrationtests/src/harness.ts
index 77914af66..6897b4b5c 100644
--- a/packages/taler-integrationtests/src/harness.ts
+++ b/packages/taler-integrationtests/src/harness.ts
@@ -66,9 +66,10 @@ import {
TransactionsResponse,
codecForTransactionsResponse,
WithdrawTestBalanceRequest,
+ AmountString,
} from "taler-wallet-core";
import { URL } from "url";
-import axios from "axios";
+import axios, { AxiosError } from "axios";
import {
codecForMerchantOrderPrivateStatusResponse,
codecForPostOrderResponse,
@@ -276,6 +277,21 @@ export class GlobalTestState {
);
}
+ async assertThrowsAsync(block: () => Promise<void>): Promise<any> {
+ try {
+ await block();
+ } catch (e) {
+ return e;
+ }
+ throw Error(
+ `expected exception to be thrown, but block finished without throwing`,
+ );
+ }
+
+ assertAxiosError(e: any): asserts e is AxiosError {
+ return e.isAxiosError;
+ }
+
assertTrue(b: boolean): asserts b {
if (!b) {
throw Error("test assertion failed");
@@ -412,6 +428,7 @@ export interface BankConfig {
httpPort: number;
database: string;
allowRegistrations: boolean;
+ maxDebt?: string;
}
function setPaths(config: Configuration, home: string) {
@@ -474,7 +491,136 @@ export interface ExchangeBankAccount {
wireGatewayApiBaseUrl: string;
}
-export class BankService {
+export interface BankServiceInterface {
+ readonly baseUrl: string;
+ readonly port: number;
+}
+
+export enum CreditDebitIndicator {
+ Credit = "credit",
+ Debit = "debit",
+}
+
+export interface BankAccountBalanceResponse {
+ balance_amount: AmountString;
+ credit_debit_indicator: CreditDebitIndicator;
+}
+
+export namespace BankAccessApi {
+ export async function getAccountBalance(
+ bank: BankServiceInterface,
+ bankUser: BankUser,
+ ): Promise<BankAccountBalanceResponse> {
+ const url = new URL(
+ `accounts/${bankUser.username}/balance`,
+ bank.baseUrl,
+ );
+ const resp = await axios.get(
+ url.href,
+ {
+ auth: bankUser,
+ },
+ );
+ return resp.data;
+ }
+
+ export async function createWithdrawalOperation(
+ bank: BankServiceInterface,
+ bankUser: BankUser,
+ amount: string,
+ ): Promise<WithdrawalOperationInfo> {
+ const url = new URL(
+ `accounts/${bankUser.username}/withdrawals`,
+ bank.baseUrl,
+ );
+ const resp = await axios.post(
+ url.href,
+ {
+ amount,
+ },
+ {
+ auth: bankUser,
+ },
+ );
+ return codecForWithdrawalOperationInfo().decode(resp.data);
+ }
+}
+
+export namespace BankApi {
+ export async function registerAccount(
+ bank: BankServiceInterface,
+ username: string,
+ password: string,
+ ): Promise<BankUser> {
+ const url = new URL("testing/register", bank.baseUrl);
+ await axios.post(url.href, {
+ username,
+ password,
+ });
+ return {
+ password,
+ username,
+ accountPaytoUri: `payto://x-taler-bank/localhost/${username}`,
+ };
+ }
+
+ export async function createRandomBankUser(
+ bank: BankServiceInterface,
+ ): Promise<BankUser> {
+ const username = "user-" + encodeCrock(getRandomBytes(10));
+ const password = "pw-" + encodeCrock(getRandomBytes(10));
+ return await registerAccount(bank, username, password);
+ }
+
+ export async function adminAddIncoming(
+ bank: BankServiceInterface,
+ params: {
+ exchangeBankAccount: ExchangeBankAccount;
+ amount: string;
+ reservePub: string;
+ debitAccountPayto: string;
+ },
+ ) {
+ const url = new URL(
+ `taler-wire-gateway/${params.exchangeBankAccount.accountName}/admin/add-incoming`,
+ bank.baseUrl,
+ );
+ await axios.post(
+ url.href,
+ {
+ amount: params.amount,
+ reserve_pub: params.reservePub,
+ debit_account: params.debitAccountPayto,
+ },
+ {
+ auth: {
+ username: params.exchangeBankAccount.accountName,
+ password: params.exchangeBankAccount.accountPassword,
+ },
+ },
+ );
+ }
+
+ export async function confirmWithdrawalOperation(
+ bank: BankServiceInterface,
+ bankUser: BankUser,
+ wopi: WithdrawalOperationInfo,
+ ): Promise<void> {
+ const url = new URL(
+ `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/confirm`,
+ bank.baseUrl,
+ );
+ await axios.post(
+ url.href,
+ {},
+ {
+ auth: bankUser,
+ },
+ );
+ }
+}
+
+export class BankService implements BankServiceInterface {
proc: ProcessWrapper | undefined;
static fromExistingConfig(gc: GlobalTestState): BankService {
@@ -502,6 +648,7 @@ export class BankService {
config.setString("bank", "database", bc.database);
config.setString("bank", "http_port", `${bc.httpPort}`);
config.setString("bank", "max_debt_bank", `${bc.currency}:999999`);
+ config.setString("bank", "max_debt", bc.maxDebt ?? `${bc.currency}:100`);
config.setString(
"bank",
"allow_registrations",
@@ -583,79 +730,6 @@ export class BankService {
const url = `http://localhost:${this.bankConfig.httpPort}/config`;
await pingProc(this.proc, url, "bank");
}
-
- async createAccount(username: string, password: string): Promise<void> {
- const url = `http://localhost:${this.bankConfig.httpPort}/testing/register`;
- await axios.post(url, {
- username,
- password,
- });
- }
-
- async createRandomBankUser(): Promise<BankUser> {
- const username = "user-" + encodeCrock(getRandomBytes(10));
- const bankUser: BankUser = {
- username,
- password: "pw-" + encodeCrock(getRandomBytes(10)),
- accountPaytoUri: `payto://x-taler-bank/localhost/${username}`,
- };
- await this.createAccount(bankUser.username, bankUser.password);
- return bankUser;
- }
-
- async createWithdrawalOperation(
- bankUser: BankUser,
- amount: string,
- ): Promise<WithdrawalOperationInfo> {
- const url = `http://localhost:${this.bankConfig.httpPort}/accounts/${bankUser.username}/withdrawals`;
- const resp = await axios.post(
- url,
- {
- amount,
- },
- {
- auth: bankUser,
- },
- );
- return codecForWithdrawalOperationInfo().decode(resp.data);
- }
-
- async adminAddIncoming(params: {
- exchangeBankAccount: ExchangeBankAccount;
- amount: string;
- reservePub: string;
- debitAccountPayto: string;
- }) {
- const url = `http://localhost:${this.bankConfig.httpPort}/taler-wire-gateway/${params.exchangeBankAccount.accountName}/admin/add-incoming`;
- await axios.post(
- url,
- {
- amount: params.amount,
- reserve_pub: params.reservePub,
- debit_account: params.debitAccountPayto,
- },
- {
- auth: {
- username: params.exchangeBankAccount.accountName,
- password: params.exchangeBankAccount.accountPassword,
- },
- },
- );
- }
-
- async confirmWithdrawalOperation(
- bankUser: BankUser,
- wopi: WithdrawalOperationInfo,
- ): Promise<void> {
- const url = `http://localhost:${this.bankConfig.httpPort}/accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/confirm`;
- await axios.post(
- url,
- {},
- {
- auth: bankUser,
- },
- );
- }
}
export interface BankUser {
@@ -945,11 +1019,12 @@ export namespace MerchantPrivateApi {
export async function giveRefund(
merchantService: MerchantServiceInterface,
r: {
- instance: string;
- orderId: string;
- amount: string;
- justification: string;
- }): Promise<{ talerRefundUri: string }> {
+ instance: string;
+ orderId: string;
+ amount: string;
+ justification: string;
+ },
+ ): Promise<{ talerRefundUri: string }> {
const reqUrl = new URL(
`private/orders/${r.orderId}/refund`,
merchantService.makeInstanceBaseUrl(r.instance),
diff --git a/packages/taler-integrationtests/src/helpers.ts b/packages/taler-integrationtests/src/helpers.ts
index 86f530e09..d33aaff4e 100644
--- a/packages/taler-integrationtests/src/helpers.ts
+++ b/packages/taler-integrationtests/src/helpers.ts
@@ -34,6 +34,8 @@ import {
defaultCoinConfig,
ExchangeBankAccount,
MerchantServiceInterface,
+ BankApi,
+ BankAccessApi,
} from "./harness";
import { AmountString } from "taler-wallet-core/lib/types/talerTypes";
import { FaultInjectedMerchantService } from "./faultInjection";
@@ -230,8 +232,8 @@ export async function withdrawViaBank(
): Promise<void> {
const { wallet, bank, exchange, amount } = p;
- const user = await bank.createRandomBankUser();
- const wop = await bank.createWithdrawalOperation(user, amount);
+ const user = await BankApi.createRandomBankUser(bank);
+ const wop = await BankAccessApi.createWithdrawalOperation(bank, user, amount);
// Hand it to the wallet
@@ -244,7 +246,7 @@ export async function withdrawViaBank(
// Confirm it
- await bank.confirmWithdrawalOperation(user, wop);
+ await BankApi.confirmWithdrawalOperation(bank, user, wop);
// Withdraw
@@ -260,3 +262,4 @@ export async function withdrawViaBank(
const balApiResp = await wallet.apiRequest("getBalances", {});
t.assertTrue(balApiResp.type === "response");
}
+
diff --git a/packages/taler-integrationtests/src/test-bank-api.ts b/packages/taler-integrationtests/src/test-bank-api.ts
new file mode 100644
index 000000000..1c233a55c
--- /dev/null
+++ b/packages/taler-integrationtests/src/test-bank-api.ts
@@ -0,0 +1,122 @@
+/*
+ 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 { runTest, GlobalTestState, MerchantPrivateApi, WalletCli, defaultCoinConfig, ExchangeService, setupDb, BankService, MerchantService, BankApi, BankUser, BankAccessApi, CreditDebitIndicator } from "./harness";
+import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
+import { createEddsaKeyPair, encodeCrock } from "taler-wallet-core";
+
+/**
+ * Run test for basic, bank-integrated withdrawal.
+ */
+runTest(async (t: GlobalTestState) => {
+ // Set up test environment
+
+ const db = await setupDb(t);
+
+ const bank = await BankService.create(t, {
+ allowRegistrations: true,
+ currency: "TESTKUDOS",
+ database: db.connStr,
+ httpPort: 8082,
+ });
+
+ 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 exchangeBankAccount = await bank.createExchangeAccount(
+ "MyExchange",
+ "x",
+ );
+ exchange.addBankAccount("1", exchangeBankAccount);
+
+ bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
+
+ 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.addInstance({
+ id: "minst1",
+ name: "minst1",
+ paytoUris: ["payto://x-taler-bank/minst1"],
+ });
+
+ await merchant.addInstance({
+ id: "default",
+ name: "Default Instance",
+ paytoUris: [`payto://x-taler-bank/merchant-default`],
+ });
+
+ console.log("setup done!");
+
+ const wallet = new WalletCli(t);
+
+ const bankUser = await BankApi.registerAccount(bank, "user1", "pw1");
+
+ // Make sure that registering twice results in a 409 Conflict
+ {
+ const e = await t.assertThrowsAsync(async () => {
+ await BankApi.registerAccount(bank, "user1", "pw1");
+ });
+ t.assertAxiosError(e);
+ t.assertTrue(e.response?.status === 409);
+ }
+
+ let bal = await BankAccessApi.getAccountBalance(bank, bankUser);
+
+ console.log(bal);
+
+ // Check that we got the sign-up bonus.
+ t.assertAmountEquals(bal.balance_amount, "TESTKUDOS:100");
+ t.assertTrue(bal.credit_debit_indicator === CreditDebitIndicator.Credit);
+
+ const res = createEddsaKeyPair();
+
+ await BankApi.adminAddIncoming(bank, {
+ amount: "TESTKUDOS:115",
+ debitAccountPayto: bankUser.accountPaytoUri,
+ exchangeBankAccount: exchangeBankAccount,
+ reservePub: encodeCrock(res.eddsaPub),
+ });
+
+ bal = await BankAccessApi.getAccountBalance(bank, bankUser);
+ t.assertAmountEquals(bal.balance_amount, "TESTKUDOS:15");
+ t.assertTrue(bal.credit_debit_indicator === CreditDebitIndicator.Debit);
+});
diff --git a/packages/taler-integrationtests/src/test-exchange-management.ts b/packages/taler-integrationtests/src/test-exchange-management.ts
index 9199c183e..4ca86b341 100644
--- a/packages/taler-integrationtests/src/test-exchange-management.ts
+++ b/packages/taler-integrationtests/src/test-exchange-management.ts
@@ -26,6 +26,8 @@ import {
ExchangeService,
MerchantService,
defaultCoinConfig,
+ BankApi,
+ BankAccessApi,
} from "./harness";
import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
import {
@@ -231,8 +233,8 @@ runTest(async (t: GlobalTestState) => {
// Create withdrawal operation
- const user = await bank.createRandomBankUser();
- const wop = await bank.createWithdrawalOperation(user, "TESTKUDOS:10");
+ const user = await BankApi.createRandomBankUser(bank);
+ const wop = await BankAccessApi.createWithdrawalOperation(bank, user, "TESTKUDOS:10");
// Hand it to the wallet
diff --git a/packages/taler-integrationtests/src/test-payment-fault.ts b/packages/taler-integrationtests/src/test-payment-fault.ts
index 8065b430c..a7f44706b 100644
--- a/packages/taler-integrationtests/src/test-payment-fault.ts
+++ b/packages/taler-integrationtests/src/test-payment-fault.ts
@@ -31,6 +31,8 @@ import {
WalletCli,
defaultCoinConfig,
MerchantPrivateApi,
+ BankApi,
+ BankAccessApi,
} from "./harness";
import {
FaultInjectedExchangeService,
@@ -114,8 +116,8 @@ runTest(async (t: GlobalTestState) => {
// Create withdrawal operation
- const user = await bank.createRandomBankUser();
- const wop = await bank.createWithdrawalOperation(user, "TESTKUDOS:20");
+ const user = await BankApi.createRandomBankUser(bank);
+ const wop = await BankAccessApi.createWithdrawalOperation(bank, user, "TESTKUDOS:20");
// Hand it to the wallet
@@ -128,7 +130,7 @@ runTest(async (t: GlobalTestState) => {
// Confirm it
- await bank.confirmWithdrawalOperation(user, wop);
+ await BankApi.confirmWithdrawalOperation(bank, user, wop);
// Withdraw
diff --git a/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts b/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts
index 46ccdaaed..f2593c802 100644
--- a/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts
+++ b/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts
@@ -17,7 +17,7 @@
/**
* Imports.
*/
-import { runTest, GlobalTestState } from "./harness";
+import { runTest, GlobalTestState, BankApi, BankAccessApi } from "./harness";
import { createSimpleTestkudosEnvironment } from "./helpers";
import { codecForBalancesResponse } from "taler-wallet-core";
@@ -31,8 +31,8 @@ runTest(async (t: GlobalTestState) => {
// Create a withdrawal operation
- const user = await bank.createRandomBankUser();
- const wop = await bank.createWithdrawalOperation(user, "TESTKUDOS:10");
+ const user = await BankApi.createRandomBankUser(bank);
+ const wop = await BankAccessApi.createWithdrawalOperation(bank, user, "TESTKUDOS:10");
// Hand it to the wallet
@@ -45,7 +45,7 @@ runTest(async (t: GlobalTestState) => {
// Confirm it
- await bank.confirmWithdrawalOperation(user, wop);
+ await BankApi.confirmWithdrawalOperation(bank, user, wop);
// Withdraw
diff --git a/packages/taler-integrationtests/src/test-withdrawal-manual.ts b/packages/taler-integrationtests/src/test-withdrawal-manual.ts
index 0d09c3e5c..ee844d9f0 100644
--- a/packages/taler-integrationtests/src/test-withdrawal-manual.ts
+++ b/packages/taler-integrationtests/src/test-withdrawal-manual.ts
@@ -17,7 +17,7 @@
/**
* Imports.
*/
-import { runTest, GlobalTestState } from "./harness";
+import { runTest, GlobalTestState, BankApi } from "./harness";
import { createSimpleTestkudosEnvironment } from "./helpers";
import { CoreApiResponse } from "taler-wallet-core/lib/walletCoreApiHandler";
import { codecForBalancesResponse } from "taler-wallet-core";
@@ -37,7 +37,7 @@ runTest(async (t: GlobalTestState) => {
// Create a withdrawal operation
- const user = await bank.createRandomBankUser();
+ const user = await BankApi.createRandomBankUser(bank);
let wresp: CoreApiResponse;
@@ -56,7 +56,7 @@ runTest(async (t: GlobalTestState) => {
const reservePub: string = (wresp.result as any).reservePub;
- await bank.adminAddIncoming({
+ await BankApi.adminAddIncoming(bank, {
exchangeBankAccount,
amount: "TESTKUDOS:10",
debitAccountPayto: user.accountPaytoUri,