gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: implement the big LibEuFin in


From: gnunet
Subject: [taler-wallet-core] branch master updated: implement the big LibEuFin integration test
Date: Sun, 17 Jan 2021 01:18:41 +0100

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 9aa9742d implement the big LibEuFin integration test
9aa9742d is described below

commit 9aa9742d0e909609f9ce22bc1db8364ab7076db8
Author: Florian Dold <florian@dold.me>
AuthorDate: Sun Jan 17 01:18:37 2021 +0100

    implement the big LibEuFin integration test
---
 .../src/integrationtests/harness.ts                |  70 +++-
 .../src/integrationtests/libeufin.ts               | 442 +++++++++++++++++++++
 .../src/integrationtests/test-libeufin-basic.ts    | 293 ++++++++++++++
 .../src/integrationtests/testrunner.ts             |  12 +-
 4 files changed, 794 insertions(+), 23 deletions(-)

diff --git a/packages/taler-wallet-cli/src/integrationtests/harness.ts 
b/packages/taler-wallet-cli/src/integrationtests/harness.ts
index 4a856cea..3434b5e7 100644
--- a/packages/taler-wallet-cli/src/integrationtests/harness.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/harness.ts
@@ -76,8 +76,8 @@ import {
   codecForPrepareTipResult,
   AcceptTipRequest,
   AbortPayWithRefundRequest,
-  handleWorkerError,
   openPromise,
+  parsePaytoUri,
 } from "taler-wallet-core";
 import { URL } from "url";
 import axios, { AxiosError } from "axios";
