gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated (ef5962cd3 -> ec3ae6f5e)


From: gnunet
Subject: [taler-wallet-core] branch master updated (ef5962cd3 -> ec3ae6f5e)
Date: Wed, 23 Aug 2023 17:04:22 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch master
in repository wallet-core.

    from ef5962cd3 fix #7882
     new 7fbe28e64 harness: reusable test env
     new ec3ae6f5e harness: parallelize service startup

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/taler-harness/src/harness/harness.ts      | 115 +++++++++----
 packages/taler-harness/src/harness/helpers.ts      | 179 +++++++++++++++------
 .../src/integrationtests/testrunner.ts             |   4 +-
 packages/taler-util/src/logging.ts                 |   4 +-
 4 files changed, 222 insertions(+), 80 deletions(-)

diff --git a/packages/taler-harness/src/harness/harness.ts 
b/packages/taler-harness/src/harness/harness.ts
index 4e2bae8f2..8f1f3f452 100644
--- a/packages/taler-harness/src/harness/harness.ts
+++ b/packages/taler-harness/src/harness/harness.ts
@@ -489,6 +489,7 @@ export interface BankConfig {
   database: string;
   allowRegistrations: boolean;
   maxDebt?: string;
+  overrideTestDir?: string;
 }
 
 export interface FakeBankConfig {
@@ -534,6 +535,14 @@ function setCoin(config: Configuration, c: CoinConfig) {
   }
 }
 
+function backoffStart(): number {
+  return 10;
+}
+
+function backoffIncrement(n: number): number {
+  return Math.min(Math.floor(n * 1.5), 1000);
+}
+
 /**
  * Send an HTTP request until it succeeds or the process dies.
  */
