test for manual withdrawal

This commit is contained in:
Florian Dold 2020-08-08 22:27:26 +05:30
parent e8c0a43dd3
commit 5fb9dae13c
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 188 additions and 21 deletions

View File

@ -69,8 +69,7 @@ export async function sh(
logName: string, logName: string,
command: string, command: string,
): Promise<string> { ): Promise<string> {
console.log("runing command"); console.log("runing command", command);
console.log(command);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const stdoutChunks: Buffer[] = []; const stdoutChunks: Buffer[] = [];
const proc = spawn(command, { const proc = spawn(command, {
@ -89,8 +88,8 @@ export async function sh(
flags: "a", flags: "a",
}); });
proc.stderr.pipe(stderrLog); proc.stderr.pipe(stderrLog);
proc.on("exit", (code) => { proc.on("exit", (code, signal) => {
console.log("child process exited"); console.log(`child process exited (${code} / ${signal})`);
if (code != 0) { if (code != 0) {
reject(Error(`Unexpected exit code ${code} for '${command}'`)); reject(Error(`Unexpected exit code ${code} for '${command}'`));
return; return;
@ -419,6 +418,13 @@ async function pingProc(
} }
} }
export interface ExchangeBankAccount {
accountName: string;
accountPassword: string;
accountPaytoUri: string;
wireGatewayApiBaseUrl: string;
}
export class BankService { export class BankService {
proc: ProcessWrapper | undefined; proc: ProcessWrapper | undefined;
@ -454,6 +460,18 @@ export class BankService {
); );
const cfgFilename = gc.testDir + "/bank.conf"; const cfgFilename = gc.testDir + "/bank.conf";
config.write(cfgFilename); config.write(cfgFilename);
await sh(
gc,
"taler-bank-manage_django",
`taler-bank-manage -c '${cfgFilename}' django migrate`,
);
await sh(
gc,
"taler-bank-manage_django",
`taler-bank-manage -c '${cfgFilename}' django provide_accounts`,
);
return new BankService(gc, bc, cfgFilename); return new BankService(gc, bc, cfgFilename);
} }
@ -463,6 +481,33 @@ export class BankService {
config.setString("bank", "suggested_exchange_payto", exchangePayto); config.setString("bank", "suggested_exchange_payto", exchangePayto);
} }
async createExchangeAccount(
accountName: string,
password: string,
): Promise<ExchangeBankAccount> {
await sh(
this.globalTestState,
"taler-bank-manage_django",
`taler-bank-manage -c '${this.configFile}' django add_bank_account ${accountName}`,
);
await sh(
this.globalTestState,
"taler-bank-manage_django",
`taler-bank-manage -c '${this.configFile}' django changepassword_unsafe ${accountName} ${password}`,
);
await sh(
this.globalTestState,
"taler-bank-manage_django",
`taler-bank-manage -c '${this.configFile}' django top_up ${accountName} ${this.bankConfig.currency}:100000`,
);
return {
accountName: accountName,
accountPassword: password,
accountPaytoUri: `payto://x-taler-bank/${accountName}`,
wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/taler-wire-gateway/${accountName}/`,
};
}
get port() { get port() {
return this.bankConfig.httpPort; return this.bankConfig.httpPort;
} }
@ -495,10 +540,12 @@ export class BankService {
} }
async createRandomBankUser(): Promise<BankUser> { async createRandomBankUser(): Promise<BankUser> {
const username =
"user-" + talerCrypto.encodeCrock(talerCrypto.getRandomBytes(10));
const bankUser: BankUser = { const bankUser: BankUser = {
username: username,
"user-" + talerCrypto.encodeCrock(talerCrypto.getRandomBytes(10)),
password: "pw-" + talerCrypto.encodeCrock(talerCrypto.getRandomBytes(10)), password: "pw-" + talerCrypto.encodeCrock(talerCrypto.getRandomBytes(10)),
accountPaytoUri: `payto://x-taler-bank/localhost/${username}`,
}; };
await this.createAccount(bankUser.username, bankUser.password); await this.createAccount(bankUser.username, bankUser.password);
return bankUser; return bankUser;
@ -521,6 +568,29 @@ export class BankService {
return codecForWithdrawalOperationInfo().decode(resp.data); 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( async confirmWithdrawalOperation(
bankUser: BankUser, bankUser: BankUser,
wopi: WithdrawalOperationInfo, wopi: WithdrawalOperationInfo,
@ -539,6 +609,7 @@ export class BankService {
export interface BankUser { export interface BankUser {
username: string; username: string;
password: string; password: string;
accountPaytoUri: string;
} }
export interface WithdrawalOperationInfo { export interface WithdrawalOperationInfo {
@ -600,6 +671,14 @@ export class ExchangeService implements ExchangeServiceInterface {
return new ExchangeService(gc, ec, cfgFilename, keyPair); return new ExchangeService(gc, ec, cfgFilename, keyPair);
} }
async runWirewatchOnce() {
await sh(
this.globalState,
"wirewatch-test",
`taler-exchange-wirewatch -c '${this.configFilename}' -t`,
);
}
static create(gc: GlobalTestState, e: ExchangeConfig) { static create(gc: GlobalTestState, e: ExchangeConfig) {
const config = new Configuration(); const config = new Configuration();
config.setString("taler", "currency", e.currency); config.setString("taler", "currency", e.currency);
@ -686,13 +765,10 @@ export class ExchangeService implements ExchangeServiceInterface {
return this.exchangeConfig.httpPort; return this.exchangeConfig.httpPort;
} }
async setupTestBankAccount( async addBankAccount(
bc: BankService,
localName: string, localName: string,
accountName: string, exchangeBankAccount: ExchangeBankAccount,
password: string,
): Promise<void> { ): Promise<void> {
await bc.createAccount(accountName, password);
const config = Configuration.load(this.configFilename); const config = Configuration.load(this.configFilename);
config.setString( config.setString(
`exchange-account-${localName}`, `exchange-account-${localName}`,
@ -702,22 +778,30 @@ export class ExchangeService implements ExchangeServiceInterface {
config.setString( config.setString(
`exchange-account-${localName}`, `exchange-account-${localName}`,
"payto_uri", "payto_uri",
`payto://x-taler-bank/localhost/${accountName}`, exchangeBankAccount.accountPaytoUri,
); );
config.setString(`exchange-account-${localName}`, "enable_credit", "yes"); config.setString(`exchange-account-${localName}`, "enable_credit", "yes");
config.setString(`exchange-account-${localName}`, "enable_debit", "yes"); config.setString(`exchange-account-${localName}`, "enable_debit", "yes");
config.setString( config.setString(
`exchange-account-${localName}`, `exchange-account-${localName}`,
"wire_gateway_url", "wire_gateway_url",
`http://localhost:${bc.port}/taler-wire-gateway/${accountName}/`, exchangeBankAccount.wireGatewayApiBaseUrl,
); );
config.setString( config.setString(
`exchange-account-${localName}`, `exchange-account-${localName}`,
"wire_gateway_auth_method", "wire_gateway_auth_method",
"basic", "basic",
); );
config.setString(`exchange-account-${localName}`, "username", accountName); config.setString(
config.setString(`exchange-account-${localName}`, "password", password); `exchange-account-${localName}`,
"username",
exchangeBankAccount.accountName,
);
config.setString(
`exchange-account-${localName}`,
"password",
exchangeBankAccount.accountPassword,
);
config.write(this.configFilename); config.write(this.configFilename);
} }

View File

@ -32,6 +32,7 @@ import {
setupDb, setupDb,
BankService, BankService,
defaultCoinConfig, defaultCoinConfig,
ExchangeBankAccount,
} from "./harness"; } from "./harness";
import { AmountString } from "taler-wallet-core/lib/types/talerTypes"; import { AmountString } from "taler-wallet-core/lib/types/talerTypes";
@ -39,6 +40,7 @@ export interface SimpleTestEnvironment {
commonDb: DbInfo; commonDb: DbInfo;
bank: BankService; bank: BankService;
exchange: ExchangeService; exchange: ExchangeService;
exchangeBankAccount: ExchangeBankAccount;
merchant: MerchantService; merchant: MerchantService;
wallet: WalletCli; wallet: WalletCli;
} }
@ -73,13 +75,15 @@ export async function createSimpleTestkudosEnvironment(
database: db.connStr, database: db.connStr,
}); });
bank.setSuggestedExchange(exchange, "payto://x-taler-bank/MyExchange"); const exchangeBankAccount = await bank.createExchangeAccount("MyExchange", "x");
exchange.addBankAccount("1", exchangeBankAccount);
bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
await bank.start(); await bank.start();
await bank.pingUntilAvailable(); await bank.pingUntilAvailable();
await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x");
exchange.addOfferedCoins(defaultCoinConfig); exchange.addOfferedCoins(defaultCoinConfig);
await exchange.start(); await exchange.start();
@ -112,6 +116,7 @@ export async function createSimpleTestkudosEnvironment(
merchant, merchant,
wallet, wallet,
bank, bank,
exchangeBankAccount,
}; };
} }

View File

@ -56,13 +56,15 @@ runTest(async (t: GlobalTestState) => {
database: db.connStr, database: db.connStr,
}); });
bank.setSuggestedExchange(exchange, "payto://x-taler-bank/MyExchange"); const exchangeBankAccount = await bank.createExchangeAccount("MyExchange", "x");
bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
await bank.start(); await bank.start();
await bank.pingUntilAvailable(); await bank.pingUntilAvailable();
await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x"); await exchange.addBankAccount("1", exchangeBankAccount);
exchange.addOfferedCoins(defaultCoinConfig); exchange.addOfferedCoins(defaultCoinConfig);
await exchange.start(); await exchange.start();

View File

@ -51,15 +51,17 @@ async function setupTest(t: GlobalTestState): Promise<{
database: db.connStr, database: db.connStr,
}); });
const exchangeBankAccount = await bank.createExchangeAccount("MyExchange", "x");
exchange.addOfferedCoins([coin_ct10, coin_u1]); exchange.addOfferedCoins([coin_ct10, coin_u1]);
bank.setSuggestedExchange(exchange, "payto://x-taler-bank/MyExchange"); bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
await bank.start(); await bank.start();
await bank.pingUntilAvailable(); await bank.pingUntilAvailable();
await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x"); await exchange.addBankAccount("1", exchangeBankAccount);
await exchange.start(); await exchange.start();
await exchange.pingUntilAvailable(); await exchange.pingUntilAvailable();

