[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] branch master updated: integration testing tweaks, r
From: |
gnunet |
Subject: |
[taler-wallet-core] branch master updated: integration testing tweaks, rerun-payment-multiple scenario |
Date: |
Fri, 07 Aug 2020 19:43:42 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository wallet-core.
The following commit(s) were added to refs/heads/master by this push:
new 3321e40b integration testing tweaks, rerun-payment-multiple scenario
3321e40b is described below
commit 3321e40bffc5fe47133342d63f706a005a652273
Author: Florian Dold <florian.dold@gmail.com>
AuthorDate: Fri Aug 7 23:06:52 2020 +0530
integration testing tweaks, rerun-payment-multiple scenario
---
packages/taler-integrationtests/src/harness.ts | 160 +++++++++++++--------
packages/taler-integrationtests/src/helpers.ts | 24 ++--
...tiple.ts => scenario-rerun-payment-multiple.ts} | 82 ++++-------
.../src/test-payment-fault.ts | 14 +-
.../src/test-payment-multiple.ts | 47 +++---
packages/taler-wallet-core/src/util/talerconfig.ts | 53 ++++++-
6 files changed, 232 insertions(+), 148 deletions(-)
diff --git a/packages/taler-integrationtests/src/harness.ts
b/packages/taler-integrationtests/src/harness.ts
index 13487fb0..18a88d26 100644
--- a/packages/taler-integrationtests/src/harness.ts
+++ b/packages/taler-integrationtests/src/harness.ts
@@ -46,6 +46,7 @@ import {
PostOrderRequest,
PostOrderResponse,
} from "./merchantApiTypes";
+import { EddsaKeyPair } from "taler-wallet-core/lib/crypto/talerCrypto";
const exec = util.promisify(require("child_process").exec);
@@ -77,7 +78,6 @@ export async function sh(
shell: true,
});
proc.stdout.on("data", (x) => {
- console.log("child process got data chunk");
if (x instanceof Buffer) {
stdoutChunks.push(x);
} else {
@@ -363,8 +363,6 @@ export interface BankConfig {
currency: string;
httpPort: number;
database: string;
- suggestedExchange: string | undefined;
- suggestedExchangePayto: string | undefined;
allowRegistrations: boolean;
}
@@ -397,8 +395,48 @@ function setCoin(config: Configuration, c: CoinConfig) {
config.setString(s, "rsa_keysize", `${c.rsaKeySize}`);
}
+async function pingProc(
+ proc: ProcessWrapper | undefined,
+ url: string,
+ serviceName: string,
+): Promise<void> {
+ if (!proc || proc.proc.exitCode !== null) {
+ throw Error(`service process ${serviceName} not started, can't ping`);
+ }
+ while (true) {
+ try {
+ console.log(`pinging ${serviceName}`);
+ const resp = await axios.get(url);
+ console.log(`service ${serviceName} available`);
+ return;
+ } catch (e) {
+ console.log(`service ${serviceName} not ready:`, e.toString());
+ await delay(1000);
+ }
+ if (!proc || proc.proc.exitCode !== null) {
+ throw Error(`service process ${serviceName} stopped unexpectedly`);
+ }
+ }
+}
+
export class BankService {
proc: ProcessWrapper | undefined;
+
+ static fromExistingConfig(gc: GlobalTestState): BankService {
+ const cfgFilename = gc.testDir + "/bank.conf";
+ console.log("reading bank config from", cfgFilename);
+ const config = Configuration.load(cfgFilename);
+ const bc: BankConfig = {
+ allowRegistrations: config
+ .getYesNo("bank", "allow_registrations")
+ .required(),
+ currency: config.getString("taler", "currency").required(),
+ database: config.getString("bank", "database").required(),
+ httpPort: config.getNumber("bank", "http_port").required(),
+ };
+ return new BankService(gc, bc, cfgFilename);
+ }
+
static async create(
gc: GlobalTestState,
bc: BankConfig,
@@ -414,21 +452,17 @@ export class BankService {
"allow_registrations",
bc.allowRegistrations ? "yes" : "no",
);
- if (bc.suggestedExchange) {
- config.setString("bank", "suggested_exchange", bc.suggestedExchange);
- }
- if (bc.suggestedExchangePayto) {
- config.setString(
- "bank",
- "suggested_exchange_payto",
- bc.suggestedExchangePayto,
- );
- }
const cfgFilename = gc.testDir + "/bank.conf";
config.write(cfgFilename);
return new BankService(gc, bc, cfgFilename);
}
+ setSuggestedExchange(e: ExchangeService, exchangePayto: string) {
+ const config = Configuration.load(this.configFile);
+ config.setString("bank", "suggested_exchange", e.baseUrl);
+ config.setString("bank", "suggested_exchange_payto", exchangePayto);
+ }
+
get port() {
return this.bankConfig.httpPort;
}
@@ -449,16 +483,7 @@ export class BankService {
async pingUntilAvailable(): Promise<void> {
const url = `http://localhost:${this.bankConfig.httpPort}/config`;
- while (true) {
- try {
- console.log("pinging bank");
- const resp = await axios.get(url);
- return;
- } catch (e) {
- console.log("bank not ready:", e.toString());
- await delay(1000);
- }
- }
+ await pingProc(this.proc, url, "bank");
}
async createAccount(username: string, password: string): Promise<void> {
@@ -546,7 +571,6 @@ export interface ExchangeConfig {
roundUnit?: string;
httpPort: number;
database: string;
- coinConfig?: ((curr: string) => CoinConfig)[];
}
export interface ExchangeServiceInterface {
@@ -557,6 +581,27 @@ export interface ExchangeServiceInterface {
}
export class ExchangeService implements ExchangeServiceInterface {
+ static fromExistingConfig(gc: GlobalTestState, exchangeName: string) {
+ const cfgFilename = gc.testDir + `/exchange-${exchangeName}.conf`;
+ const config = Configuration.load(cfgFilename);
+ const ec: ExchangeConfig = {
+ currency: config.getString("taler", "currency").required(),
+ database: config.getString("exchangedb-postgres", "config").required(),
+ httpPort: config.getNumber("exchange", "port").required(),
+ name: exchangeName,
+ roundUnit: config.getString("taler", "currency_round_unit").required(),
+ };
+ const privFile = config
+ .getPath("exchange", "master_priv_file")
+ .required();
+ const eddsaPriv = fs.readFileSync(privFile);
+ const keyPair: EddsaKeyPair = {
+ eddsaPriv,
+ eddsaPub: talerCrypto.eddsaGetPublic(eddsaPriv),
+ };
+ return new ExchangeService(gc, ec, cfgFilename, keyPair);
+ }
+
static create(gc: GlobalTestState, e: ExchangeConfig) {
const config = new Configuration();
config.setString("taler", "currency", e.currency);
@@ -586,7 +631,6 @@ export class ExchangeService implements
ExchangeServiceInterface {
);
config.setString("exchange", "serve", "tcp");
config.setString("exchange", "port", `${e.httpPort}`);
- config.setString("exchange", "port", `${e.httpPort}`);
config.setString("exchange", "signkey_duration", "4 weeks");
config.setString("exchange", "legal_duraction", "2 years");
config.setString("exchange", "lookahead_sign", "32 weeks 1 day");
@@ -607,10 +651,6 @@ export class ExchangeService implements
ExchangeServiceInterface {
config.setString("exchangedb-postgres", "config", e.database);
- const coinConfig = e.coinConfig ?? defaultCoinConfig;
-
- coinConfig.forEach((cc) => setCoin(config, cc(e.currency)));
-
const exchangeMasterKey = talerCrypto.createEddsaKeyPair();
config.setString(
@@ -632,6 +672,14 @@ export class ExchangeService implements
ExchangeServiceInterface {
return new ExchangeService(gc, e, cfgFilename, exchangeMasterKey);
}
+ addOfferedCoins(offeredCoins: ((curr: string) => CoinConfig)[]) {
+ const config = Configuration.load(this.configFilename);
+ offeredCoins.forEach((cc) =>
+ setCoin(config, cc(this.exchangeConfig.currency)),
+ );
+ config.write(this.configFilename);
+ }
+
get masterPub() {
return talerCrypto.encodeCrock(this.keyPair.eddsaPub);
}
@@ -713,16 +761,7 @@ export class ExchangeService implements
ExchangeServiceInterface {
async pingUntilAvailable(): Promise<void> {
const url = `http://localhost:${this.exchangeConfig.httpPort}/keys`;
- while (true) {
- try {
- console.log("pinging exchange");
- const resp = await axios.get(url);
- return;
- } catch (e) {
- console.log("exchange not ready:", e.toString());
- await delay(1000);
- }
- }
+ await pingProc(this.exchangeHttpProc, url, `exchange (${this.name})`);
}
}
@@ -734,6 +773,18 @@ export interface MerchantConfig {
}
export class MerchantService {
+ static fromExistingConfig(gc: GlobalTestState, name: string) {
+ const cfgFilename = gc.testDir + `/merchant-${name}.conf`;
+ const config = Configuration.load(cfgFilename);
+ const mc: MerchantConfig = {
+ currency: config.getString("taler", "currency").required(),
+ database: config.getString("merchantdb-postgres", "config").required(),
+ httpPort: config.getNumber("merchant", "port").required(),
+ name,
+ };
+ return new MerchantService(gc, mc, cfgFilename);
+ }
+
proc: ProcessWrapper | undefined;
constructor(
@@ -844,16 +895,7 @@ export class MerchantService {
async pingUntilAvailable(): Promise<void> {
const url = `http://localhost:${this.merchantConfig.httpPort}/config`;
- while (true) {
- try {
- console.log("pinging merchant");
- const resp = await axios.get(url);
- return;
- } catch (e) {
- console.log("merchant not ready", e.toString());
- await delay(1000);
- }
- }
+ await pingProc(this.proc, url, `merchant (${this.merchantConfig.name})`);
}
}
@@ -903,16 +945,13 @@ function updateCurrentSymlink(testDir: string): void {
}
}
-export function runTest(testMain: (gc: GlobalTestState) => Promise<void>) {
+export function runTestWithState(
+ gc: GlobalTestState,
+ testMain: (t: GlobalTestState) => Promise<void>,
+) {
const main = async () => {
- let gc: GlobalTestState | undefined;
let ret = 0;
try {
- gc = new GlobalTestState({
- testDir: fs.mkdtempSync(
- path.join(os.tmpdir(), "taler-integrationtest-"),
- ),
- });
updateCurrentSymlink(gc.testDir);
console.log("running test in directory", gc.testDir);
await testMain(gc);
@@ -936,6 +975,15 @@ export function runTest(testMain: (gc: GlobalTestState) =>
Promise<void>) {
main();
}
+export function runTest(
+ testMain: (gc: GlobalTestState) => Promise<void>,
+): void {
+ const gc = new GlobalTestState({
+ testDir: fs.mkdtempSync(path.join(os.tmpdir(), "taler-integrationtest-")),
+ });
+ runTestWithState(gc, testMain);
+}
+
function shellWrap(s: string) {
return "'" + s.replace("\\", "\\\\").replace("'", "\\'") + "'";
}
diff --git a/packages/taler-integrationtests/src/helpers.ts
b/packages/taler-integrationtests/src/helpers.ts
index 01362370..9afb6642 100644
--- a/packages/taler-integrationtests/src/helpers.ts
+++ b/packages/taler-integrationtests/src/helpers.ts
@@ -31,6 +31,7 @@ import {
MerchantService,
setupDb,
BankService,
+ defaultCoinConfig,
} from "./harness";
import { AmountString } from "taler-wallet-core/lib/types/talerTypes";
@@ -56,14 +57,8 @@ export async function createSimpleTestkudosEnvironment(
currency: "TESTKUDOS",
database: db.connStr,
httpPort: 8082,
- suggestedExchange: "http://localhost:8081/",
- suggestedExchangePayto: "payto://x-taler-bank/MyExchange",
});
- await bank.start();
-
- await bank.pingUntilAvailable();
-
const exchange = ExchangeService.create(t, {
name: "testexchange-1",
currency: "TESTKUDOS",
@@ -71,11 +66,6 @@ export async function createSimpleTestkudosEnvironment(
database: db.connStr,
});
- await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x");
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
const merchant = await MerchantService.create(t, {
name: "testmerchant-1",
currency: "TESTKUDOS",
@@ -83,6 +73,18 @@ export async function createSimpleTestkudosEnvironment(
database: db.connStr,
});
+ bank.setSuggestedExchange(exchange, "payto://x-taler-bank/MyExchange");
+
+ await bank.start();
+
+ await bank.pingUntilAvailable();
+
+ await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x");
+ exchange.addOfferedCoins(defaultCoinConfig);
+
+ await exchange.start();
+ await exchange.pingUntilAvailable();
+
merchant.addExchange(exchange);
await merchant.start();
diff --git a/packages/taler-integrationtests/src/test-payment-multiple.ts
b/packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts
similarity index 59%
copy from packages/taler-integrationtests/src/test-payment-multiple.ts
copy to packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts
index 2914b718..967b5391 100644
--- a/packages/taler-integrationtests/src/test-payment-multiple.ts
+++ b/packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts
@@ -18,79 +18,47 @@
* Imports.
*/
import {
- runTest,
GlobalTestState,
- setupDb,
BankService,
ExchangeService,
MerchantService,
WalletCli,
- coin_ct10,
- coin_u1,
+ runTestWithState,
} from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
+import { withdrawViaBank } from "./helpers";
+import fs from "fs";
+
+let existingTestDir =
+ process.env["TALER_TEST_OLD_DIR"] ?? "/tmp/taler-integrationtest-current";
+
+if (!fs.existsSync(existingTestDir)) {
+ throw Error("old test dir not found");
+}
+
+existingTestDir = fs.realpathSync(existingTestDir);
+
+const prevT = new GlobalTestState({
+ testDir: existingTestDir,
+});
/**
* Run test.
- *
- * This test uses a very sub-optimal denomination structure.
*/
-runTest(async (t: GlobalTestState) => {
+runTestWithState(prevT, 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,
- suggestedExchange: "http://localhost:8081/",
- suggestedExchangePayto: "payto://x-taler-bank/MyExchange",
- });
+ const bank = BankService.fromExistingConfig(t);
+ const exchange = ExchangeService.fromExistingConfig(t, "testexchange-1");
+ const merchant = MerchantService.fromExistingConfig(t, "testmerchant-1");
await bank.start();
-
- await bank.pingUntilAvailable();
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- coinConfig: [coin_ct10, coin_u1],
- });
-
- await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x");
-
await exchange.start();
- await exchange.pingUntilAvailable();
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- 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!");
+ await Promise.all([
+ bank.pingUntilAvailable(),
+ merchant.pingUntilAvailable(),
+ exchange.pingUntilAvailable(),
+ ]);
const wallet = new WalletCli(t);
diff --git a/packages/taler-integrationtests/src/test-payment-fault.ts
b/packages/taler-integrationtests/src/test-payment-fault.ts
index 2e044888..f0b17a7f 100644
--- a/packages/taler-integrationtests/src/test-payment-fault.ts
+++ b/packages/taler-integrationtests/src/test-payment-fault.ts
@@ -29,6 +29,7 @@ import {
setupDb,
BankService,
WalletCli,
+ defaultCoinConfig,
} from "./harness";
import { FaultInjectedExchangeService, FaultInjectionRequestContext,
FaultInjectionResponseContext } from "./faultInjection";
import { CoreApiResponse } from "taler-wallet-core/lib/walletCoreApiHandler";
@@ -46,14 +47,8 @@ runTest(async (t: GlobalTestState) => {
currency: "TESTKUDOS",
database: db.connStr,
httpPort: 8082,
- suggestedExchange: "http://localhost:8091/",
- suggestedExchangePayto: "payto://x-taler-bank/MyExchange",
});
- await bank.start();
-
- await bank.pingUntilAvailable();
-
const exchange = ExchangeService.create(t, {
name: "testexchange-1",
currency: "TESTKUDOS",
@@ -61,7 +56,14 @@ runTest(async (t: GlobalTestState) => {
database: db.connStr,
});
+ bank.setSuggestedExchange(exchange, "payto://x-taler-bank/MyExchange");
+
+ await bank.start();
+
+ await bank.pingUntilAvailable();
+
await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x");
+ exchange.addOfferedCoins(defaultCoinConfig);
await exchange.start();
await exchange.pingUntilAvailable();
diff --git a/packages/taler-integrationtests/src/test-payment-multiple.ts
b/packages/taler-integrationtests/src/test-payment-multiple.ts
index 2914b718..84aab4c8 100644
--- a/packages/taler-integrationtests/src/test-payment-multiple.ts
+++ b/packages/taler-integrationtests/src/test-payment-multiple.ts
@@ -28,16 +28,13 @@ import {
coin_ct10,
coin_u1,
} from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-
-/**
- * Run test.
- *
- * This test uses a very sub-optimal denomination structure.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
+import { withdrawViaBank } from "./helpers";
+async function setupTest(t: GlobalTestState): Promise<{
+ merchant: MerchantService,
+ exchange: ExchangeService,
+ bank: BankService,
+}> {
const db = await setupDb(t);
const bank = await BankService.create(t, {
@@ -45,22 +42,23 @@ runTest(async (t: GlobalTestState) => {
currency: "TESTKUDOS",
database: db.connStr,
httpPort: 8082,
- suggestedExchange: "http://localhost:8081/",
- suggestedExchangePayto: "payto://x-taler-bank/MyExchange",
});
- await bank.start();
-
- await bank.pingUntilAvailable();
-
const exchange = ExchangeService.create(t, {
name: "testexchange-1",
currency: "TESTKUDOS",
httpPort: 8081,
database: db.connStr,
- coinConfig: [coin_ct10, coin_u1],
});
+ exchange.addOfferedCoins([coin_ct10, coin_u1]);
+
+ bank.setSuggestedExchange(exchange, "payto://x-taler-bank/MyExchange");
+
+ await bank.start();
+
+ await bank.pingUntilAvailable();
+
await exchange.setupTestBankAccount(bank, "1", "MyExchange", "x");
await exchange.start();
@@ -92,6 +90,23 @@ runTest(async (t: GlobalTestState) => {
console.log("setup done!");
+ return {
+ merchant,
+ bank,
+ exchange,
+ }
+}
+
+/**
+ * Run test.
+ *
+ * This test uses a very sub-optimal denomination structure.
+ */
+runTest(async (t: GlobalTestState) => {
+ // Set up test environment
+
+ const { merchant, bank, exchange } = await setupTest(t);
+
const wallet = new WalletCli(t);
// Withdraw digital cash into the wallet.
diff --git a/packages/taler-wallet-core/src/util/talerconfig.ts
b/packages/taler-wallet-core/src/util/talerconfig.ts
index 8c740e1e..e9a67287 100644
--- a/packages/taler-wallet-core/src/util/talerconfig.ts
+++ b/packages/taler-wallet-core/src/util/talerconfig.ts
@@ -26,7 +26,6 @@
import { AmountJson } from "./amounts";
import * as Amounts from "./amounts";
import fs from "fs";
-import { acceptExchangeTermsOfService } from "../operations/exchanges";
export class ConfigError extends Error {
constructor(message: string) {
@@ -56,6 +55,26 @@ export class ConfigValue<T> {
}
return this.converter(this.val);
}
+
+ orUndefined(): T | undefined {
+ if (this.val !== undefined) {
+ return this.converter(this.val);
+ } else {
+ return undefined;
+ }
+ }
+
+ orDefault(v: T): T | undefined {
+ if (this.val !== undefined) {
+ return this.converter(this.val);
+ } else {
+ return v;
+ }
+ }
+
+ isDefined(): boolean {
+ return this.val !== undefined;
+ }
}
/**
@@ -197,7 +216,7 @@ export class Configuration {
getString(section: string, option: string): ConfigValue<string> {
const secNorm = section.toUpperCase();
const optNorm = option.toUpperCase();
- const val = (this.sectionMap[section] ?? {})[optNorm];
+ const val = (this.sectionMap[secNorm] ?? {})[optNorm];
return new ConfigValue(secNorm, optNorm, val, (x) => x);
}
@@ -210,6 +229,36 @@ export class Configuration {
);
}
+ getYesNo(section: string, option: string): ConfigValue<boolean> {
+ const secNorm = section.toUpperCase();
+ const optNorm = option.toUpperCase();
+ const val = (this.sectionMap[secNorm] ?? {})[optNorm];
+ const convert = (x: string): boolean => {
+ x = x.toLowerCase();
+ if (x === "yes") {
+ return true;
+ } else if (x === "no") {
+ return false;
+ }
+ throw Error(`invalid config value for [${secNorm}]/${optNorm}, expected
yes/no`);
+ };
+ return new ConfigValue(secNorm, optNorm, val, convert);
+ }
+
+ getNumber(section: string, option: string): ConfigValue<number> {
+ const secNorm = section.toUpperCase();
+ const optNorm = option.toUpperCase();
+ const val = (this.sectionMap[secNorm] ?? {})[optNorm];
+ const convert = (x: string): number => {
+ try {
+ return Number.parseInt(x, 10);
+ } catch (e) {
+ throw Error(`invalid config value for [${secNorm}]/${optNorm},
expected number`);
+ }
+ };
+ return new ConfigValue(secNorm, optNorm, val, convert);
+ }
+
lookupVariable(x: string, depth: number = 0): string | undefined {
// We loop up options in PATHS in upper case, as option names
// are case insensitive
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-wallet-core] branch master updated: integration testing tweaks, rerun-payment-multiple scenario,
gnunet <=