gnunet-svn
[Top][All Lists]
Advanced

[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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]