View File

@ -0,0 +1,74 @@
/*
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 } from "./harness";
import { createSimpleTestkudosEnvironment } from "./helpers";
import { walletTypes } from "taler-wallet-core";
import { CoreApiResponse } from "taler-wallet-core/lib/walletCoreApiHandler";
/**
* Run test for basic, bank-integrated withdrawal.
*/
runTest(async (t: GlobalTestState) => {
// Set up test environment
const { wallet, bank, exchange, exchangeBankAccount } = await createSimpleTestkudosEnvironment(t);
// Create a withdrawal operation
const user = await bank.createRandomBankUser();
let wresp: CoreApiResponse;
wresp = await wallet.apiRequest("addExchange", {
exchangeBaseUrl: exchange.baseUrl,
});
t.assertTrue(wresp.type === "response");
wresp = await wallet.apiRequest("acceptManualWithdrawal", {
exchangeBaseUrl: exchange.baseUrl,
amount: "TESTKUDOS:10",
});
t.assertTrue(wresp.type === "response");
const reservePub: string = (wresp.result as any).reservePub;
await bank.adminAddIncoming({
exchangeBankAccount,
amount: "TESTKUDOS:10",
debitAccountPayto: user.accountPaytoUri,
reservePub: reservePub,
});
await exchange.runWirewatchOnce();
await wallet.runUntilDone();
// Check balance
const balApiResp = await wallet.apiRequest("getBalances", {});
t.assertTrue(balApiResp.type === "response");
const balResp = walletTypes.codecForBalancesResponse().decode(balApiResp.result);
t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available)
await t.shutdown();
});