@@ -352,6 +352,10 @@ export class GlobalTestState {
     if (this.inShutdown) {
       return;
     }
+    if (shouldLingerInTest()) {
+      console.log("refusing to shut down, lingering was requested");
+      return;
+    }
     this.inShutdown = true;
     console.log("shutting down");
     for (const s of this.servers) {
@@ -368,6 +372,10 @@ export class GlobalTestState {
   }
 }
 
+export function shouldLingerInTest(): boolean {
+  return !!process.env["TALER_TEST_LINGER"];
+}
+
 export interface TalerConfigSection {
   options: Record<string, string | undefined>;
 }
@@ -427,7 +435,11 @@ function setCoin(config: Configuration, c: CoinConfig) {
   config.setString(s, "rsa_keysize", `${c.rsaKeySize}`);
 }
 
-async function pingProc(
+/**
+ * Send an HTTP request until it succeeds or the
+ * process dies.
+ */
+export async function pingProc(
   proc: ProcessWrapper | undefined,
   url: string,
   serviceName: string,
@@ -814,6 +826,15 @@ export class ExchangeService implements 
ExchangeServiceInterface {
     );
   }
 
+  async runTransferOnce() {
+    await runCommand(
+      this.globalState,
+      `exchange-${this.name}-transfer-once`,
+      "taler-exchange-transfer",
+      [...this.timetravelArgArr, "-c", this.configFilename, "-t"],
+    );
+  }
+
   changeConfig(f: (config: Configuration) => void) {
     const config = Configuration.load(this.configFilename);
     f(config);
@@ -1006,11 +1027,18 @@ export class ExchangeService implements 
ExchangeServiceInterface {
     );
 
     const accounts: string[] = [];
+    const accountTargetTypes: Set<string> = new Set();
 
     const config = Configuration.load(this.configFilename);
     for (const sectionName of config.getSectionNames()) {
       if (sectionName.startsWith("exchange-account")) {
-        accounts.push(config.getString(sectionName, "payto_uri").required());
+        const paytoUri = config.getString(sectionName, "payto_uri").required();
+        const p = parsePaytoUri(paytoUri);
+        if (!p) {
+          throw Error(`invalid payto uri in exchange config: ${paytoUri}`);
+        }
+        accountTargetTypes.add(p?.targetType);
+        accounts.push(paytoUri);
       }
     }
 
@@ -1032,22 +1060,24 @@ export class ExchangeService implements 
ExchangeServiceInterface {
     }
 
     const year = new Date().getFullYear();
-    for (let i = year; i < year + 5; i++) {
-      await runCommand(
-        this.globalState,
-        "exchange-offline",
-        "taler-exchange-offline",
-        [
-          "-c",
-          this.configFilename,
-          "wire-fee",
-          `${i}`,
-          "x-taler-bank",
-          `${this.exchangeConfig.currency}:0.01`,
-          `${this.exchangeConfig.currency}:0.01`,
-          "upload",
-        ],
-      );
+    for (const accTargetType of accountTargetTypes.values()) {
+      for (let i = year; i < year + 5; i++) {
+        await runCommand(
+          this.globalState,
+          "exchange-offline",
+          "taler-exchange-offline",
+          [
+            "-c",
+            this.configFilename,
+            "wire-fee",
+            `${i}`,
+            accTargetType,
+            `${this.exchangeConfig.currency}:0.01`,
+            `${this.exchangeConfig.currency}:0.01`,
+            "upload",
+          ],
+        );
+      }
     }
   }
 
@@ -1451,10 +1481,10 @@ export async function runTestWithState(
   let status: TestStatus;
 
   const handleSignal = (s: string) => {
-    gc.shutdownSync();
     console.warn(
       `**** received fatal proces event, terminating test ${testName}`,
     );
+    gc.shutdownSync();
     process.exit(1);
   };
 
diff --git a/packages/taler-wallet-cli/src/integrationtests/libeufin.ts 
b/packages/taler-wallet-cli/src/integrationtests/libeufin.ts
new file mode 100644
index 00000000..cb739f52
--- /dev/null
+++ b/packages/taler-wallet-cli/src/integrationtests/libeufin.ts
@@ -0,0 +1,442 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 axios from "axios";
+import { URL } from "taler-wallet-core";
+import {
+  GlobalTestState,
+  pingProc,
+  ProcessWrapper,
+  runCommand,
+} from "./harness";
+
+export interface LibeufinSandboxServiceInterface {
+  baseUrl: string;
+}
+
+export interface LibeufinNexusServiceInterface {
+  baseUrl: string;
+}
+
+export interface LibeufinSandboxConfig {
+  httpPort: number;
+  databaseJdbcUri: string;
+}
+
+export interface LibeufinNexusConfig {
+  httpPort: number;
+  databaseJdbcUri: string;
+}
+
+export class LibeufinSandboxService implements LibeufinSandboxServiceInterface 
{
+  static async create(
+    gc: GlobalTestState,
+    sandboxConfig: LibeufinSandboxConfig,
+  ): Promise<LibeufinSandboxService> {
+    return new LibeufinSandboxService(gc, sandboxConfig);
+  }
+
+  sandboxProc: ProcessWrapper | undefined;
+  globalTestState: GlobalTestState;
+
+  constructor(
+    gc: GlobalTestState,
+    private sandboxConfig: LibeufinSandboxConfig,
+  ) {
+    this.globalTestState = gc;
+  }
+
+  get baseUrl(): string {
+    return `http://localhost:${this.sandboxConfig.httpPort}/`;
+  }
+
+  async start(): Promise<void> {
+    this.sandboxProc = this.globalTestState.spawnService(
+      "libeufin-sandbox",
+      [
+        "serve",
+        "--port",
+        `${this.sandboxConfig.httpPort}`,
+        "--db-conn-string",
+        this.sandboxConfig.databaseJdbcUri,
+      ],
+      "libeufin-sandbox",
+    );
+  }
+
+  async pingUntilAvailable(): Promise<void> {
+    const url = `${this.baseUrl}config`;
+    await pingProc(this.sandboxProc, url, "libeufin-sandbox");
+  }
+}
+
+export class LibeufinNexusService {
+  static async create(
+    gc: GlobalTestState,
+    nexusConfig: LibeufinNexusConfig,
+  ): Promise<LibeufinNexusService> {
+    return new LibeufinNexusService(gc, nexusConfig);
+  }
+
+  nexusProc: ProcessWrapper | undefined;
+  globalTestState: GlobalTestState;
+
+  constructor(gc: GlobalTestState, private nexusConfig: LibeufinNexusConfig) {
+    this.globalTestState = gc;
+  }
+
+  get baseUrl(): string {
+    return `http://localhost:${this.nexusConfig.httpPort}/`;
+  }
+
+  async start(): Promise<void> {
+    await runCommand(
+      this.globalTestState,
+      "libeufin-nexus-superuser",
+      "libeufin-nexus",
+      [
+        "superuser",
+        "admin",
+        "--password",
+        "test",
+        "--db-conn-string",
+        this.nexusConfig.databaseJdbcUri,
+      ],
+    );
+
+    this.nexusProc = this.globalTestState.spawnService(
+      "libeufin-nexus",
+      [
+        "serve",
+        "--port",
+        `${this.nexusConfig.httpPort}`,
+        "--db-conn-string",
+        this.nexusConfig.databaseJdbcUri,
+      ],
+      "libeufin-nexus",
+    );
+  }
+
+  async pingUntilAvailable(): Promise<void> {
+    const url = `${this.baseUrl}config`;
+    await pingProc(this.nexusProc, url, "libeufin-nexus");
+  }
+}
+
+export interface CreateEbicsSubscriberRequest {
+  hostID: string;
+  userID: string;
+  partnerID: string;
+  systemID?: string;
+}
+
+interface CreateEbicsBankAccountRequest {
+  subscriber: {
+    hostID: string;
+    partnerID: string;
+    userID: string;
+    systemID?: string;
+  };
+  // IBAN
+  iban: string;
+  // BIC
+  bic: string;
+  // human name
+  name: string;
+  currency: string;
+  label: string;
+}
+
+export interface SimulateIncomingTransactionRequest {
+  debtorIban: string;
+  debtorBic: string;
+  debtorName: string;
+
+  /**
+   * Subject / unstructured remittance info.
+   */
+  subject: string;
+
+  /**
+   * Decimal amount without currency.
+   */
+  amount: string;
+  currency: string;
+}
+
+export namespace LibeufinSandboxApi {
+  export async function createEbicsHost(
+    libeufinSandboxService: LibeufinSandboxServiceInterface,
+    hostID: string,
+  ) {
+    const baseUrl = libeufinSandboxService.baseUrl;
+    let url = new URL("admin/ebics/hosts", baseUrl);
+    await axios.post(url.href, {
+      hostID,
+      ebicsVersion: "2.5",
+    });
+  }
+
+  export async function createEbicsSubscriber(
+    libeufinSandboxService: LibeufinSandboxServiceInterface,
+    req: CreateEbicsSubscriberRequest,
+  ) {
+    const baseUrl = libeufinSandboxService.baseUrl;
+    let url = new URL("admin/ebics/subscribers", baseUrl);
+    await axios.post(url.href, req);
+  }
+
+  export async function createEbicsBankAccount(
+    libeufinSandboxService: LibeufinSandboxServiceInterface,
+    req: CreateEbicsBankAccountRequest,
+  ) {
+    const baseUrl = libeufinSandboxService.baseUrl;
+    let url = new URL("admin/ebics/bank-accounts", baseUrl);
+    await axios.post(url.href, req);
+  }
+
+  export async function simulateIncomingTransaction(
+    libeufinSandboxService: LibeufinSandboxServiceInterface,
+    accountLabel: string,
+    req: SimulateIncomingTransactionRequest,
+  ) {
+    const baseUrl = libeufinSandboxService.baseUrl;
+    let url = new URL(
+      `admin/bank-accounts/${accountLabel}/simulate-incoming-transaction`,
+      baseUrl,
+    );
+    await axios.post(url.href, req);
+  }
+
+  export async function getAccountTransactions(
+    libeufinSandboxService: LibeufinSandboxServiceInterface,
+    accountLabel: string,
+  ): Promise<SandboxAccountTransactions> {
+    const baseUrl = libeufinSandboxService.baseUrl;
+    let url = new URL(
+      `admin/bank-accounts/${accountLabel}/transactions`,
+      baseUrl,
+    );
+    const res = await axios.get(url.href);
+    return res.data as SandboxAccountTransactions;
+  }
+}
+
+export interface SandboxAccountTransactions {
+  payments: {
+    accountLabel: string;
+    creditorIban: string;
+    creditorBic?: string;
+    creditorName: string;
+    debtorIban: string;
+    debtorBic: string;
+    debtorName: string;
+    amount: string;
+    currency: string;
+    subject: string;
+    date: string;
+    creditDebitIndicator: "debit" | "credit";
+    accountServicerReference: string;
+  }[];
+}
+
+export interface CreateEbicsBankConnectionRequest {
+  name: string;
+  ebicsURL: string;
+  hostID: string;
+  userID: string;
+  partnerID: string;
+  systemID?: string;
+}
+
+export interface CreateTalerWireGatewayFacadeRequest {
+  name: string;
+  connectionName: string;
+  accountName: string;
+  currency: string;
+  reserveTransferLevel: "report" | "statement" | "notification";
+}
+
+export namespace LibeufinNexusApi {
+  export async function createEbicsBankConnection(
+    libeufinNexusService: LibeufinNexusServiceInterface,
+    req: CreateEbicsBankConnectionRequest,
+  ): Promise<void> {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL("bank-connections", baseUrl);
+    await axios.post(
+      url.href,
+      {
+        source: "new",
+        type: "ebics",
+        name: req.name,
+        data: {
+          ebicsURL: req.ebicsURL,
+          hostID: req.hostID,
+          userID: req.userID,
+          partnerID: req.partnerID,
+          systemID: req.systemID,
+        },
+      },
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+
+  export async function fetchAccounts(
+    libeufinNexusService: LibeufinNexusServiceInterface,
+    connectionName: string,
+  ): Promise<void> {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL(
+      `bank-connections/${connectionName}/fetch-accounts`,
+      baseUrl,
+    );
+    await axios.post(
+      url.href,
+      {},
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+
+  export async function importConnectionAccount(
+    libeufinNexusService: LibeufinNexusServiceInterface,
+    connectionName: string,
+    offeredAccountId: string,
+    nexusBankAccountId: string,
+  ): Promise<void> {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL(
+      `bank-connections/${connectionName}/import-account`,
+      baseUrl,
+    );
+    await axios.post(
+      url.href,
+      {
+        offeredAccountId,
+        nexusBankAccountId,
+      },
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+
+  export async function connectBankConnection(
+    libeufinNexusService: LibeufinNexusServiceInterface,
+    connectionName: string,
+  ) {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL(`bank-connections/${connectionName}/connect`, baseUrl);
+    await axios.post(
+      url.href,
+      {},
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+
+  export async function fetchAllTransactions(
+    libeufinNexusService: LibeufinNexusService,
+    accountName: string,
+  ): Promise<void> {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL(
+      `/bank-accounts/${accountName}/fetch-transactions`,
+      baseUrl,
+    );
+    await axios.post(
+      url.href,
+      {
+        rangeType: "all",
+        level: "report",
+      },
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+
+  export async function createTwgFacade(
+    libeufinNexusService: LibeufinNexusServiceInterface,
+    req: CreateTalerWireGatewayFacadeRequest,
+  ) {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL("facades", baseUrl);
+    await axios.post(
+      url.href,
+      {
+        name: req.name,
+        type: "taler-wire-gateway",
+        config: {
+          bankAccount: req.accountName,
+          bankConnection: req.connectionName,
+          currency: req.currency,
+          reserveTransferLevel: req.reserveTransferLevel,
+        },
+      },
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+
+  export async function submitAllPaymentInitiations(
+    libeufinNexusService: LibeufinNexusServiceInterface,
+    accountId: string,
+  ) {
+    const baseUrl = libeufinNexusService.baseUrl;
+    let url = new URL(
+      `/bank-accounts/${accountId}/submit-all-payment-initiations`,
+      baseUrl,
+    );
+    await axios.post(
+      url.href,
+      {},
+      {
+        auth: {
+          username: "admin",
+          password: "test",
+        },
+      },
+    );
+  }
+}
diff --git 
a/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts
new file mode 100644
index 00000000..39980dac
--- /dev/null
+++ b/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts
@@ -0,0 +1,293 @@
+/*
+ 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 { CoreApiResponse } from "taler-wallet-core";
+import { CoinConfig, defaultCoinConfig } from "./denomStructures";
+import {
+  BankService,
+  DbInfo,
+  delayMs,
+  ExchangeBankAccount,
+  ExchangeService,
+  GlobalTestState,
+  MerchantService,
+  setupDb,
+  WalletCli,
+} from "./harness";
+import { makeTestPayment } from "./helpers";
+import {
+  LibeufinNexusApi,
+  LibeufinNexusService,
+  LibeufinSandboxApi,
+  LibeufinSandboxService,
+} from "./libeufin";
+
+const exchangeIban = "DE71500105179674997361";
+const customerIban = "DE84500105176881385584";
+const customerBic = "BELADEBEXXX";
+const merchantIban = "DE42500105171245624648";
+
+export interface LibeufinTestEnvironment {
+  commonDb: DbInfo;
+  exchange: ExchangeService;
+  exchangeBankAccount: ExchangeBankAccount;
+  merchant: MerchantService;
+  wallet: WalletCli;
+  libeufinSandbox: LibeufinSandboxService;
+  libeufinNexus: LibeufinNexusService;
+}
+
+/**
+ * Create a Taler environment with LibEuFin and an EBICS account.
+ */
+export async function createLibeufinTestEnvironment(
+  t: GlobalTestState,
+  coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("EUR")),
+): Promise<LibeufinTestEnvironment> {
+  const db = await setupDb(t);
+
+  const libeufinSandbox = await LibeufinSandboxService.create(t, {
+    httpPort: 5010,
+    databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`,
+  });
+
+  await libeufinSandbox.start();
+  await libeufinSandbox.pingUntilAvailable();
+
+  const libeufinNexus = await LibeufinNexusService.create(t, {
+    httpPort: 5011,
+    databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`,
+  });
+
+  await libeufinNexus.start();
+  await libeufinNexus.pingUntilAvailable();
+
+  await LibeufinSandboxApi.createEbicsHost(libeufinSandbox, "host01");
+  // Subscriber and bank Account for the exchange
+  await LibeufinSandboxApi.createEbicsSubscriber(libeufinSandbox, {
+    hostID: "host01",
+    partnerID: "partner01",
+    userID: "user01",
+  });
+  await LibeufinSandboxApi.createEbicsBankAccount(libeufinSandbox, {
+    bic: "DEUTDEBB101",
+    iban: exchangeIban,
+    label: "exchangeacct",
+    name: "Taler Exchange",
+    subscriber: {
+      hostID: "host01",
+      partnerID: "partner01",
+      userID: "user01",
+    },
+    currency: "EUR",
+  });
+  // Subscriber and bank Account for the merchant
+  // (Merchant doesn't need EBICS access, but sandbox right now only supports 
EBICS
+  // accounts.)
+  await LibeufinSandboxApi.createEbicsSubscriber(libeufinSandbox, {
+    hostID: "host01",
+    partnerID: "partner02",
+    userID: "user02",
+  });
+  await LibeufinSandboxApi.createEbicsBankAccount(libeufinSandbox, {
+    bic: "COBADEFXXX",
+    iban: merchantIban,
+    label: "merchantacct",
+    name: "Merchant",
+    subscriber: {
+      hostID: "host01",
+      partnerID: "partner02",
+      userID: "user02",
+    },
+    currency: "EUR",
+  });
+
+  await LibeufinNexusApi.createEbicsBankConnection(libeufinNexus, {
+    name: "myconn",
+    ebicsURL: "http://localhost:5010/ebicsweb";,
+    hostID: "host01",
+    partnerID: "partner01",
+    userID: "user01",
+  });
+  await LibeufinNexusApi.connectBankConnection(libeufinNexus, "myconn");
+  await LibeufinNexusApi.fetchAccounts(libeufinNexus, "myconn");
+  await LibeufinNexusApi.importConnectionAccount(
+    libeufinNexus,
+    "myconn",
+    "exchangeacct",
+    "myacct",
+  );
+
+  await LibeufinNexusApi.createTwgFacade(libeufinNexus, {
+    name: "twg1",
+    accountName: "myacct",
+    connectionName: "myconn",
+    currency: "EUR",
+    reserveTransferLevel: "report",
+  });
+
+  const exchange = ExchangeService.create(t, {
+    name: "testexchange-1",
+    currency: "EUR",
+    httpPort: 8081,
+    database: db.connStr,
+  });
+
+  const merchant = await MerchantService.create(t, {
+    name: "testmerchant-1",
+    currency: "EUR",
+    httpPort: 8083,
+    database: db.connStr,
+  });
+
+  const exchangeBankAccount: ExchangeBankAccount = {
+    accountName: "twg-user",
+    accountPassword: "123",
+    accountPaytoUri: `payto://iban/${exchangeIban}?receiver-name=Exchange`,
+    wireGatewayApiBaseUrl:
+      "http://localhost:5011/facades/twg1/taler-wire-gateway/";,
+  };
+
+  exchange.addBankAccount("1", exchangeBankAccount);
+
+  exchange.addCoinConfigList(coinConfig);
+
+  await exchange.start();
+  await exchange.pingUntilAvailable();
+
+  merchant.addExchange(exchange);
+
+  await merchant.start();
+  await merchant.pingUntilAvailable();
+
+  await merchant.addInstance({
+    id: "default",
+    name: "Default Instance",
+    paytoUris: [`payto://iban/${merchantIban}?receiver-name=Merchant`],
+    defaultWireTransferDelay: { d_ms: 0 },
+  });
+
+  console.log("setup done!");
+
+  const wallet = new WalletCli(t);
+
+  return {
+    commonDb: db,
+    exchange,
+    merchant,
+    wallet,
+    exchangeBankAccount,
+    libeufinNexus,
+    libeufinSandbox,
+  };
+}
+
+/**
+ * Run basic test with LibEuFin.
+ */
+export async function runLibeufinBasicTest(t: GlobalTestState) {
+  // Set up test environment
+
+  const {
+    wallet,
+    exchange,
+    merchant,
+    libeufinSandbox,
+    libeufinNexus,
+  } = await createLibeufinTestEnvironment(t);
+
+  let wresp: CoreApiResponse;
+
+  // FIXME: add nicer api in the harness wallet for this.
+  wresp = await wallet.apiRequest("addExchange", {
+    exchangeBaseUrl: exchange.baseUrl,
+  });
+
+  t.assertTrue(wresp.type === "response");
+
+  // FIXME: add nicer api in the harness wallet for this.
+  wresp = await wallet.apiRequest("acceptManualWithdrawal", {
+    exchangeBaseUrl: exchange.baseUrl,
+    amount: "EUR:10",
+  });
+
+  t.assertTrue(wresp.type === "response");
+
+  const reservePub: string = (wresp.result as any).reservePub;
+
+  await LibeufinSandboxApi.simulateIncomingTransaction(
+    libeufinSandbox,
+    "exchangeacct",
+    {
+      amount: "15.00",
+      currency: "EUR",
+      debtorBic: customerBic,
+      debtorIban: customerIban,
+      debtorName: "Jane Customer",
+      subject: `Taler Top-up ${reservePub}`,
+    },
+  );
+
+  await LibeufinNexusApi.fetchAllTransactions(libeufinNexus, "myacct");
+
+  await exchange.runWirewatchOnce();
+
+  await wallet.runUntilDone();
+
+  const bal = await wallet.getBalances();
+  console.log("balances", JSON.stringify(bal, undefined, 2));
+  t.assertAmountEquals(bal.balances[0].available, "EUR:14.7");
+
+  const order = {
+    summary: "Buy me!",
+    amount: "EUR:5",
+    fulfillment_url: "taler://fulfillment-success/thx",
+  };
+
+  await makeTestPayment(t, { wallet, merchant, order });
+
+  await exchange.runAggregatorOnce();
+  await exchange.runTransferOnce();
+
+  await LibeufinNexusApi.submitAllPaymentInitiations(libeufinNexus, "myacct");
+
+  const exchangeTransactions = await LibeufinSandboxApi.getAccountTransactions(
+    libeufinSandbox,
+    "exchangeacct",
+  );
+
+  console.log(
+    "exchange transactions:",
+    JSON.stringify(exchangeTransactions, undefined, 2),
+  );
+
+  t.assertDeepEqual(
+    exchangeTransactions.payments[0].creditDebitIndicator,
+    "credit",
+  );
+  t.assertDeepEqual(
+    exchangeTransactions.payments[1].creditDebitIndicator,
+    "debit",
+  );
+  t.assertDeepEqual(exchangeTransactions.payments[1].debtorIban, exchangeIban);
+  t.assertDeepEqual(
+    exchangeTransactions.payments[1].creditorIban,
+    merchantIban,
+  );
+}
diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts 
b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
index 2acec062..04e803b7 100644
--- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
@@ -14,7 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { GlobalTestState, runTestWithState, TestRunResult } from "./harness";
+import { GlobalTestState, runTestWithState, shouldLingerInTest, TestRunResult 
} from "./harness";
 import { runPaymentTest } from "./test-payment";
 import * as fs from "fs";
 import * as path from "path";
@@ -48,6 +48,7 @@ import { runWithdrawalAbortBankTest } from 
"./test-withdrawal-abort-bank";
 import { runWithdrawalBankIntegratedTest } from 
"./test-withdrawal-bank-integrated";
 import M from "minimatch";
 import { runMerchantExchangeConfusionTest } from 
"./test-merchant-exchange-confusion";
+import { runLibeufinBasicTest } from "./test-libeufin-basic";
 
 /**
  * Test runner.
@@ -65,6 +66,8 @@ const allTests: TestMainFunction[] = [
   runClaimLoopTest,
   runExchangeManagementTest,
   runFeeRegressionTest,
+  runLibeufinBasicTest,
+  runMerchantExchangeConfusionTest,
   runMerchantLongpollingTest,
   runMerchantRefundApiTest,
   runPayAbortTest,
@@ -81,14 +84,13 @@ const allTests: TestMainFunction[] = [
   runRefundIncrementalTest,
   runRefundTest,
   runRevocationTest,
+  runTestWithdrawalManualTest,
   runTimetravelAutorefreshTest,
   runTimetravelWithdrawTest,
   runTippingTest,
   runWallettestingTest,
-  runTestWithdrawalManualTest,
   runWithdrawalAbortBankTest,
   runWithdrawalBankIntegratedTest,
-  runMerchantExchangeConfusionTest,
 ];
 
 export interface TestRunSpec {
@@ -301,6 +303,10 @@ if (runTestInstrStr && 
process.argv.includes("__TWCLI_TESTWORKER")) {
   runTest()
     .then(() => {
       console.log(`test ${testName} finished in worker`);
+      if (shouldLingerInTest()) {
+        console.log("lingering ...");
+        return;
+      }
       process.exit(0);
     })
     .catch((e) => {

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