@@ -545,6 +554,7 @@ export async function pingProc(
   if (!proc || proc.proc.exitCode !== null) {
     throw Error(`service process ${serviceName} not started, can't ping`);
   }
+  let nextDelay = backoffStart();
   while (true) {
     try {
       logger.trace(`pinging ${serviceName} at ${url}`);
@@ -553,8 +563,9 @@ export async function pingProc(
       return;
     } catch (e: any) {
       logger.warn(`service ${serviceName} not ready:`, e.toString());
-      //console.log(e);
-      await delayMs(1000);
+      logger.info(`waiting ${nextDelay}ms`);
+      await delayMs(nextDelay);
+      nextDelay = backoffIncrement(nextDelay);
     }
     if (!proc || proc.proc.exitCode != null || proc.proc.signalCode != null) {
       throw Error(`service process ${serviceName} stopped unexpectedly`);
@@ -875,7 +886,7 @@ export class FakebankService
 
   /**
    * Create a new fakebank service handle.
-   * 
+   *
    * First generates the configuration for the fakebank and
    * then creates a fakebank handle, but doesn't start the fakebank
    * service yet.
@@ -885,19 +896,38 @@ export class FakebankService
     bc: BankConfig,
   ): Promise<FakebankService> {
     const config = new Configuration();
-    setTalerPaths(config, gc.testDir + "/talerhome");
+    const testDir = bc.overrideTestDir ?? gc.testDir;
+    setTalerPaths(config, testDir + "/talerhome");
     config.setString("taler", "currency", bc.currency);
     config.setString("bank", "http_port", `${bc.httpPort}`);
     config.setString("bank", "serve", "http");
     config.setString("bank", "max_debt_bank", `${bc.currency}:999999`);
     config.setString("bank", "max_debt", bc.maxDebt ?? `${bc.currency}:100`);
     config.setString("bank", "ram_limit", `${1024}`);
-    const cfgFilename = gc.testDir + "/bank.conf";
+    const cfgFilename = testDir + "/bank.conf";
     config.write(cfgFilename);
 
     return new FakebankService(gc, bc, cfgFilename);
   }
 
+  static fromExistingConfig(
+    gc: GlobalTestState,
+    opts: { overridePath?: string },
+  ): FakebankService {
+    const testDir = opts.overridePath ?? gc.testDir;
+    const cfgFilename = testDir + `/bank.conf`;
+    const config = Configuration.load(cfgFilename);
+    const bc: BankConfig = {
+      allowRegistrations:
+        config.getYesNo("bank", "allow_registrations").orUndefined() ?? true,
+      currency: config.getString("taler", "currency").required(),
+      database: "none",
+      httpPort: config.getNumber("bank", "http_port").required(),
+      maxDebt: config.getString("bank", "max_debt").required(),
+    };
+    return new FakebankService(gc, bc, cfgFilename);
+  }
+
   setSuggestedExchange(e: ExchangeServiceInterface, exchangePayto: string) {
     if (!!this.proc) {
       throw Error("Can't set suggested exchange while bank is running.");
@@ -981,6 +1011,7 @@ export interface ExchangeConfig {
   roundUnit?: string;
   httpPort: number;
   database: string;
+  overrideTestDir?: string;
 }
 
 export interface ExchangeServiceInterface {
@@ -991,8 +1022,13 @@ export interface ExchangeServiceInterface {
 }
 
 export class ExchangeService implements ExchangeServiceInterface {
-  static fromExistingConfig(gc: GlobalTestState, exchangeName: string) {
-    const cfgFilename = gc.testDir + `/exchange-${exchangeName}.conf`;
+  static fromExistingConfig(
+    gc: GlobalTestState,
+    exchangeName: string,
+    opts: { overridePath?: string },
+  ) {
+    const testDir = opts.overridePath ?? gc.testDir;
+    const cfgFilename = testDir + `/exchange-${exchangeName}.conf`;
     const config = Configuration.load(cfgFilename);
     const ec: ExchangeConfig = {
       currency: config.getString("taler", "currency").required(),
@@ -1103,7 +1139,9 @@ export class ExchangeService implements 
ExchangeServiceInterface {
   }
 
   static create(gc: GlobalTestState, e: ExchangeConfig) {
+    const testDir = e.overrideTestDir ?? gc.testDir;
     const config = new Configuration();
+    setTalerPaths(config, testDir + "/talerhome");
     config.setString("taler", "currency", e.currency);
     // Required by the exchange but not really used yet.
     config.setString("exchange", "aml_threshold", `${e.currency}:1000000`);
@@ -1112,7 +1150,6 @@ export class ExchangeService implements 
ExchangeServiceInterface {
       "currency_round_unit",
       e.roundUnit ?? `${e.currency}:0.01`,
     );
-    setTalerPaths(config, gc.testDir + "/talerhome");
     config.setString(
       "exchange",
       "revocation_dir",
@@ -1149,7 +1186,7 @@ export class ExchangeService implements 
ExchangeServiceInterface {
 
     fs.writeFileSync(masterPrivFile, Buffer.from(exchangeMasterKey.eddsaPriv));
 
-    const cfgFilename = gc.testDir + `/exchange-${e.name}.conf`;
+    const cfgFilename = testDir + `/exchange-${e.name}.conf`;
     config.write(cfgFilename);
     return new ExchangeService(gc, e, cfgFilename, exchangeMasterKey);
   }
@@ -1498,15 +1535,20 @@ export class ExchangeService implements 
ExchangeServiceInterface {
     );
   }
 
-  async start(): Promise<void> {
+  async start(opts: { skipSetup?: boolean } = {}): Promise<void> {
     if (this.isRunning()) {
       throw Error("exchange is already running");
     }
-    await sh(
-      this.globalState,
-      "exchange-dbinit",
-      `taler-exchange-dbinit -c "${this.configFilename}"`,
-    );
+
+    const skipSetup = opts.skipSetup ?? false;
+
+    if (!skipSetup) {
+      await sh(
+        this.globalState,
+        "exchange-dbinit",
+        `taler-exchange-dbinit -c "${this.configFilename}"`,
+      );
+    }
 
     this.helperCryptoEddsaProc = this.globalState.spawnService(
       "taler-exchange-secmod-eddsa",
@@ -1537,7 +1579,11 @@ export class ExchangeService implements 
ExchangeServiceInterface {
     );
 
     await this.pingUntilAvailable();
-    await this.keyup();
+    if (!skipSetup) {
+      await this.keyup();
+    } else {
+      logger.info("skipping keyup");
+    }
   }
 
   async pingUntilAvailable(): Promise<void> {
@@ -1553,6 +1599,7 @@ export interface MerchantConfig {
   currency: string;
   httpPort: number;
   database: string;
+  overrideTestDir?: string;
 }
 
 export interface PrivateOrderStatusQuery {
@@ -1798,8 +1845,13 @@ export interface CreateMerchantTippingReserveRequest {
 }
 
 export class MerchantService implements MerchantServiceInterface {
-  static fromExistingConfig(gc: GlobalTestState, name: string) {
-    const cfgFilename = gc.testDir + `/merchant-${name}.conf`;
+  static fromExistingConfig(
+    gc: GlobalTestState,
+    name: string,
+    opts: { overridePath?: string },
+  ) {
+    const testDir = opts.overridePath ?? gc.testDir;
+    const cfgFilename = testDir + `/merchant-${name}.conf`;
     const config = Configuration.load(cfgFilename);
     const mc: MerchantConfig = {
       currency: config.getString("taler", "currency").required(),
@@ -1869,13 +1921,17 @@ export class MerchantService implements 
MerchantServiceInterface {
     }
   }
 
-  async start(): Promise<void> {
-    await runCommand(
-      this.globalState,
-      "merchant-dbinit",
-      "taler-merchant-dbinit",
-      ["-c", this.configFilename],
-    );
+  async start(opts: { skipSetup?: boolean } = {}): Promise<void> {
+    const skipSetup = opts.skipSetup ?? false;
+
+    if (!skipSetup) {
+      await runCommand(
+        this.globalState,
+        "merchant-dbinit",
+        "taler-merchant-dbinit",
+        ["-c", this.configFilename],
+      );
+    }
 
     this.proc = this.globalState.spawnService(
       "taler-merchant-httpd",
@@ -1894,11 +1950,12 @@ export class MerchantService implements 
MerchantServiceInterface {
     gc: GlobalTestState,
     mc: MerchantConfig,
   ): Promise<MerchantService> {
+    const testDir = mc.overrideTestDir ?? gc.testDir;
     const config = new Configuration();
     config.setString("taler", "currency", mc.currency);
 
-    const cfgFilename = gc.testDir + `/merchant-${mc.name}.conf`;
-    setTalerPaths(config, gc.testDir + "/talerhome");
+    const cfgFilename = testDir + `/merchant-${mc.name}.conf`;
+    setTalerPaths(config, testDir + "/talerhome");
     config.setString("merchant", "serve", "tcp");
     config.setString("merchant", "port", `${mc.httpPort}`);
     config.setString(
@@ -2241,12 +2298,14 @@ export class WalletService {
   }
 
   async pingUntilAvailable(): Promise<void> {
+    let nextDelay = backoffStart();
     while (1) {
       try {
         await tryUnixConnect(this.socketPath);
       } catch (e) {
         logger.info(`connection attempt failed: ${e}`);
-        await delayMs(200);
+        await delayMs(nextDelay);
+        nextDelay = backoffIncrement(nextDelay);
         continue;
       }
       logger.info("connection to wallet-core succeeded");
diff --git a/packages/taler-harness/src/harness/helpers.ts 
b/packages/taler-harness/src/harness/helpers.ts
index 9ad46e587..932854a1e 100644
--- a/packages/taler-harness/src/harness/helpers.ts
+++ b/packages/taler-harness/src/harness/helpers.ts
@@ -32,6 +32,7 @@ import {
   NotificationType,
   WalletNotification,
   TransactionMajorState,
+  Logger,
 } from "@gnu-taler/taler-util";
 import {
   BankAccessApi,
@@ -49,6 +50,7 @@ import {
   DbInfo,
   ExchangeService,
   ExchangeServiceInterface,
+  FakebankService,
   getPayto,
   GlobalTestState,
   MerchantPrivateApi,
@@ -62,6 +64,10 @@ import {
   WithAuthorization,
 } from "./harness.js";
 
+import * as fs from "fs";
+
+const logger = new Logger("helpers.ts");
+
 /**
  * @deprecated
  */
@@ -212,76 +218,151 @@ export async function createSimpleTestkudosEnvironment(
 export async function useSharedTestkudosEnvironment(t: GlobalTestState) {
   const coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => 
x("TESTKUDOS"));
 
+  const sharedDir = `/tmp/taler-harness@${process.env.USER}`;
+
+  fs.mkdirSync(sharedDir, { recursive: true });
+
   const db = await setupSharedDb(t);
 
-  const bank = await BankService.create(t, {
-    allowRegistrations: true,
-    currency: "TESTKUDOS",
-    database: db.connStr,
-    httpPort: 8082,
-  });
+  let bank: FakebankService;
 
-  const exchange = ExchangeService.create(t, {
-    name: "testexchange-1",
-    currency: "TESTKUDOS",
-    httpPort: 8081,
-    database: db.connStr,
-  });
+  const prevSetupDone = fs.existsSync(sharedDir + "/setup-done");
 
-  const merchant = await MerchantService.create(t, {
-    name: "testmerchant-1",
-    currency: "TESTKUDOS",
-    httpPort: 8083,
-    database: db.connStr,
-  });
+  logger.info(`previous setup done: ${prevSetupDone}`);
+
+  if (fs.existsSync(sharedDir + "/bank.conf")) {
+    logger.info("reusing existing bank");
+    bank = BankService.fromExistingConfig(t, {
+      overridePath: sharedDir,
+    });
+  } else {
+    logger.info("creating new bank config");
+    bank = await BankService.create(t, {
+      allowRegistrations: true,
+      currency: "TESTKUDOS",
+      database: db.connStr,
+      httpPort: 8082,
+      overrideTestDir: sharedDir,
+    });
+  }
+
+  logger.info("setting up exchange");
+
+  const exchangeName = "testexchange-1";
+  const exchangeConfigFilename = sharedDir + `/exchange-${exchangeName}}`;
+
+  let exchange: ExchangeService;
+
+  if (fs.existsSync(exchangeConfigFilename)) {
+    exchange = ExchangeService.fromExistingConfig(t, exchangeName, {
+      overridePath: sharedDir,
+    });
+  } else {
+    exchange = ExchangeService.create(t, {
+      name: "testexchange-1",
+      currency: "TESTKUDOS",
+      httpPort: 8081,
+      database: db.connStr,
+      overrideTestDir: sharedDir,
+    });
+  }
+
+  logger.info("setting up merchant");
+
+  let merchant: MerchantService;
+  const merchantName = "testmerchant-1";
+  const merchantConfigFilename = sharedDir + `/merchant-${merchantName}}`;
+
+  if (fs.existsSync(merchantConfigFilename)) {
+    merchant = MerchantService.fromExistingConfig(t, merchantName, {
+      overridePath: sharedDir,
+    });
+  } else {
+    merchant = await MerchantService.create(t, {
+      name: "testmerchant-1",
+      currency: "TESTKUDOS",
+      httpPort: 8083,
+      database: db.connStr,
+      overrideTestDir: sharedDir,
+    });
+  }
+
+  logger.info("creating bank account for exchange");
 
   const exchangeBankAccount = await bank.createExchangeAccount(
     "myexchange",
     "x",
   );
+
+  logger.info("creating exchange bank account");
   await exchange.addBankAccount("1", exchangeBankAccount);
 
   bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
 
-  await bank.start();
+  exchange.addCoinConfigList(coinConfig);
 
-  await bank.pingUntilAvailable();
+  merchant.addExchange(exchange);
 
-  exchange.addCoinConfigList(coinConfig);
+  logger.info("basic setup done, starting services");
 
-  await exchange.start();
-  await exchange.pingUntilAvailable();
+  const bankStart = async () => {
+    await bank.start();
 
-  merchant.addExchange(exchange);
+    await bank.pingUntilAvailable();
+  };
 
-  await merchant.start();
-  await merchant.pingUntilAvailable();
+  const exchangeStart = async () => {
+    await exchange.start({
+      skipSetup: prevSetupDone,
+    });
+    await exchange.pingUntilAvailable();
+  };
 
-  await merchant.addInstance({
-    id: "default",
-    name: "Default Instance",
-    paytoUris: [getPayto("merchant-default")],
-    defaultWireTransferDelay: Duration.toTalerProtocolDuration(
-      Duration.fromSpec({ minutes: 1 }),
-    ),
-  });
+  const merchStart = async () => {
+    await merchant.start({
+      skipSetup: prevSetupDone,
+    });
+    await merchant.pingUntilAvailable();
+
+    if (!prevSetupDone) {
+      await merchant.addInstance({
+        id: "default",
+        name: "Default Instance",
+        paytoUris: [getPayto("merchant-default")],
+        defaultWireTransferDelay: Duration.toTalerProtocolDuration(
+          Duration.fromSpec({ minutes: 1 }),
+        ),
+      });
+
+      await merchant.addInstance({
+        id: "minst1",
+        name: "minst1",
+        paytoUris: [getPayto("minst1")],
+        defaultWireTransferDelay: Duration.toTalerProtocolDuration(
+          Duration.fromSpec({ minutes: 1 }),
+        ),
+      });
+    }
+  };
 
-  await merchant.addInstance({
-    id: "minst1",
-    name: "minst1",
-    paytoUris: [getPayto("minst1")],
-    defaultWireTransferDelay: Duration.toTalerProtocolDuration(
-      Duration.fromSpec({ minutes: 1 }),
-    ),
-  });
+  const walletStart = async () => {
+    return await createWalletDaemonWithClient(t, { name: "wallet" });
+  };
 
-  const { walletClient, walletService } = await createWalletDaemonWithClient(
-    t,
-    { name: "wallet" },
-  );
+  const res = await Promise.all([
+    exchangeStart(),
+    merchStart(),
+    bankStart(),
+    walletStart(),
+  ]);
+
+  const walletClient = res[3].walletClient;
+  const walletService = res[3].walletService;
 
   console.log("setup done!");
 
+  fs.writeFileSync(sharedDir + "/setup-done", "OK");
+
   return {
     commonDb: db,
     exchange,
@@ -336,7 +417,7 @@ export async function createSimpleTestkudosEnvironmentV2(
   bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
 
   if (opts.additionalBankConfig) {
-    opts.additionalBankConfig(bank)
+    opts.additionalBankConfig(bank);
   }
   await bank.start();
 
@@ -365,7 +446,7 @@ export async function createSimpleTestkudosEnvironmentV2(
   }
 
   if (opts.additionalExchangeConfig) {
-    opts.additionalExchangeConfig(exchange)
+    opts.additionalExchangeConfig(exchange);
   }
   await exchange.start();
   await exchange.pingUntilAvailable();
@@ -373,7 +454,7 @@ export async function createSimpleTestkudosEnvironmentV2(
   merchant.addExchange(exchange);
 
   if (opts.additionalMerchantConfig) {
-    opts.additionalMerchantConfig(merchant)
+    opts.additionalMerchantConfig(merchant);
   }
   await merchant.start();
   await merchant.pingUntilAvailable();
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts 
b/packages/taler-harness/src/integrationtests/testrunner.ts
index a9b6d1304..c1b06f21e 100644
--- a/packages/taler-harness/src/integrationtests/testrunner.ts
+++ b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -14,7 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { CancellationToken, Logger, minimatch } from "@gnu-taler/taler-util";
+import { CancellationToken, Logger, minimatch, setGlobalLogLevelFromString } 
from "@gnu-taler/taler-util";
 import * as child_process from "child_process";
 import * as fs from "fs";
 import * as os from "os";
@@ -494,6 +494,8 @@ if (runTestInstrStr && 
process.argv.includes("__TWCLI_TESTWORKER")) {
     runTestInstrStr,
   ) as RunTestChildInstruction;
 
+  setGlobalLogLevelFromString("TRACE");
+
   process.on("disconnect", () => {
     logger.trace("got disconnect from parent");
     process.exit(3);
diff --git a/packages/taler-util/src/logging.ts 
b/packages/taler-util/src/logging.ts
index c4b2a3da0..b14274560 100644
--- a/packages/taler-util/src/logging.ts
+++ b/packages/taler-util/src/logging.ts
@@ -32,13 +32,13 @@ export enum LogLevel {
   None = "none",
 }
 
-export let globalLogLevel = LogLevel.Info;
+let globalLogLevel = LogLevel.Info;
+const byTagLogLevel: Record<string, LogLevel> = {};
 
 export function setGlobalLogLevelFromString(logLevelStr: string): void {
   globalLogLevel = getLevelForString(logLevelStr);
 }
 
-export const byTagLogLevel: Record<string, LogLevel> = {};
 export function setLogLevelFromString(tag: string, logLevelStr: string): void {
   byTagLogLevel[tag] = getLevelForString(logLevelStr);
 }

-- 
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]