summaryrefslogtreecommitdiff
path: root/packages/taler-integrationtests/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-integrationtests/src')
-rw-r--r--packages/taler-integrationtests/src/denomStructures.ts151
-rw-r--r--packages/taler-integrationtests/src/faultInjection.ts263
-rw-r--r--packages/taler-integrationtests/src/harness.ts1749
-rw-r--r--packages/taler-integrationtests/src/helpers.ts370
-rw-r--r--packages/taler-integrationtests/src/merchantApiTypes.ts304
-rw-r--r--packages/taler-integrationtests/src/scenario-prompt-payment.ts60
-rw-r--r--packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts128
-rw-r--r--packages/taler-integrationtests/src/test-bank-api.ts137
-rw-r--r--packages/taler-integrationtests/src/test-claim-loop.ts83
-rw-r--r--packages/taler-integrationtests/src/test-exchange-management.ts250
-rw-r--r--packages/taler-integrationtests/src/test-fee-regression.ts206
-rw-r--r--packages/taler-integrationtests/src/test-merchant-longpolling.ts132
-rw-r--r--packages/taler-integrationtests/src/test-merchant-refund-api.ts286
-rw-r--r--packages/taler-integrationtests/src/test-pay-abort.ts202
-rw-r--r--packages/taler-integrationtests/src/test-pay-paid.ts206
-rw-r--r--packages/taler-integrationtests/src/test-payment-claim.ts109
-rw-r--r--packages/taler-integrationtests/src/test-payment-fault.ts210
-rw-r--r--packages/taler-integrationtests/src/test-payment-idempotency.ts103
-rw-r--r--packages/taler-integrationtests/src/test-payment-multiple.ts161
-rw-r--r--packages/taler-integrationtests/src/test-payment-transient.ts172
-rw-r--r--packages/taler-integrationtests/src/test-payment.ts53
-rw-r--r--packages/taler-integrationtests/src/test-paywall-flow.ts233
-rw-r--r--packages/taler-integrationtests/src/test-refund-auto.ts100
-rw-r--r--packages/taler-integrationtests/src/test-refund-gone.ts127
-rw-r--r--packages/taler-integrationtests/src/test-refund-incremental.ts191
-rw-r--r--packages/taler-integrationtests/src/test-refund.ts103
-rw-r--r--packages/taler-integrationtests/src/test-revocation.ts122
-rw-r--r--packages/taler-integrationtests/src/test-timetravel-autorefresh.ts204
-rw-r--r--packages/taler-integrationtests/src/test-timetravel-withdraw.ts90
-rw-r--r--packages/taler-integrationtests/src/test-tipping.ts128
-rw-r--r--packages/taler-integrationtests/src/test-wallettesting.ts87
-rw-r--r--packages/taler-integrationtests/src/test-withdrawal-abort-bank.ts67
-rw-r--r--packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts71
-rw-r--r--packages/taler-integrationtests/src/test-withdrawal-manual.ts78
34 files changed, 0 insertions, 6936 deletions
diff --git a/packages/taler-integrationtests/src/denomStructures.ts b/packages/taler-integrationtests/src/denomStructures.ts
deleted file mode 100644
index 5ab9aca00..000000000
--- a/packages/taler-integrationtests/src/denomStructures.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- 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/>
- */
-
-export interface CoinConfig {
- name: string;
- value: string;
- durationWithdraw: string;
- durationSpend: string;
- durationLegal: string;
- feeWithdraw: string;
- feeDeposit: string;
- feeRefresh: string;
- feeRefund: string;
- rsaKeySize: number;
-}
-
-const coinCommon = {
- durationLegal: "3 years",
- durationSpend: "2 years",
- durationWithdraw: "7 days",
- rsaKeySize: 1024,
-};
-
-export const coin_ct1 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_ct1`,
- value: `${curr}:0.01`,
- feeDeposit: `${curr}:0.00`,
- feeRefresh: `${curr}:0.01`,
- feeRefund: `${curr}:0.00`,
- feeWithdraw: `${curr}:0.01`,
-});
-
-export const coin_ct10 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_ct10`,
- value: `${curr}:0.10`,
- feeDeposit: `${curr}:0.01`,
- feeRefresh: `${curr}:0.01`,
- feeRefund: `${curr}:0.00`,
- feeWithdraw: `${curr}:0.01`,
-});
-
-export const coin_u1 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_u1`,
- value: `${curr}:1`,
- feeDeposit: `${curr}:0.02`,
- feeRefresh: `${curr}:0.02`,
- feeRefund: `${curr}:0.02`,
- feeWithdraw: `${curr}:0.02`,
-});
-
-export const coin_u2 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_u2`,
- value: `${curr}:2`,
- feeDeposit: `${curr}:0.02`,
- feeRefresh: `${curr}:0.02`,
- feeRefund: `${curr}:0.02`,
- feeWithdraw: `${curr}:0.02`,
-});
-
-export const coin_u4 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_u4`,
- value: `${curr}:4`,
- feeDeposit: `${curr}:0.02`,
- feeRefresh: `${curr}:0.02`,
- feeRefund: `${curr}:0.02`,
- feeWithdraw: `${curr}:0.02`,
-});
-
-export const coin_u8 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_u8`,
- value: `${curr}:8`,
- feeDeposit: `${curr}:0.16`,
- feeRefresh: `${curr}:0.16`,
- feeRefund: `${curr}:0.16`,
- feeWithdraw: `${curr}:0.16`,
-});
-
-const coin_u10 = (curr: string): CoinConfig => ({
- ...coinCommon,
- name: `${curr}_u10`,
- value: `${curr}:10`,
- feeDeposit: `${curr}:0.2`,
- feeRefresh: `${curr}:0.2`,
- feeRefund: `${curr}:0.2`,
- feeWithdraw: `${curr}:0.2`,
-});
-
-export const defaultCoinConfig = [
- coin_ct1,
- coin_ct10,
- coin_u1,
- coin_u2,
- coin_u4,
- coin_u8,
- coin_u10,
-];
-
-const coinCheapCommon = (curr: string) => ({
- durationLegal: "3 years",
- durationSpend: "2 years",
- durationWithdraw: "7 days",
- rsaKeySize: 1024,
- feeRefresh: `${curr}:0.2`,
- feeRefund: `${curr}:0.2`,
- feeWithdraw: `${curr}:0.2`,
-});
-
-export function makeNoFeeCoinConfig(curr: string): CoinConfig[] {
- const cc: CoinConfig[] = [];
-
- for (let i = 0; i < 16; i++) {
- const ct = 2 ** i;
-
- const unit = Math.floor(ct / 100);
- const cent = ct % 100;
-
- cc.push({
- durationLegal: "3 years",
- durationSpend: "2 years",
- durationWithdraw: "7 days",
- rsaKeySize: 1024,
- name: `${curr}-u${i}`,
- feeDeposit: `${curr}:0`,
- feeRefresh: `${curr}:0`,
- feeRefund: `${curr}:0`,
- feeWithdraw: `${curr}:0`,
- value: `${curr}:${unit}.${cent}`,
- });
- }
-
- return cc;
-}
diff --git a/packages/taler-integrationtests/src/faultInjection.ts b/packages/taler-integrationtests/src/faultInjection.ts
deleted file mode 100644
index a2d4836d9..000000000
--- a/packages/taler-integrationtests/src/faultInjection.ts
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Fault injection proxy.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports
- */
-import * as http from "http";
-import { URL } from "url";
-import {
- GlobalTestState,
- ExchangeService,
- BankService,
- ExchangeServiceInterface,
- MerchantServiceInterface,
- MerchantService,
- PrivateOrderStatusQuery,
-} from "./harness";
-import {
- PostOrderRequest,
- PostOrderResponse,
- MerchantOrderPrivateStatusResponse,
-} from "./merchantApiTypes";
-
-export interface FaultProxyConfig {
- inboundPort: number;
- targetPort: number;
-}
-
-/**
- * Fault injection context. Modified by fault injection functions.
- */
-export interface FaultInjectionRequestContext {
- requestUrl: string;
- method: string;
- requestHeaders: Record<string, string | string[] | undefined>;
- requestBody?: Buffer;
- dropRequest: boolean;
-}
-
-export interface FaultInjectionResponseContext {
- request: FaultInjectionRequestContext;
- statusCode: number;
- responseHeaders: Record<string, string | string[] | undefined>;
- responseBody: Buffer | undefined;
- dropResponse: boolean;
-}
-
-export interface FaultSpec {
- modifyRequest?: (ctx: FaultInjectionRequestContext) => void;
- modifyResponse?: (ctx: FaultInjectionResponseContext) => void;
-}
-
-export class FaultProxy {
- constructor(
- private globalTestState: GlobalTestState,
- private faultProxyConfig: FaultProxyConfig,
- ) {}
-
- private currentFaultSpecs: FaultSpec[] = [];
-
- start() {
- const server = http.createServer((req, res) => {
- const requestChunks: Buffer[] = [];
- const requestUrl = `http://localhost:${this.faultProxyConfig.inboundPort}${req.url}`;
- console.log("request for", new URL(requestUrl));
- req.on("data", (chunk) => {
- requestChunks.push(chunk);
- });
- req.on("end", () => {
- console.log("end of data");
- let requestBuffer: Buffer | undefined;
- if (requestChunks.length > 0) {
- requestBuffer = Buffer.concat(requestChunks);
- }
- console.log("full request body", requestBuffer);
-
- const faultReqContext: FaultInjectionRequestContext = {
- dropRequest: false,
- method: req.method!!,
- requestHeaders: req.headers,
- requestUrl,
- requestBody: requestBuffer,
- };
-
- for (const faultSpec of this.currentFaultSpecs) {
- if (faultSpec.modifyRequest) {
- faultSpec.modifyRequest(faultReqContext);
- }
- }
-
- if (faultReqContext.dropRequest) {
- res.destroy();
- return;
- }
-
- const faultedUrl = new URL(faultReqContext.requestUrl);
-
- const proxyRequest = http.request({
- method: faultReqContext.method,
- host: "localhost",
- port: this.faultProxyConfig.targetPort,
- path: faultedUrl.pathname + faultedUrl.search,
- headers: faultReqContext.requestHeaders,
- });
-
- console.log(
- `proxying request to target path '${
- faultedUrl.pathname + faultedUrl.search
- }'`,
- );
-
- if (faultReqContext.requestBody) {
- proxyRequest.write(faultReqContext.requestBody);
- }
- proxyRequest.end();
- proxyRequest.on("response", (proxyResp) => {
- console.log("gotten response from target", proxyResp.statusCode);
- const respChunks: Buffer[] = [];
- proxyResp.on("data", (proxyRespData) => {
- respChunks.push(proxyRespData);
- });
- proxyResp.on("end", () => {
- console.log("end of target response");
- let responseBuffer: Buffer | undefined;
- if (respChunks.length > 0) {
- responseBuffer = Buffer.concat(respChunks);
- }
- const faultRespContext: FaultInjectionResponseContext = {
- request: faultReqContext,
- dropResponse: false,
- responseBody: responseBuffer,
- responseHeaders: proxyResp.headers,
- statusCode: proxyResp.statusCode!!,
- };
- for (const faultSpec of this.currentFaultSpecs) {
- const modResponse = faultSpec.modifyResponse;
- if (modResponse) {
- modResponse(faultRespContext);
- }
- }
- if (faultRespContext.dropResponse) {
- req.destroy();
- return;
- }
- if (faultRespContext.responseBody) {
- // We must accomodate for potentially changed content length
- faultRespContext.responseHeaders[
- "content-length"
- ] = `${faultRespContext.responseBody.byteLength}`;
- }
- console.log("writing response head");
- res.writeHead(
- faultRespContext.statusCode,
- http.STATUS_CODES[faultRespContext.statusCode],
- faultRespContext.responseHeaders,
- );
- if (faultRespContext.responseBody) {
- res.write(faultRespContext.responseBody);
- }
- res.end();
- });
- });
- });
- });
-
- server.listen(this.faultProxyConfig.inboundPort);
- this.globalTestState.servers.push(server);
- }
-
- addFault(f: FaultSpec) {
- this.currentFaultSpecs.push(f);
- }
-
- clearAllFaults() {
- this.currentFaultSpecs = [];
- }
-}
-
-export class FaultInjectedExchangeService implements ExchangeServiceInterface {
- baseUrl: string;
- port: number;
- faultProxy: FaultProxy;
-
- get name(): string {
- return this.innerExchange.name;
- }
-
- get masterPub(): string {
- return this.innerExchange.masterPub;
- }
-
- private innerExchange: ExchangeService;
-
- constructor(
- t: GlobalTestState,
- e: ExchangeService,
- proxyInboundPort: number,
- ) {
- this.innerExchange = e;
- this.faultProxy = new FaultProxy(t, {
- inboundPort: proxyInboundPort,
- targetPort: e.port,
- });
- this.faultProxy.start();
-
- const exchangeUrl = new URL(e.baseUrl);
- exchangeUrl.port = `${proxyInboundPort}`;
- this.baseUrl = exchangeUrl.href;
- this.port = proxyInboundPort;
- }
-}
-
-export class FaultInjectedMerchantService implements MerchantServiceInterface {
- baseUrl: string;
- port: number;
- faultProxy: FaultProxy;
-
- get name(): string {
- return this.innerMerchant.name;
- }
-
- private innerMerchant: MerchantService;
- private inboundPort: number;
-
- constructor(
- t: GlobalTestState,
- m: MerchantService,
- proxyInboundPort: number,
- ) {
- this.innerMerchant = m;
- this.faultProxy = new FaultProxy(t, {
- inboundPort: proxyInboundPort,
- targetPort: m.port,
- });
- this.faultProxy.start();
- this.inboundPort = proxyInboundPort;
- }
-
- makeInstanceBaseUrl(instanceName?: string | undefined): string {
- const url = new URL(this.innerMerchant.makeInstanceBaseUrl(instanceName));
- url.port = `${this.inboundPort}`;
- return url.href;
- }
-}
diff --git a/packages/taler-integrationtests/src/harness.ts b/packages/taler-integrationtests/src/harness.ts
deleted file mode 100644
index 58bcf2cf4..000000000
--- a/packages/taler-integrationtests/src/harness.ts
+++ /dev/null
@@ -1,1749 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Test harness for various GNU Taler components.
- * Also provides a fault-injection proxy.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports
- */
-import * as util from "util";
-import * as fs from "fs";
-import * as path from "path";
-import * as os from "os";
-import * as http from "http";
-import { deepStrictEqual } from "assert";
-import { ChildProcess, spawn } from "child_process";
-import {
- Configuration,
- AmountJson,
- Amounts,
- Codec,
- buildCodecForObject,
- codecForString,
- Duration,
- CoreApiResponse,
- PreparePayResult,
- PreparePayRequest,
- codecForPreparePayResult,
- OperationFailedError,
- AddExchangeRequest,
- ExchangesListRespose,
- codecForExchangesListResponse,
- GetWithdrawalDetailsForUriRequest,
- WithdrawUriInfoResponse,
- codecForWithdrawUriInfoResponse,
- ConfirmPayRequest,
- ConfirmPayResult,
- codecForConfirmPayResult,
- IntegrationTestArgs,
- TestPayArgs,
- BalancesResponse,
- codecForBalancesResponse,
- encodeCrock,
- getRandomBytes,
- EddsaKeyPair,
- eddsaGetPublic,
- createEddsaKeyPair,
- TransactionsResponse,
- codecForTransactionsResponse,
- WithdrawTestBalanceRequest,
- AmountString,
- ApplyRefundRequest,
- codecForApplyRefundResponse,
- codecForAny,
- CoinDumpJson,
- ForceExchangeUpdateRequest,
- ForceRefreshRequest,
- PrepareTipResult,
- PrepareTipRequest,
- codecForPrepareTipResult,
- AcceptTipRequest,
- AbortPayWithRefundRequest,
-} from "taler-wallet-core";
-import { URL } from "url";
-import axios, { AxiosError } from "axios";
-import {
- codecForMerchantOrderPrivateStatusResponse,
- codecForPostOrderResponse,
- PostOrderRequest,
- PostOrderResponse,
- MerchantOrderPrivateStatusResponse,
- TippingReserveStatus,
- TipCreateConfirmation,
- TipCreateRequest,
-} from "./merchantApiTypes";
-import { ApplyRefundResponse } from "taler-wallet-core";
-import { PendingOperationsResponse } from "taler-wallet-core";
-import { CoinConfig } from "./denomStructures";
-
-const exec = util.promisify(require("child_process").exec);
-
-export async function delayMs(ms: number): Promise<void> {
- return new Promise((resolve, reject) => {
- setTimeout(() => resolve(), ms);
- });
-}
-
-interface WaitResult {
- code: number | null;
- signal: NodeJS.Signals | null;
-}
-
-/**
- * Run a shell command, return stdout.
- */
-export async function sh(
- t: GlobalTestState,
- logName: string,
- command: string,
-): Promise<string> {
- console.log("runing command", command);
- return new Promise((resolve, reject) => {
- const stdoutChunks: Buffer[] = [];
- const proc = spawn(command, {
- stdio: ["inherit", "pipe", "pipe"],
- shell: true,
- });
- proc.stdout.on("data", (x) => {
- if (x instanceof Buffer) {
- stdoutChunks.push(x);
- } else {
- throw Error("unexpected data chunk type");
- }
- });
- const stderrLogFileName = path.join(t.testDir, `${logName}-stderr.log`);
- const stderrLog = fs.createWriteStream(stderrLogFileName, {
- flags: "a",
- });
- proc.stderr.pipe(stderrLog);
- proc.on("exit", (code, signal) => {
- console.log(`child process exited (${code} / ${signal})`);
- if (code != 0) {
- reject(Error(`Unexpected exit code ${code} for '${command}'`));
- return;
- }
- const b = Buffer.concat(stdoutChunks).toString("utf-8");
- resolve(b);
- });
- proc.on("error", () => {
- reject(Error("Child process had error"));
- });
- });
-}
-
-function shellescape(args: string[]) {
- const ret = args.map((s) => {
- if (/[^A-Za-z0-9_\/:=-]/.test(s)) {
- s = "'" + s.replace(/'/g, "'\\''") + "'";
- s = s.replace(/^(?:'')+/g, "").replace(/\\'''/g, "\\'");
- }
- return s;
- });
- return ret.join(" ");
-}
-
-/**
- * Run a shell command, return stdout.
- *
- * Log stderr to a log file.
- */
-export async function runCommand(
- t: GlobalTestState,
- logName: string,
- command: string,
- args: string[],
-): Promise<string> {
- console.log("runing command", shellescape([command, ...args]));
- return new Promise((resolve, reject) => {
- const stdoutChunks: Buffer[] = [];
- const proc = spawn(command, args, {
- stdio: ["inherit", "pipe", "pipe"],
- shell: false,
- });
- proc.stdout.on("data", (x) => {
- if (x instanceof Buffer) {
- stdoutChunks.push(x);
- } else {
- throw Error("unexpected data chunk type");
- }
- });
- const stderrLogFileName = path.join(t.testDir, `${logName}-stderr.log`);
- const stderrLog = fs.createWriteStream(stderrLogFileName, {
- flags: "a",
- });
- proc.stderr.pipe(stderrLog);
- proc.on("exit", (code, signal) => {
- console.log(`child process exited (${code} / ${signal})`);
- if (code != 0) {
- reject(Error(`Unexpected exit code ${code} for '${command}'`));
- return;
- }
- const b = Buffer.concat(stdoutChunks).toString("utf-8");
- resolve(b);
- });
- proc.on("error", () => {
- reject(Error("Child process had error"));
- });
- });
-}
-
-export class ProcessWrapper {
- private waitPromise: Promise<WaitResult>;
- constructor(public proc: ChildProcess) {
- this.waitPromise = new Promise((resolve, reject) => {
- proc.on("exit", (code, signal) => {
- resolve({ code, signal });
- });
- proc.on("error", (err) => {
- reject(err);
- });
- });
- }
-
- wait(): Promise<WaitResult> {
- return this.waitPromise;
- }
-}
-
-export class GlobalTestParams {
- testDir: string;
-}
-
-export class GlobalTestState {
- testDir: string;
- procs: ProcessWrapper[];
- servers: http.Server[];
- inShutdown: boolean = false;
- constructor(params: GlobalTestParams) {
- this.testDir = params.testDir;
- this.procs = [];
- this.servers = [];
-
- process.on("SIGINT", () => this.shutdownSync());
- process.on("SIGTERM", () => this.shutdownSync());
- process.on("unhandledRejection", () => this.shutdownSync());
- process.on("uncaughtException", () => this.shutdownSync());
- }
-
- async assertThrowsOperationErrorAsync(
- block: () => Promise<void>,
- ): Promise<OperationFailedError> {
- try {
- await block();
- } catch (e) {
- if (e instanceof OperationFailedError) {
- return e;
- }
- throw Error(`expected OperationFailedError to be thrown, but got ${e}`);
- }
- throw Error(
- `expected OperationFailedError to be thrown, but block finished without throwing`,
- );
- }
-
- async assertThrowsAsync(block: () => Promise<void>): Promise<any> {
- try {
- await block();
- } catch (e) {
- return e;
- }
- throw Error(
- `expected exception to be thrown, but block finished without throwing`,
- );
- }
-
- assertAxiosError(e: any): asserts e is AxiosError {
- return e.isAxiosError;
- }
-
- assertTrue(b: boolean): asserts b {
- if (!b) {
- throw Error("test assertion failed");
- }
- }
-
- assertDeepEqual<T>(actual: any, expected: T): asserts actual is T {
- deepStrictEqual(actual, expected);
- }
-
- assertAmountEquals(
- amtActual: string | AmountJson,
- amtExpected: string | AmountJson,
- ): void {
- if (Amounts.cmp(amtActual, amtExpected) != 0) {
- throw Error(
- `test assertion failed: expected ${Amounts.stringify(
- amtExpected,
- )} but got ${Amounts.stringify(amtActual)}`,
- );
- }
- }
-
- assertAmountLeq(a: string | AmountJson, b: string | AmountJson): void {
- if (Amounts.cmp(a, b) > 0) {
- throw Error(
- `test assertion failed: expected ${Amounts.stringify(
- a,
- )} to be less or equal (leq) than ${Amounts.stringify(b)}`,
- );
- }
- }
-
- private shutdownSync(): void {
- for (const s of this.servers) {
- s.close();
- s.removeAllListeners();
- }
- for (const p of this.procs) {
- if (p.proc.exitCode == null) {
- p.proc.kill("SIGTERM");
- } else {
- }
- }
- console.log("*** test harness interrupted");
- console.log("*** test state can be found under", this.testDir);
- process.exit(1);
- }
-
- spawnService(
- command: string,
- args: string[],
- logName: string,
- ): ProcessWrapper {
- console.log(
- `spawning process (${logName}): ${shellescape([command, ...args])}`,
- );
- const proc = spawn(command, args, {
- stdio: ["inherit", "pipe", "pipe"],
- });
- console.log(`spawned process (${logName}) with pid ${proc.pid}`);
- proc.on("error", (err) => {
- console.log(`could not start process (${command})`, err);
- });
- proc.on("exit", (code, signal) => {
- console.log(`process ${logName} exited`);
- });
- const stderrLogFileName = this.testDir + `/${logName}-stderr.log`;
- const stderrLog = fs.createWriteStream(stderrLogFileName, {
- flags: "a",
- });
- proc.stderr.pipe(stderrLog);
- const stdoutLogFileName = this.testDir + `/${logName}-stdout.log`;
- const stdoutLog = fs.createWriteStream(stdoutLogFileName, {
- flags: "a",
- });
- proc.stdout.pipe(stdoutLog);
- const procWrap = new ProcessWrapper(proc);
- this.procs.push(procWrap);
- return procWrap;
- }
-
- async shutdown(): Promise<void> {
- if (this.inShutdown) {
- return;
- }
- this.inShutdown = true;
- console.log("shutting down");
- if (shouldLingerAlways()) {
- console.log("*** test finished, but requested to linger");
- console.log("*** test state can be found under", this.testDir);
- return;
- }
- for (const s of this.servers) {
- s.close();
- s.removeAllListeners();
- }
- for (const p of this.procs) {
- if (p.proc.exitCode == null) {
- console.log("killing process", p.proc.pid);
- p.proc.kill("SIGTERM");
- await p.wait();
- }
- }
- }
-}
-
-export interface TalerConfigSection {
- options: Record<string, string | undefined>;
-}
-
-export interface TalerConfig {
- sections: Record<string, TalerConfigSection>;
-}
-
-export interface DbInfo {
- connStr: string;
- dbname: string;
-}
-
-export async function setupDb(gc: GlobalTestState): Promise<DbInfo> {
- const dbname = "taler-integrationtest";
- await exec(`dropdb "${dbname}" || true`);
- await exec(`createdb "${dbname}"`);
- return {
- connStr: `postgres:///${dbname}`,
- dbname,
- };
-}
-
-export interface BankConfig {
- currency: string;
- httpPort: number;
- database: string;
- allowRegistrations: boolean;
- maxDebt?: string;
-}
-
-function setPaths(config: Configuration, home: string) {
- config.setString("paths", "taler_home", home);
- config.setString("paths", "taler_runtime_dir", "$TALER_HOME/taler-runtime/");
- config.setString(
- "paths",
- "taler_data_home",
- "$TALER_HOME/.local/share/taler/",
- );
- config.setString("paths", "taler_config_home", "$TALER_HOME/.config/taler/");
- config.setString("paths", "taler_cache_home", "$TALER_HOME/.config/taler/");
- config.setString(
- "paths",
- "taler_runtime_dir",
- "${TMPDIR:-${TMP:-/tmp}}/taler-system-runtime/",
- );
-}
-
-function setCoin(config: Configuration, c: CoinConfig) {
- const s = `coin_${c.name}`;
- config.setString(s, "value", c.value);
- config.setString(s, "duration_withdraw", c.durationWithdraw);
- config.setString(s, "duration_spend", c.durationSpend);
- config.setString(s, "duration_legal", c.durationLegal);
- config.setString(s, "fee_deposit", c.feeDeposit);
- config.setString(s, "fee_withdraw", c.feeWithdraw);
- config.setString(s, "fee_refresh", c.feeRefresh);
- config.setString(s, "fee_refund", c.feeRefund);
- 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 delayMs(1000);
- }
- if (!proc || proc.proc.exitCode !== null) {
- throw Error(`service process ${serviceName} stopped unexpectedly`);
- }
- }
-}
-
-export interface ExchangeBankAccount {
- accountName: string;
- accountPassword: string;
- accountPaytoUri: string;
- wireGatewayApiBaseUrl: string;
-}
-
-export interface BankServiceInterface {
- readonly baseUrl: string;
- readonly port: number;
-}
-
-export enum CreditDebitIndicator {
- Credit = "credit",
- Debit = "debit",
-}
-
-export interface BankAccountBalanceResponse {
- balance: {
- amount: AmountString;
- credit_debit_indicator: CreditDebitIndicator;
- };
-}
-
-export namespace BankAccessApi {
- export async function getAccountBalance(
- bank: BankServiceInterface,
- bankUser: BankUser,
- ): Promise<BankAccountBalanceResponse> {
- const url = new URL(`accounts/${bankUser.username}`, bank.baseUrl);
- const resp = await axios.get(url.href, {
- auth: bankUser,
- });
- return resp.data;
- }
-
- export async function createWithdrawalOperation(
- bank: BankServiceInterface,
- bankUser: BankUser,
- amount: string,
- ): Promise<WithdrawalOperationInfo> {
- const url = new URL(
- `accounts/${bankUser.username}/withdrawals`,
- bank.baseUrl,
- );
- const resp = await axios.post(
- url.href,
- {
- amount,
- },
- {
- auth: bankUser,
- },
- );
- return codecForWithdrawalOperationInfo().decode(resp.data);
- }
-}
-
-export namespace BankApi {
- export async function registerAccount(
- bank: BankServiceInterface,
- username: string,
- password: string,
- ): Promise<BankUser> {
- const url = new URL("testing/register", bank.baseUrl);
- await axios.post(url.href, {
- username,
- password,
- });
- return {
- password,
- username,
- accountPaytoUri: `payto://x-taler-bank/localhost/${username}`,
- };
- }
-
- export async function createRandomBankUser(
- bank: BankServiceInterface,
- ): Promise<BankUser> {
- const username = "user-" + encodeCrock(getRandomBytes(10));
- const password = "pw-" + encodeCrock(getRandomBytes(10));
- return await registerAccount(bank, username, password);
- }
-
- export async function adminAddIncoming(
- bank: BankServiceInterface,
- params: {
- exchangeBankAccount: ExchangeBankAccount;
- amount: string;
- reservePub: string;
- debitAccountPayto: string;
- },
- ) {
- const url = new URL(
- `taler-wire-gateway/${params.exchangeBankAccount.accountName}/admin/add-incoming`,
- bank.baseUrl,
- );
- await axios.post(
- url.href,
- {
- amount: params.amount,
- reserve_pub: params.reservePub,
- debit_account: params.debitAccountPayto,
- },
- {
- auth: {
- username: params.exchangeBankAccount.accountName,
- password: params.exchangeBankAccount.accountPassword,
- },
- },
- );
- }
-
- export async function confirmWithdrawalOperation(
- bank: BankServiceInterface,
- bankUser: BankUser,
- wopi: WithdrawalOperationInfo,
- ): Promise<void> {
- const url = new URL(
- `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/confirm`,
- bank.baseUrl,
- );
- await axios.post(
- url.href,
- {},
- {
- auth: bankUser,
- },
- );
- }
-
- export async function abortWithdrawalOperation(
- bank: BankServiceInterface,
- bankUser: BankUser,
- wopi: WithdrawalOperationInfo,
- ): Promise<void> {
- const url = new URL(
- `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/abort`,
- bank.baseUrl,
- );
- await axios.post(
- url.href,
- {},
- {
- auth: bankUser,
- },
- );
- }
-}
-
-export class BankService implements BankServiceInterface {
- 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,
- ): Promise<BankService> {
- const config = new Configuration();
- setPaths(config, gc.testDir + "/talerhome");
- config.setString("taler", "currency", bc.currency);
- config.setString("bank", "database", bc.database);
- 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",
- "allow_registrations",
- bc.allowRegistrations ? "yes" : "no",
- );
- const cfgFilename = gc.testDir + "/bank.conf";
- 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);
- }
-
- setSuggestedExchange(e: ExchangeServiceInterface, exchangePayto: string) {
- const config = Configuration.load(this.configFile);
- config.setString("bank", "suggested_exchange", e.baseUrl);
- config.setString("bank", "suggested_exchange_payto", exchangePayto);
- }
-
- get baseUrl(): string {
- return `http://localhost:${this.bankConfig.httpPort}/`;
- }
-
- 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() {
- return this.bankConfig.httpPort;
- }
-
- private constructor(
- private globalTestState: GlobalTestState,
- private bankConfig: BankConfig,
- private configFile: string,
- ) {}
-
- async start(): Promise<void> {
- this.proc = this.globalTestState.spawnService(
- "taler-bank-manage",
- ["-c", this.configFile, "serve"],
- "bank",
- );
- }
-
- async pingUntilAvailable(): Promise<void> {
- const url = `http://localhost:${this.bankConfig.httpPort}/config`;
- await pingProc(this.proc, url, "bank");
- }
-}
-
-export interface BankUser {
- username: string;
- password: string;
- accountPaytoUri: string;
-}
-
-export interface WithdrawalOperationInfo {
- withdrawal_id: string;
- taler_withdraw_uri: string;
-}
-
-const codecForWithdrawalOperationInfo = (): Codec<WithdrawalOperationInfo> =>
- buildCodecForObject<WithdrawalOperationInfo>()
- .property("withdrawal_id", codecForString())
- .property("taler_withdraw_uri", codecForString())
- .build("WithdrawalOperationInfo");
-
-export interface ExchangeConfig {
- name: string;
- currency: string;
- roundUnit?: string;
- httpPort: number;
- database: string;
-}
-
-export interface ExchangeServiceInterface {
- readonly baseUrl: string;
- readonly port: number;
- readonly name: string;
- readonly masterPub: string;
-}
-
-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: eddsaGetPublic(eddsaPriv),
- };
- return new ExchangeService(gc, ec, cfgFilename, keyPair);
- }
-
- private currentTimetravel: Duration | undefined;
-
- setTimetravel(t: Duration | undefined): void {
- if (this.isRunning()) {
- throw Error("can't set time travel while the exchange is running");
- }
- this.currentTimetravel = t;
- }
-
- private get timetravelArg(): string | undefined {
- if (this.currentTimetravel && this.currentTimetravel.d_ms !== "forever") {
- // Convert to microseconds
- return `--timetravel=+${this.currentTimetravel.d_ms * 1000}`;
- }
- return undefined;
- }
-
- /**
- * Return an empty array if no time travel is set,
- * and an array with the time travel command line argument
- * otherwise.
- */
- private get timetravelArgArr(): string[] {
- const tta = this.timetravelArg;
- if (tta) {
- return [tta];
- }
- return [];
- }
-
- async runWirewatchOnce() {
- await runCommand(
- this.globalState,
- `exchange-${this.name}-wirewatch-once`,
- "taler-exchange-wirewatch",
- [...this.timetravelArgArr, "-c", this.configFilename, "-t"],
- );
- }
-
- async runAggregatorOnce() {
- await runCommand(
- this.globalState,
- `exchange-${this.name}-aggregator-once`,
- "taler-exchange-aggregator",
- [...this.timetravelArgArr, "-c", this.configFilename, "-t"],
- );
- }
-
- static create(gc: GlobalTestState, e: ExchangeConfig) {
- const config = new Configuration();
- config.setString("taler", "currency", e.currency);
- config.setString(
- "taler",
- "currency_round_unit",
- e.roundUnit ?? `${e.currency}:0.01`,
- );
- setPaths(config, gc.testDir + "/talerhome");
-
- config.setString(
- "exchange",
- "keydir",
- "${TALER_DATA_HOME}/exchange/live-keys/",
- );
- config.setString(
- "exchage",
- "revocation_dir",
- "${TALER_DATA_HOME}/exchange/revocations",
- );
- config.setString("exchange", "max_keys_caching", "forever");
- config.setString("exchange", "db", "postgres");
- config.setString(
- "exchange-offline",
- "master_priv_file",
- "${TALER_DATA_HOME}/exchange/offline-keys/master.priv",
- );
- config.setString("exchange", "serve", "tcp");
- 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");
- config.setString("exchange", "lookahead_provide", "4 weeks 1 day");
-
- config.setString("exchangedb-postgres", "config", e.database);
-
- const exchangeMasterKey = createEddsaKeyPair();
-
- config.setString(
- "exchange",
- "master_public_key",
- encodeCrock(exchangeMasterKey.eddsaPub),
- );
-
- const masterPrivFile = config
- .getPath("exchange-offline", "master_priv_file")
- .required();
-
- fs.mkdirSync(path.dirname(masterPrivFile), { recursive: true });
-
- fs.writeFileSync(masterPrivFile, Buffer.from(exchangeMasterKey.eddsaPriv));
-
- const cfgFilename = gc.testDir + `/exchange-${e.name}.conf`;
- config.write(cfgFilename);
- 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);
- }
-
- addCoinConfigList(ccs: CoinConfig[]) {
- const config = Configuration.load(this.configFilename);
- ccs.forEach((cc) => setCoin(config, cc));
- config.write(this.configFilename);
- }
-
- get masterPub() {
- return encodeCrock(this.keyPair.eddsaPub);
- }
-
- get port() {
- return this.exchangeConfig.httpPort;
- }
-
- async addBankAccount(
- localName: string,
- exchangeBankAccount: ExchangeBankAccount,
- ): Promise<void> {
- const config = Configuration.load(this.configFilename);
- config.setString(
- `exchange-account-${localName}`,
- "wire_response",
- `\${TALER_DATA_HOME}/exchange/account-${localName}.json`,
- );
- config.setString(
- `exchange-account-${localName}`,
- "payto_uri",
- exchangeBankAccount.accountPaytoUri,
- );
- config.setString(`exchange-account-${localName}`, "enable_credit", "yes");
- config.setString(`exchange-account-${localName}`, "enable_debit", "yes");
- config.setString(
- `exchange-account-${localName}`,
- "wire_gateway_url",
- exchangeBankAccount.wireGatewayApiBaseUrl,
- );
- config.setString(
- `exchange-account-${localName}`,
- "wire_gateway_auth_method",
- "basic",
- );
- config.setString(
- `exchange-account-${localName}`,
- "username",
- exchangeBankAccount.accountName,
- );
- config.setString(
- `exchange-account-${localName}`,
- "password",
- exchangeBankAccount.accountPassword,
- );
- config.write(this.configFilename);
- }
-
- exchangeHttpProc: ProcessWrapper | undefined;
- exchangeWirewatchProc: ProcessWrapper | undefined;
-
- helperCryptoRsaProc: ProcessWrapper | undefined;
- helperCryptoEddsaProc: ProcessWrapper | undefined;
-
- constructor(
- private globalState: GlobalTestState,
- private exchangeConfig: ExchangeConfig,
- private configFilename: string,
- private keyPair: EddsaKeyPair,
- ) {}
-
- get name() {
- return this.exchangeConfig.name;
- }
-
- get baseUrl() {
- return `http://localhost:${this.exchangeConfig.httpPort}/`;
- }
-
- isRunning(): boolean {
- return !!this.exchangeWirewatchProc || !!this.exchangeHttpProc;
- }
-
- async stop(): Promise<void> {
- const wirewatch = this.exchangeWirewatchProc;
- if (wirewatch) {
- wirewatch.proc.kill("SIGTERM");
- await wirewatch.wait();
- this.exchangeWirewatchProc = undefined;
- }
- const httpd = this.exchangeHttpProc;
- if (httpd) {
- httpd.proc.kill("SIGTERM");
- await httpd.wait();
- this.exchangeHttpProc = undefined;
- }
- const cryptoRsa = this.helperCryptoRsaProc;
- if (cryptoRsa) {
- cryptoRsa.proc.kill("SIGTERM");
- await cryptoRsa.wait();
- this.helperCryptoRsaProc = undefined;
- }
- const cryptoEddsa = this.helperCryptoEddsaProc;
- if (cryptoEddsa) {
- cryptoEddsa.proc.kill("SIGTERM");
- await cryptoEddsa.wait();
- this.helperCryptoRsaProc = undefined;
- }
- }
-
- /**
- * Update keys signing the keys generated by the security module
- * with the offline signing key.
- */
- async keyup(): Promise<void> {
- await runCommand(
- this.globalState,
- "exchange-offline",
- "taler-exchange-offline",
- [
- "-c",
- this.configFilename,
- ...this.timetravelArgArr,
- "download",
- "sign",
- "upload",
- ],
- );
-
- const accounts: string[] = [];
-
- 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());
- }
- }
-
- console.log("configuring bank accounts", accounts);
-
- for (const acc of accounts) {
- await runCommand(
- this.globalState,
- "exchange-offline",
- "taler-exchange-offline",
- [
- "-c",
- this.configFilename,
- ...this.timetravelArgArr,
- "enable-account",
- acc,
- "upload",
- ],
- );
- }
-
- 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,
- ...this.timetravelArgArr,
- "wire-fee",
- `${i}`,
- "x-taler-bank",
- `${this.exchangeConfig.currency}:0.01`,
- `${this.exchangeConfig.currency}:0.01`,
- "upload",
- ],
- );
- }
- }
-
- async revokeDenomination(denomPubHash: string) {
- if (!this.isRunning()) {
- throw Error("exchange must be running when revoking denominations");
- }
- await runCommand(
- this.globalState,
- "exchange-offline",
- "taler-exchange-offline",
- [
- "-c",
- this.configFilename,
- ...this.timetravelArgArr,
- "revoke-denomination",
- denomPubHash,
- "upload",
- ],
- );
- }
-
- async start(): Promise<void> {
- if (this.isRunning()) {
- throw Error("exchange is already running");
- }
- await sh(
- this.globalState,
- "exchange-dbinit",
- `taler-exchange-dbinit -c "${this.configFilename}"`,
- );
-
- this.helperCryptoEddsaProc = this.globalState.spawnService(
- "taler-helper-crypto-eddsa",
- ["-c", this.configFilename, ...this.timetravelArgArr],
- `exchange-crypto-eddsa-${this.name}`,
- );
-
- this.helperCryptoRsaProc = this.globalState.spawnService(
- "taler-helper-crypto-rsa",
- ["-c", this.configFilename, ...this.timetravelArgArr],
- `exchange-crypto-rsa-${this.name}`,
- );
-
- this.exchangeWirewatchProc = this.globalState.spawnService(
- "taler-exchange-wirewatch",
- ["-c", this.configFilename, ...this.timetravelArgArr],
- `exchange-wirewatch-${this.name}`,
- );
-
- this.exchangeHttpProc = this.globalState.spawnService(
- "taler-exchange-httpd",
- [
- "-c",
- this.configFilename,
- "--num-threads",
- "1",
- ...this.timetravelArgArr,
- ],
- `exchange-httpd-${this.name}`,
- );
-
- await this.keyup();
- }
-
- async pingUntilAvailable(): Promise<void> {
- const url = `http://localhost:${this.exchangeConfig.httpPort}/keys`;
- await pingProc(this.exchangeHttpProc, url, `exchange (${this.name})`);
- }
-}
-
-export interface MerchantConfig {
- name: string;
- currency: string;
- httpPort: number;
- database: string;
-}
-
-export interface PrivateOrderStatusQuery {
- instance?: string;
- orderId: string;
- sessionId?: string;
-}
-
-export interface MerchantServiceInterface {
- makeInstanceBaseUrl(instanceName?: string): string;
- readonly port: number;
- readonly name: string;
-}
-
-export namespace MerchantPrivateApi {
- export async function createOrder(
- merchantService: MerchantServiceInterface,
- instanceName: string,
- req: PostOrderRequest,
- ): Promise<PostOrderResponse> {
- const baseUrl = merchantService.makeInstanceBaseUrl(instanceName);
- let url = new URL("private/orders", baseUrl);
- const resp = await axios.post(url.href, req);
- return codecForPostOrderResponse().decode(resp.data);
- }
-
- export async function queryPrivateOrderStatus(
- merchantService: MerchantServiceInterface,
- query: PrivateOrderStatusQuery,
- ): Promise<MerchantOrderPrivateStatusResponse> {
- const reqUrl = new URL(
- `private/orders/${query.orderId}`,
- merchantService.makeInstanceBaseUrl(query.instance),
- );
- if (query.sessionId) {
- reqUrl.searchParams.set("session_id", query.sessionId);
- }
- const resp = await axios.get(reqUrl.href);
- return codecForMerchantOrderPrivateStatusResponse().decode(resp.data);
- }
-
- export async function giveRefund(
- merchantService: MerchantServiceInterface,
- r: {
- instance: string;
- orderId: string;
- amount: string;
- justification: string;
- },
- ): Promise<{ talerRefundUri: string }> {
- const reqUrl = new URL(
- `private/orders/${r.orderId}/refund`,
- merchantService.makeInstanceBaseUrl(r.instance),
- );
- const resp = await axios.post(reqUrl.href, {
- refund: r.amount,
- reason: r.justification,
- });
- return {
- talerRefundUri: resp.data.taler_refund_uri,
- };
- }
-
- export async function createTippingReserve(
- merchantService: MerchantServiceInterface,
- instance: string,
- req: CreateMerchantTippingReserveRequest,
- ): Promise<CreateMerchantTippingReserveConfirmation> {
- const reqUrl = new URL(
- `private/reserves`,
- merchantService.makeInstanceBaseUrl(instance),
- );
- const resp = await axios.post(reqUrl.href, req);
- // FIXME: validate
- return resp.data;
- }
-
- export async function queryTippingReserves(
- merchantService: MerchantServiceInterface,
- instance: string,
- ): Promise<TippingReserveStatus> {
- const reqUrl = new URL(
- `private/reserves`,
- merchantService.makeInstanceBaseUrl(instance),
- );
- const resp = await axios.get(reqUrl.href);
- // FIXME: validate
- return resp.data;
- }
-
- export async function giveTip(
- merchantService: MerchantServiceInterface,
- instance: string,
- req: TipCreateRequest,
- ): Promise<TipCreateConfirmation> {
- const reqUrl = new URL(
- `private/tips`,
- merchantService.makeInstanceBaseUrl(instance),
- );
- const resp = await axios.post(reqUrl.href, req);
- // FIXME: validate
- return resp.data;
- }
-}
-
-export interface CreateMerchantTippingReserveRequest {
- // Amount that the merchant promises to put into the reserve
- initial_balance: AmountString;
-
- // Exchange the merchant intends to use for tipping
- exchange_url: string;
-
- // Desired wire method, for example "iban" or "x-taler-bank"
- wire_method: string;
-}
-
-export interface CreateMerchantTippingReserveConfirmation {
- // Public key identifying the reserve
- reserve_pub: string;
-
- // Wire account of the exchange where to transfer the funds
- payto_uri: string;
-}
-
-export class MerchantService implements MerchantServiceInterface {
- 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(
- private globalState: GlobalTestState,
- private merchantConfig: MerchantConfig,
- private configFilename: string,
- ) {}
-
- private currentTimetravel: Duration | undefined;
-
- private isRunning(): boolean {
- return !!this.proc;
- }
-
- setTimetravel(t: Duration | undefined): void {
- if (this.isRunning()) {
- throw Error("can't set time travel while the exchange is running");
- }
- this.currentTimetravel = t;
- }
-
- private get timetravelArg(): string | undefined {
- if (this.currentTimetravel && this.currentTimetravel.d_ms !== "forever") {
- // Convert to microseconds
- return `--timetravel=+${this.currentTimetravel.d_ms * 1000}`;
- }
- return undefined;
- }
-
- /**
- * Return an empty array if no time travel is set,
- * and an array with the time travel command line argument
- * otherwise.
- */
- private get timetravelArgArr(): string[] {
- const tta = this.timetravelArg;
- if (tta) {
- return [tta];
- }
- return [];
- }
-
- get port(): number {
- return this.merchantConfig.httpPort;
- }
-
- get name(): string {
- return this.merchantConfig.name;
- }
-
- async stop(): Promise<void> {
- const httpd = this.proc;
- if (httpd) {
- httpd.proc.kill("SIGTERM");
- await httpd.wait();
- this.proc = undefined;
- }
- }
-
- async start(): Promise<void> {
- await exec(`taler-merchant-dbinit -c "${this.configFilename}"`);
-
- this.proc = this.globalState.spawnService(
- "taler-merchant-httpd",
- ["-LDEBUG", "-c", this.configFilename, ...this.timetravelArgArr],
- `merchant-${this.merchantConfig.name}`,
- );
- }
-
- static async create(
- gc: GlobalTestState,
- mc: MerchantConfig,
- ): Promise<MerchantService> {
- const config = new Configuration();
- config.setString("taler", "currency", mc.currency);
-
- const cfgFilename = gc.testDir + `/merchant-${mc.name}.conf`;
- setPaths(config, gc.testDir + "/talerhome");
- config.setString("merchant", "serve", "tcp");
- config.setString("merchant", "port", `${mc.httpPort}`);
- config.setString(
- "merchant",
- "keyfile",
- "${TALER_DATA_HOME}/merchant/merchant.priv",
- );
- config.setString("merchantdb-postgres", "config", mc.database);
- config.write(cfgFilename);
-
- return new MerchantService(gc, mc, cfgFilename);
- }
-
- addExchange(e: ExchangeServiceInterface): void {
- const config = Configuration.load(this.configFilename);
- config.setString(
- `merchant-exchange-${e.name}`,
- "exchange_base_url",
- e.baseUrl,
- );
- config.setString(
- `merchant-exchange-${e.name}`,
- "currency",
- this.merchantConfig.currency,
- );
- config.setString(`merchant-exchange-${e.name}`, "master_key", e.masterPub);
- config.write(this.configFilename);
- }
-
- async addInstance(instanceConfig: MerchantInstanceConfig): Promise<void> {
- if (!this.proc) {
- throw Error("merchant must be running to add instance");
- }
- console.log("adding instance");
- const url = `http://localhost:${this.merchantConfig.httpPort}/private/instances`;
- await axios.post(url, {
- payto_uris: instanceConfig.paytoUris,
- id: instanceConfig.id,
- name: instanceConfig.name,
- address: instanceConfig.address ?? {},
- jurisdiction: instanceConfig.jurisdiction ?? {},
- default_max_wire_fee:
- instanceConfig.defaultMaxWireFee ??
- `${this.merchantConfig.currency}:1.0`,
- default_wire_fee_amortization:
- instanceConfig.defaultWireFeeAmortization ?? 3,
- default_max_deposit_fee:
- instanceConfig.defaultMaxDepositFee ??
- `${this.merchantConfig.currency}:1.0`,
- default_wire_transfer_delay: instanceConfig.defaultWireTransferDelay ?? {
- d_ms: "forever",
- },
- default_pay_delay: instanceConfig.defaultPayDelay ?? { d_ms: "forever" },
- });
- }
-
- makeInstanceBaseUrl(instanceName?: string): string {
- if (instanceName === undefined || instanceName === "default") {
- return `http://localhost:${this.merchantConfig.httpPort}/`;
- } else {
- return `http://localhost:${this.merchantConfig.httpPort}/instances/${instanceName}/`;
- }
- }
-
- async pingUntilAvailable(): Promise<void> {
- const url = `http://localhost:${this.merchantConfig.httpPort}/config`;
- await pingProc(this.proc, url, `merchant (${this.merchantConfig.name})`);
- }
-}
-
-export interface MerchantInstanceConfig {
- id: string;
- name: string;
- paytoUris: string[];
- address?: unknown;
- jurisdiction?: unknown;
- defaultMaxWireFee?: string;
- defaultMaxDepositFee?: string;
- defaultWireFeeAmortization?: number;
- defaultWireTransferDelay?: Duration;
- defaultPayDelay?: Duration;
-}
-
-/**
- * Check if the test should hang around after it failed.
- */
-function shouldLinger(): boolean {
- return (
- process.env["TALER_TEST_LINGER"] == "1" ||
- process.env["TALER_TEST_LINGER_ALWAYS"] == "1"
- );
-}
-
-/**
- * Check if the test should hang around even after it finished
- * successfully.
- */
-function shouldLingerAlways(): boolean {
- return process.env["TALER_TEST_LINGER_ALWAYS"] == "1";
-}
-
-function updateCurrentSymlink(testDir: string): void {
- const currLink = path.join(os.tmpdir(), "taler-integrationtest-current");
- try {
- fs.unlinkSync(currLink);
- } catch (e) {
- // Ignore
- }
- try {
- fs.symlinkSync(testDir, currLink);
- } catch (e) {
- console.log(e);
- // Ignore
- }
-}
-
-export function runTestWithState(
- gc: GlobalTestState,
- testMain: (t: GlobalTestState) => Promise<void>,
-) {
- const main = async () => {
- let ret = 0;
- try {
- updateCurrentSymlink(gc.testDir);
- console.log("running test in directory", gc.testDir);
- await testMain(gc);
- } catch (e) {
- console.error("FATAL: test failed with exception", e);
- ret = 1;
- } finally {
- if (gc) {
- if (shouldLinger()) {
- console.log("test logs and config can be found under", gc.testDir);
- console.log("keeping test environment running");
- } else {
- await gc.shutdown();
- console.log("test logs and config can be found under", gc.testDir);
- process.exit(ret);
- }
- }
- }
- };
-
- 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("'", "\\'") + "'";
-}
-
-export class WalletCli {
- private currentTimetravel: Duration | undefined;
-
- setTimetravel(d: Duration | undefined) {
- this.currentTimetravel = d;
- }
-
- private get timetravelArg(): string | undefined {
- if (this.currentTimetravel && this.currentTimetravel.d_ms !== "forever") {
- // Convert to microseconds
- return `--timetravel=${this.currentTimetravel.d_ms * 1000}`;
- }
- return undefined;
- }
-
- constructor(
- private globalTestState: GlobalTestState,
- private name: string = "default",
- ) {}
-
- get dbfile(): string {
- return this.globalTestState.testDir + `/walletdb-${this.name}.json`;
- }
-
- deleteDatabase() {
- fs.unlinkSync(this.dbfile);
- }
-
- private get timetravelArgArr(): string[] {
- const tta = this.timetravelArg;
- if (tta) {
- return [tta];
- }
- return [];
- }
-
- async apiRequest(
- request: string,
- payload: unknown,
- ): Promise<CoreApiResponse> {
- const resp = await sh(
- this.globalTestState,
- `wallet-${this.name}`,
- `taler-wallet-cli ${
- this.timetravelArg ?? ""
- } --no-throttle --wallet-db '${this.dbfile}' api '${request}' ${shellWrap(
- JSON.stringify(payload),
- )}`,
- );
- console.log(resp);
- return JSON.parse(resp) as CoreApiResponse;
- }
-
- async runUntilDone(args: { maxRetries?: number } = {}): Promise<void> {
- await runCommand(
- this.globalTestState,
- `wallet-${this.name}`,
- "taler-wallet-cli",
- [
- "--no-throttle",
- ...this.timetravelArgArr,
- "--wallet-db",
- this.dbfile,
- "run-until-done",
- ...(args.maxRetries ? ["--max-retries", `${args.maxRetries}`] : []),
- ],
- );
- }
-
- async runPending(): Promise<void> {
- await runCommand(
- this.globalTestState,
- `wallet-${this.name}`,
- "taler-wallet-cli",
- [
- "--no-throttle",
- ...this.timetravelArgArr,
- "--wallet-db",
- this.dbfile,
- "run-pending",
- ],
- );
- }
-
- async applyRefund(req: ApplyRefundRequest): Promise<ApplyRefundResponse> {
- const resp = await this.apiRequest("applyRefund", req);
- if (resp.type === "response") {
- return codecForApplyRefundResponse().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async preparePay(req: PreparePayRequest): Promise<PreparePayResult> {
- const resp = await this.apiRequest("preparePay", req);
- if (resp.type === "response") {
- return codecForPreparePayResult().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async abortFailedPayWithRefund(
- req: AbortPayWithRefundRequest,
- ): Promise<void> {
- const resp = await this.apiRequest("abortFailedPayWithRefund", req);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async confirmPay(req: ConfirmPayRequest): Promise<ConfirmPayResult> {
- const resp = await this.apiRequest("confirmPay", req);
- if (resp.type === "response") {
- return codecForConfirmPayResult().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async prepareTip(req: PrepareTipRequest): Promise<PrepareTipResult> {
- const resp = await this.apiRequest("prepareTip", req);
- if (resp.type === "response") {
- return codecForPrepareTipResult().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async acceptTip(req: AcceptTipRequest): Promise<void> {
- const resp = await this.apiRequest("acceptTip", req);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async dumpCoins(): Promise<CoinDumpJson> {
- const resp = await this.apiRequest("dumpCoins", {});
- if (resp.type === "response") {
- return codecForAny().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async addExchange(req: AddExchangeRequest): Promise<void> {
- const resp = await this.apiRequest("addExchange", req);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async forceUpdateExchange(req: ForceExchangeUpdateRequest): Promise<void> {
- const resp = await this.apiRequest("forceUpdateExchange", req);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async forceRefresh(req: ForceRefreshRequest): Promise<void> {
- const resp = await this.apiRequest("forceRefresh", req);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async listExchanges(): Promise<ExchangesListRespose> {
- const resp = await this.apiRequest("listExchanges", {});
- if (resp.type === "response") {
- return codecForExchangesListResponse().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async getBalances(): Promise<BalancesResponse> {
- const resp = await this.apiRequest("getBalances", {});
- if (resp.type === "response") {
- return codecForBalancesResponse().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async getPendingOperations(): Promise<PendingOperationsResponse> {
- const resp = await this.apiRequest("getPendingOperations", {});
- if (resp.type === "response") {
- // FIXME: validate properly!
- return codecForAny().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async getTransactions(): Promise<TransactionsResponse> {
- const resp = await this.apiRequest("getTransactions", {});
- if (resp.type === "response") {
- return codecForTransactionsResponse().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-
- async runIntegrationTest(args: IntegrationTestArgs): Promise<void> {
- const resp = await this.apiRequest("runIntegrationTest", args);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async testPay(args: TestPayArgs): Promise<void> {
- const resp = await this.apiRequest("testPay", args);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async withdrawTestBalance(args: WithdrawTestBalanceRequest): Promise<void> {
- const resp = await this.apiRequest("withdrawTestBalance", args);
- if (resp.type === "response") {
- return;
- }
- throw new OperationFailedError(resp.error);
- }
-
- async getWithdrawalDetailsForUri(
- req: GetWithdrawalDetailsForUriRequest,
- ): Promise<WithdrawUriInfoResponse> {
- const resp = await this.apiRequest("getWithdrawalDetailsForUri", req);
- if (resp.type === "response") {
- return codecForWithdrawUriInfoResponse().decode(resp.result);
- }
- throw new OperationFailedError(resp.error);
- }
-}
diff --git a/packages/taler-integrationtests/src/helpers.ts b/packages/taler-integrationtests/src/helpers.ts
deleted file mode 100644
index f4e676b61..000000000
--- a/packages/taler-integrationtests/src/helpers.ts
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Helpers to create typical test environments.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports
- */
-import {
- GlobalTestState,
- DbInfo,
- ExchangeService,
- WalletCli,
- MerchantService,
- setupDb,
- BankService,
- ExchangeBankAccount,
- MerchantServiceInterface,
- BankApi,
- BankAccessApi,
- MerchantPrivateApi,
- ExchangeServiceInterface,
-} from "./harness";
-import {
- AmountString,
- Duration,
- PreparePayResultType,
- ConfirmPayResultType,
- ContractTerms,
-} from "taler-wallet-core";
-import { FaultInjectedMerchantService } from "./faultInjection";
-import { defaultCoinConfig } from "./denomStructures";
-
-export interface SimpleTestEnvironment {
- commonDb: DbInfo;
- bank: BankService;
- exchange: ExchangeService;
- exchangeBankAccount: ExchangeBankAccount;
- merchant: MerchantService;
- wallet: WalletCli;
-}
-
-/**
- * Run a test case with a simple TESTKUDOS Taler environment, consisting
- * of one exchange, one bank and one merchant.
- */
-export async function createSimpleTestkudosEnvironment(
- t: GlobalTestState,
-): Promise<SimpleTestEnvironment> {
- const db = await setupDb(t);
-
- const bank = await BankService.create(t, {
- allowRegistrations: true,
- currency: "TESTKUDOS",
- database: db.connStr,
- httpPort: 8082,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
- exchange.addBankAccount("1", exchangeBankAccount);
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- exchange.addOfferedCoins(defaultCoinConfig);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- 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!");
-
- const wallet = new WalletCli(t);
-
- return {
- commonDb: db,
- exchange,
- merchant,
- wallet,
- bank,
- exchangeBankAccount,
- };
-}
-
-export interface FaultyMerchantTestEnvironment {
- commonDb: DbInfo;
- bank: BankService;
- exchange: ExchangeService;
- exchangeBankAccount: ExchangeBankAccount;
- merchant: MerchantService;
- faultyMerchant: FaultInjectedMerchantService;
- wallet: WalletCli;
-}
-
-/**
- * Run a test case with a simple TESTKUDOS Taler environment, consisting
- * of one exchange, one bank and one merchant.
- */
-export async function createFaultInjectedMerchantTestkudosEnvironment(
- t: GlobalTestState,
-): Promise<FaultyMerchantTestEnvironment> {
- const db = await setupDb(t);
-
- const bank = await BankService.create(t, {
- allowRegistrations: true,
- currency: "TESTKUDOS",
- database: db.connStr,
- httpPort: 8082,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- const faultyMerchant = new FaultInjectedMerchantService(t, merchant, 9083);
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
- exchange.addBankAccount("1", exchangeBankAccount);
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- exchange.addOfferedCoins(defaultCoinConfig);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- 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!");
-
- const wallet = new WalletCli(t);
-
- return {
- commonDb: db,
- exchange,
- merchant,
- wallet,
- bank,
- exchangeBankAccount,
- faultyMerchant,
- };
-}
-
-/**
- * Withdraw balance.
- */
-export async function startWithdrawViaBank(
- t: GlobalTestState,
- p: {
- wallet: WalletCli;
- bank: BankService;
- exchange: ExchangeServiceInterface;
- amount: AmountString;
- },
-): Promise<void> {
- const { wallet, bank, exchange, amount } = p;
-
- const user = await BankApi.createRandomBankUser(bank);
- const wop = await BankAccessApi.createWithdrawalOperation(bank, user, amount);
-
- // Hand it to the wallet
-
- const r1 = await wallet.apiRequest("getWithdrawalDetailsForUri", {
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r1.type === "response");
-
- await wallet.runPending();
-
- // Confirm it
-
- await BankApi.confirmWithdrawalOperation(bank, user, wop);
-
- // Withdraw
-
- const r2 = await wallet.apiRequest("acceptBankIntegratedWithdrawal", {
- exchangeBaseUrl: exchange.baseUrl,
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r2.type === "response");
-}
-
-/**
- * Withdraw balance.
- */
-export async function withdrawViaBank(
- t: GlobalTestState,
- p: {
- wallet: WalletCli;
- bank: BankService;
- exchange: ExchangeServiceInterface;
- amount: AmountString;
- },
-): Promise<void> {
- const { wallet } = p;
-
- await startWithdrawViaBank(t, p);
-
- await wallet.runUntilDone();
-
- // Check balance
-
- const balApiResp = await wallet.apiRequest("getBalances", {});
- t.assertTrue(balApiResp.type === "response");
-}
-
-export async function applyTimeTravel(
- timetravelDuration: Duration,
- s: {
- exchange?: ExchangeService;
- merchant?: MerchantService;
- wallet?: WalletCli;
- },
-): Promise<void> {
- if (s.exchange) {
- await s.exchange.stop();
- s.exchange.setTimetravel(timetravelDuration);
- await s.exchange.start();
- await s.exchange.pingUntilAvailable();
- }
-
- if (s.merchant) {
- await s.merchant.stop();
- s.merchant.setTimetravel(timetravelDuration);
- await s.merchant.start();
- await s.merchant.pingUntilAvailable();
- }
-
- if (s.wallet) {
- s.wallet.setTimetravel(timetravelDuration);
- }
-}
-
-/**
- * Make a simple payment and check that it succeeded.
- */
-export async function makeTestPayment(
- t: GlobalTestState,
- args: {
- merchant: MerchantServiceInterface;
- wallet: WalletCli;
- order: Partial<ContractTerms>;
- instance?: string;
- },
-): Promise<void> {
- // Set up order.
-
- const { wallet, merchant } = args;
- const instance = args.instance ?? "default";
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, instance, {
- order: args.order,
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const preparePayResult = await wallet.preparePay({
- talerPayUri: orderStatus.taler_pay_uri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.PaymentPossible,
- );
-
- const r2 = await wallet.confirmPay({
- proposalId: preparePayResult.proposalId,
- });
-
- t.assertTrue(r2.type === ConfirmPayResultType.Done);
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- instance,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-}
diff --git a/packages/taler-integrationtests/src/merchantApiTypes.ts b/packages/taler-integrationtests/src/merchantApiTypes.ts
deleted file mode 100644
index 6782391a2..000000000
--- a/packages/taler-integrationtests/src/merchantApiTypes.ts
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Test harness for various GNU Taler components.
- * Also provides a fault-injection proxy.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports.
- */
-import {
- ContractTerms,
- Duration,
- Codec,
- buildCodecForObject,
- codecForString,
- codecOptional,
- codecForConstString,
- codecForBoolean,
- codecForNumber,
- codecForContractTerms,
- codecForAny,
- buildCodecForUnion,
- AmountString,
- Timestamp,
- CoinPublicKeyString,
-} from "taler-wallet-core";
-import { codecForAmountString } from "taler-wallet-core/lib/util/amounts";
-
-export interface PostOrderRequest {
- // The order must at least contain the minimal
- // order detail, but can override all
- order: Partial<ContractTerms>;
-
- // if set, the backend will then set the refund deadline to the current
- // time plus the specified delay.
- refund_delay?: Duration;
-
- // specifies the payment target preferred by the client. Can be used
- // to select among the various (active) wire methods supported by the instance.
- payment_target?: string;
-
- // FIXME: some fields are missing
-
- // Should a token for claiming the order be generated?
- // False can make sense if the ORDER_ID is sufficiently
- // high entropy to prevent adversarial claims (like it is
- // if the backend auto-generates one). Default is 'true'.
- create_token?: boolean;
-}
-
-export type ClaimToken = string;
-
-export interface PostOrderResponse {
- order_id: string;
- token?: ClaimToken;
-}
-
-export const codecForPostOrderResponse = (): Codec<PostOrderResponse> =>
- buildCodecForObject<PostOrderResponse>()
- .property("order_id", codecForString())
- .property("token", codecOptional(codecForString()))
- .build("PostOrderResponse");
-
-export const codecForCheckPaymentPaidResponse = (): Codec<
- CheckPaymentPaidResponse
-> =>
- buildCodecForObject<CheckPaymentPaidResponse>()
- .property("order_status_url", codecForString())
- .property("order_status", codecForConstString("paid"))
- .property("refunded", codecForBoolean())
- .property("wired", codecForBoolean())
- .property("deposit_total", codecForAmountString())
- .property("exchange_ec", codecForNumber())
- .property("exchange_hc", codecForNumber())
- .property("refund_amount", codecForAmountString())
- .property("contract_terms", codecForContractTerms())
- // FIXME: specify
- .property("wire_details", codecForAny())
- .property("wire_reports", codecForAny())
- .property("refund_details", codecForAny())
- .build("CheckPaymentPaidResponse");
-
-export const codecForCheckPaymentUnpaidResponse = (): Codec<
- CheckPaymentUnpaidResponse
-> =>
- buildCodecForObject<CheckPaymentUnpaidResponse>()
- .property("order_status", codecForConstString("unpaid"))
- .property("taler_pay_uri", codecForString())
- .property("order_status_url", codecForString())
- .property("already_paid_order_id", codecOptional(codecForString()))
- .build("CheckPaymentPaidResponse");
-
-export const codecForCheckPaymentClaimedResponse = (): Codec<
- CheckPaymentClaimedResponse
-> =>
- buildCodecForObject<CheckPaymentClaimedResponse>()
- .property("order_status", codecForConstString("claimed"))
- .property("contract_terms", codecForContractTerms())
- .build("CheckPaymentClaimedResponse");
-
-export const codecForMerchantOrderPrivateStatusResponse = (): Codec<
- MerchantOrderPrivateStatusResponse
-> =>
- buildCodecForUnion<MerchantOrderPrivateStatusResponse>()
- .discriminateOn("order_status")
- .alternative("paid", codecForCheckPaymentPaidResponse())
- .alternative("unpaid", codecForCheckPaymentUnpaidResponse())
- .alternative("claimed", codecForCheckPaymentClaimedResponse())
- .build("MerchantOrderPrivateStatusResponse");
-
-export type MerchantOrderPrivateStatusResponse =
- | CheckPaymentPaidResponse
- | CheckPaymentUnpaidResponse
- | CheckPaymentClaimedResponse;
-
-export interface CheckPaymentClaimedResponse {
- // Wallet claimed the order, but didn't pay yet.
- order_status: "claimed";
-
- contract_terms: ContractTerms;
-}
-
-export interface CheckPaymentPaidResponse {
- // did the customer pay for this contract
- order_status: "paid";
-
- // Was the payment refunded (even partially)
- refunded: boolean;
-
- // Did the exchange wire us the funds
- wired: boolean;
-
- // Total amount the exchange deposited into our bank account
- // for this contract, excluding fees.
- deposit_total: AmountString;
-
- // Numeric error code indicating errors the exchange
- // encountered tracking the wire transfer for this purchase (before
- // we even got to specific coin issues).
- // 0 if there were no issues.
- exchange_ec: number;
-
- // HTTP status code returned by the exchange when we asked for
- // information to track the wire transfer for this purchase.
- // 0 if there were no issues.
- exchange_hc: number;
-
- // Total amount that was refunded, 0 if refunded is false.
- refund_amount: AmountString;
-
- // Contract terms
- contract_terms: ContractTerms;
-
- // Ihe wire transfer status from the exchange for this order if available, otherwise empty array
- wire_details: TransactionWireTransfer[];
-
- // Reports about trouble obtaining wire transfer details, empty array if no trouble were encountered.
- wire_reports: TransactionWireReport[];
-
- // The refund details for this order. One entry per
- // refunded coin; empty array if there are no refunds.
- refund_details: RefundDetails[];
-
- order_status_url: string;
-}
-
-export interface CheckPaymentUnpaidResponse {
- order_status: "unpaid";
-
- // URI that the wallet must process to complete the payment.
- taler_pay_uri: string;
-
- order_status_url: string;
-
- // Alternative order ID which was paid for already in the same session.
- // Only given if the same product was purchased before in the same session.
- already_paid_order_id?: string;
-
- // We do we NOT return the contract terms here because they may not
- // exist in case the wallet did not yet claim them.
-}
-
-export interface RefundDetails {
- // Reason given for the refund
- reason: string;
-
- // when was the refund approved
- timestamp: Timestamp;
-
- // Total amount that was refunded (minus a refund fee).
- amount: AmountString;
-}
-
-export interface TransactionWireTransfer {
- // Responsible exchange
- exchange_url: string;
-
- // 32-byte wire transfer identifier
- wtid: string;
-
- // execution time of the wire transfer
- execution_time: Timestamp;
-
- // Total amount that has been wire transfered
- // to the merchant
- amount: AmountString;
-
- // Was this transfer confirmed by the merchant via the
- // POST /transfers API, or is it merely claimed by the exchange?
- confirmed: boolean;
-}
-
-export interface TransactionWireReport {
- // Numerical error code
- code: number;
-
- // Human-readable error description
- hint: string;
-
- // Numerical error code from the exchange.
- exchange_ec: number;
-
- // HTTP status code received from the exchange.
- exchange_hc: number;
-
- // Public key of the coin for which we got the exchange error.
- coin_pub: CoinPublicKeyString;
-}
-
-export interface TippingReserveStatus {
- // Array of all known reserves (possibly empty!)
- reserves: ReserveStatusEntry[];
-}
-
-export interface ReserveStatusEntry {
- // Public key of the reserve
- reserve_pub: string;
-
- // Timestamp when it was established
- creation_time: Timestamp;
-
- // Timestamp when it expires
- expiration_time: Timestamp;
-
- // Initial amount as per reserve creation call
- merchant_initial_amount: AmountString;
-
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: AmountString;
-
- // Amount picked up so far.
- pickup_amount: AmountString;
-
- // Amount approved for tips that exceeds the pickup_amount.
- committed_amount: AmountString;
-
- // Is this reserve active (false if it was deleted but not purged)
- active: boolean;
-}
-
-export interface TipCreateConfirmation {
- // Unique tip identifier for the tip that was created.
- tip_id: string;
-
- // taler://tip URI for the tip
- taler_tip_uri: string;
-
- // URL that will directly trigger processing
- // the tip when the browser is redirected to it
- tip_status_url: string;
-
- // when does the tip expire
- tip_expiration: Timestamp;
-}
-
-export interface TipCreateRequest {
- // Amount that the customer should be tipped
- amount: AmountString;
-
- // Justification for giving the tip
- justification: string;
-
- // URL that the user should be directed to after tipping,
- // will be included in the tip_token.
- next_url: string;
-}
diff --git a/packages/taler-integrationtests/src/scenario-prompt-payment.ts b/packages/taler-integrationtests/src/scenario-prompt-payment.ts
deleted file mode 100644
index 3c34075d1..000000000
--- a/packages/taler-integrationtests/src/scenario-prompt-payment.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- console.log(orderStatus);
-
- // Wait "forever"
- await new Promise(() => {});
-});
diff --git a/packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts b/packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts
deleted file mode 100644
index 3a98987b3..000000000
--- a/packages/taler-integrationtests/src/scenario-rerun-payment-multiple.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- 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 {
- GlobalTestState,
- BankService,
- ExchangeService,
- MerchantService,
- WalletCli,
- runTestWithState,
- MerchantPrivateApi,
-} from "./harness";
-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,
-});
-
-async function withdrawAndPay(
- t: GlobalTestState,
- wallet: WalletCli,
- bank: BankService,
- exchange: ExchangeService,
- merchant: MerchantService,
-): Promise<void> {
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:100" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:80",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const r1 = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(r1.type === "response");
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: (r1.result as any).proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-}
-
-/**
- * Run test.
- */
-runTestWithState(prevT, async (t: GlobalTestState) => {
- // Set up test environment
-
- const bank = BankService.fromExistingConfig(t);
- const exchange = ExchangeService.fromExistingConfig(t, "testexchange-1");
- const merchant = MerchantService.fromExistingConfig(t, "testmerchant-1");
-
- await bank.start();
- await exchange.start();
- await merchant.start();
- await Promise.all([
- bank.pingUntilAvailable(),
- merchant.pingUntilAvailable(),
- exchange.pingUntilAvailable(),
- ]);
-
- const wallet = new WalletCli(t);
-
- // Withdraw digital cash into the wallet.
-
- const repetitions = Number.parseInt(process.env["TALER_TEST_REPEAT"] ?? "1");
-
- for (let rep = 0; rep < repetitions; rep++) {
- console.log("repetition", rep);
- try {
- wallet.deleteDatabase();
- await withdrawAndPay(t, wallet, bank, exchange, merchant);
- } catch (e) {
- console.log("ignoring exception", e);
- }
- }
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-bank-api.ts b/packages/taler-integrationtests/src/test-bank-api.ts
deleted file mode 100644
index 08991e279..000000000
--- a/packages/taler-integrationtests/src/test-bank-api.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- 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,
- WalletCli,
- ExchangeService,
- setupDb,
- BankService,
- MerchantService,
- BankApi,
- BankAccessApi,
- CreditDebitIndicator,
-} from "./harness";
-import { createEddsaKeyPair, encodeCrock } from "taler-wallet-core";
-import { defaultCoinConfig } from "./denomStructures";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(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,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
- exchange.addBankAccount("1", exchangeBankAccount);
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- exchange.addOfferedCoins(defaultCoinConfig);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- 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!");
-
- const wallet = new WalletCli(t);
-
- const bankUser = await BankApi.registerAccount(bank, "user1", "pw1");
-
- // Make sure that registering twice results in a 409 Conflict
- {
- const e = await t.assertThrowsAsync(async () => {
- await BankApi.registerAccount(bank, "user1", "pw1");
- });
- t.assertAxiosError(e);
- t.assertTrue(e.response?.status === 409);
- }
-
- let balResp = await BankAccessApi.getAccountBalance(bank, bankUser);
-
- console.log(balResp);
-
- // Check that we got the sign-up bonus.
- t.assertAmountEquals(balResp.balance.amount, "TESTKUDOS:100");
- t.assertTrue(
- balResp.balance.credit_debit_indicator === CreditDebitIndicator.Credit,
- );
-
- const res = createEddsaKeyPair();
-
- await BankApi.adminAddIncoming(bank, {
- amount: "TESTKUDOS:115",
- debitAccountPayto: bankUser.accountPaytoUri,
- exchangeBankAccount: exchangeBankAccount,
- reservePub: encodeCrock(res.eddsaPub),
- });
-
- balResp = await BankAccessApi.getAccountBalance(bank, bankUser);
- t.assertAmountEquals(balResp.balance.amount, "TESTKUDOS:15");
- t.assertTrue(
- balResp.balance.credit_debit_indicator === CreditDebitIndicator.Debit,
- );
-});
diff --git a/packages/taler-integrationtests/src/test-claim-loop.ts b/packages/taler-integrationtests/src/test-claim-loop.ts
deleted file mode 100644
index 8c4df8740..000000000
--- a/packages/taler-integrationtests/src/test-claim-loop.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- 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,
- MerchantPrivateApi,
- WalletCli,
-} from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import { URL } from "url";
-
-/**
- * Run test for the merchant's order lifecycle.
- *
- * FIXME: Is this test still necessary? We initially wrote if to confirm/document
- * assumptions about how the merchant should work.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- // Query private order status before claiming it.
- let orderStatusBefore = await MerchantPrivateApi.queryPrivateOrderStatus(
- merchant,
- {
- orderId: orderResp.order_id,
- },
- );
- t.assertTrue(orderStatusBefore.order_status === "unpaid");
- let statusUrlBefore = new URL(orderStatusBefore.order_status_url);
-
- // Make wallet claim the unpaid order.
- t.assertTrue(orderStatusBefore.order_status === "unpaid");
- const talerPayUri = orderStatusBefore.taler_pay_uri;
- const y = await wallet.preparePay({
- talerPayUri,
- });
-
- // Query private order status after claiming it.
- let orderStatusAfter = await MerchantPrivateApi.queryPrivateOrderStatus(
- merchant,
- {
- orderId: orderResp.order_id,
- },
- );
- t.assertTrue(orderStatusAfter.order_status === "claimed");
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-exchange-management.ts b/packages/taler-integrationtests/src/test-exchange-management.ts
deleted file mode 100644
index be990d9b6..000000000
--- a/packages/taler-integrationtests/src/test-exchange-management.ts
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- 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,
- WalletCli,
- setupDb,
- BankService,
- ExchangeService,
- MerchantService,
- BankApi,
- BankAccessApi,
-} from "./harness";
-import {
- PreparePayResultType,
- ExchangesListRespose,
- URL,
- TalerErrorCode,
-} from "taler-wallet-core";
-import {
- FaultInjectedExchangeService,
- FaultInjectionResponseContext,
-} from "./faultInjection";
-import { defaultCoinConfig } from "./denomStructures";
-
-/**
- * Test if the wallet handles outdated exchange versions correct.y
- */
-runTest(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,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
- exchange.addBankAccount("1", exchangeBankAccount);
-
- const faultyExchange = new FaultInjectedExchangeService(t, exchange, 8091);
-
- bank.setSuggestedExchange(
- faultyExchange,
- exchangeBankAccount.accountPaytoUri,
- );
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- exchange.addOfferedCoins(defaultCoinConfig);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- 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!");
-
- /*
- * =========================================================================
- * Check that the exchange can be added to the wallet
- * (without any faults active).
- * =========================================================================
- */
-
- const wallet = new WalletCli(t);
-
- let exchangesList: ExchangesListRespose;
-
- exchangesList = await wallet.listExchanges();
- t.assertTrue(exchangesList.exchanges.length === 0);
-
- // Try before fault is injected
- await wallet.addExchange({
- exchangeBaseUrl: faultyExchange.baseUrl,
- });
-
- exchangesList = await wallet.listExchanges();
- t.assertTrue(exchangesList.exchanges.length === 1);
-
- await wallet.addExchange({
- exchangeBaseUrl: faultyExchange.baseUrl,
- });
-
- console.log("listing exchanges");
-
- exchangesList = await wallet.listExchanges();
- t.assertTrue(exchangesList.exchanges.length === 1);
-
- console.log("got list", exchangesList);
-
- /*
- * =========================================================================
- * Check what happens if the exchange returns something totally
- * bogus for /keys.
- * =========================================================================
- */
-
- wallet.deleteDatabase();
-
- exchangesList = await wallet.listExchanges();
- t.assertTrue(exchangesList.exchanges.length === 0);
-
- faultyExchange.faultProxy.addFault({
- modifyResponse(ctx: FaultInjectionResponseContext) {
- const url = new URL(ctx.request.requestUrl);
- if (url.pathname === "/keys") {
- const body = {
- version: "whaaat",
- };
- ctx.responseBody = Buffer.from(JSON.stringify(body), "utf-8");
- }
- },
- });
-
- const err1 = await t.assertThrowsOperationErrorAsync(async () => {
- await wallet.addExchange({
- exchangeBaseUrl: faultyExchange.baseUrl,
- });
- });
-
- // Response is malformed, since it didn't even contain a version code
- // in a format the wallet can understand.
- t.assertTrue(
- err1.operationError.code ===
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- );
-
- exchangesList = await wallet.listExchanges();
- t.assertTrue(exchangesList.exchanges.length === 0);
-
- /*
- * =========================================================================
- * Check what happens if the exchange returns an old, unsupported
- * version for /keys
- * =========================================================================
- */
-
- wallet.deleteDatabase();
- faultyExchange.faultProxy.clearAllFaults();
-
- faultyExchange.faultProxy.addFault({
- modifyResponse(ctx: FaultInjectionResponseContext) {
- const url = new URL(ctx.request.requestUrl);
- if (url.pathname === "/keys") {
- const keys = ctx.responseBody?.toString("utf-8");
- t.assertTrue(keys != null);
- const keysJson = JSON.parse(keys);
- keysJson["version"] = "2:0:0";
- ctx.responseBody = Buffer.from(JSON.stringify(keysJson), "utf-8");
- }
- },
- });
-
- const err2 = await t.assertThrowsOperationErrorAsync(async () => {
- await wallet.addExchange({
- exchangeBaseUrl: faultyExchange.baseUrl,
- });
- });
-
- t.assertTrue(
- err2.operationError.code ===
- TalerErrorCode.WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE,
- );
-
- exchangesList = await wallet.listExchanges();
- t.assertTrue(exchangesList.exchanges.length === 0);
-
- /*
- * =========================================================================
- * Check that the exchange version is also checked when
- * the exchange is implicitly added via the suggested
- * exchange of a bank-integrated withdrawal.
- * =========================================================================
- */
-
- // Fault from above is still active!
-
- // Create withdrawal operation
-
- const user = await BankApi.createRandomBankUser(bank);
- const wop = await BankAccessApi.createWithdrawalOperation(
- bank,
- user,
- "TESTKUDOS:10",
- );
-
- // Hand it to the wallet
-
- const wd = await wallet.getWithdrawalDetailsForUri({
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
-
- // Make sure the faulty exchange isn't used for the suggestion.
- t.assertTrue(wd.possibleExchanges.length === 0);
-});
diff --git a/packages/taler-integrationtests/src/test-fee-regression.ts b/packages/taler-integrationtests/src/test-fee-regression.ts
deleted file mode 100644
index 7b3193df2..000000000
--- a/packages/taler-integrationtests/src/test-fee-regression.ts
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- 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 { defaultCoinConfig } from "./denomStructures";
-import {
- runTest,
- GlobalTestState,
- BankService,
- ExchangeService,
- MerchantService,
- setupDb,
- WalletCli,
-} from "./harness";
-import {
- withdrawViaBank,
- makeTestPayment,
- SimpleTestEnvironment,
-} from "./helpers";
-
-/**
- * Run a test case with a simple TESTKUDOS Taler environment, consisting
- * of one exchange, one bank and one merchant.
- */
-export async function createMyTestkudosEnvironment(
- t: GlobalTestState,
-): Promise<SimpleTestEnvironment> {
- const db = await setupDb(t);
-
- const bank = await BankService.create(t, {
- allowRegistrations: true,
- currency: "TESTKUDOS",
- database: db.connStr,
- httpPort: 8082,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
- exchange.addBankAccount("1", exchangeBankAccount);
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- const coinCommon = {
- durationLegal: "3 years",
- durationSpend: "2 years",
- durationWithdraw: "7 days",
- rsaKeySize: 1024,
- feeDeposit: "TESTKUDOS:0.0025",
- feeWithdraw: "TESTKUDOS:0",
- feeRefresh: "TESTKUDOS:0",
- feeRefund: "TESTKUDOS:0",
- };
-
- exchange.addCoinConfigList([
- {
- ...coinCommon,
- name: "c1",
- value: "TESTKUDOS:1.28",
- },
- {
- ...coinCommon,
- name: "c2",
- value: "TESTKUDOS:0.64",
- },
- {
- ...coinCommon,
- name: "c3",
- value: "TESTKUDOS:0.32",
- },
- {
- ...coinCommon,
- name: "c4",
- value: "TESTKUDOS:0.16",
- },
- {
- ...coinCommon,
- name: "c5",
- value: "TESTKUDOS:0.08",
- },
- {
- ...coinCommon,
- name: "c5",
- value: "TESTKUDOS:0.04",
- },
- {
- ...coinCommon,
- name: "c6",
- value: "TESTKUDOS:0.02",
- },
- {
- ...coinCommon,
- name: "c7",
- value: "TESTKUDOS:0.01",
- },
- ]);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- 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!");
-
- const wallet = new WalletCli(t);
-
- return {
- commonDb: db,
- exchange,
- merchant,
- wallet,
- bank,
- exchangeBankAccount,
- };
-}
-
-/**
- * Run test for basic, bank-integrated withdrawal and payment.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createMyTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, {
- wallet,
- bank,
- exchange,
- amount: "TESTKUDOS:1.92",
- });
-
- const coins = await wallet.dumpCoins();
-
- // Make sure we really withdraw one 0.64 and one 1.28 coin.
- t.assertTrue(coins.coins.length === 2);
-
- const order = {
- summary: "Buy me!",
- amount: "TESTKUDOS:1.30",
- fulfillment_url: "taler://fulfillment-success/thx",
- };
-
- await makeTestPayment(t, { wallet, merchant, order });
-
- await wallet.runUntilDone();
-
- const txs = await wallet.getTransactions();
- t.assertAmountEquals(txs.transactions[1].amountEffective, "TESTKUDOS:1.30");
- console.log(txs);
-});
diff --git a/packages/taler-integrationtests/src/test-merchant-longpolling.ts b/packages/taler-integrationtests/src/test-merchant-longpolling.ts
deleted file mode 100644
index 5189d247e..000000000
--- a/packages/taler-integrationtests/src/test-merchant-longpolling.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import {
- PreparePayResultType,
- codecForMerchantOrderStatusUnpaid,
- ConfirmPayResultType,
- URL,
-} from "taler-wallet-core";
-import axios from "axios";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- /**
- * =========================================================================
- * Create an order and let the wallet pay under a session ID
- *
- * We check along the way that the JSON response to /orders/{order_id}
- * returns the right thing.
- * =========================================================================
- */
-
- let orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "https://example.com/article42",
- },
- });
-
- const firstOrderId = orderResp.order_id;
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- sessionId: "mysession-one",
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- t.assertTrue(orderStatus.already_paid_order_id === undefined);
- let publicOrderStatusUrl = new URL(orderStatus.order_status_url);
-
- // Wait for half a second seconds!
- publicOrderStatusUrl.searchParams.set("timeout_ms", "500");
-
- let publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (before claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- let pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- console.log(pubUnpaidStatus);
-
- /**
- * =========================================================================
- * Now actually pay, but WHILE a long poll is active!
- * =========================================================================
- */
-
- publicOrderStatusUrl.searchParams.set("timeout_ms", "5000");
-
- let publicOrderStatusPromise = axios.get(publicOrderStatusUrl.href, {
- validateStatus: () => true,
- });
-
- let preparePayResp = await wallet.preparePay({
- talerPayUri: pubUnpaidStatus.taler_pay_uri,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.PaymentPossible);
-
- const proposalId = preparePayResp.proposalId;
-
- publicOrderStatusResp = await publicOrderStatusPromise;
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (after claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- const confirmPayRes = await wallet.confirmPay({
- proposalId: proposalId,
- });
-
- t.assertTrue(confirmPayRes.type === ConfirmPayResultType.Done);
-});
diff --git a/packages/taler-integrationtests/src/test-merchant-refund-api.ts b/packages/taler-integrationtests/src/test-merchant-refund-api.ts
deleted file mode 100644
index 121c571d2..000000000
--- a/packages/taler-integrationtests/src/test-merchant-refund-api.ts
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- 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,
- MerchantPrivateApi,
- MerchantService,
- BankServiceInterface,
- MerchantServiceInterface,
- WalletCli,
- ExchangeServiceInterface,
-} from "./harness";
-import {
- createSimpleTestkudosEnvironment,
- withdrawViaBank,
- SimpleTestEnvironment,
-} from "./helpers";
-import { durationFromSpec, PreparePayResultType, URL } from "taler-wallet-core";
-import axios from "axios";
-
-async function testRefundApiWithFulfillmentUrl(
- t: GlobalTestState,
- env: {
- merchant: MerchantServiceInterface;
- bank: BankServiceInterface;
- wallet: WalletCli;
- exchange: ExchangeServiceInterface;
- },
-): Promise<void> {
- const { wallet, bank, exchange, merchant } = env;
-
- // Set up order.
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "https://example.com/fulfillment",
- },
- refund_delay: durationFromSpec({ minutes: 5 }),
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- const talerPayUri = orderStatus.taler_pay_uri;
- const orderId = orderResp.order_id;
-
- // Make wallet pay for the order
-
- let preparePayResult = await wallet.preparePay({
- talerPayUri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.PaymentPossible,
- );
-
- const r2 = await wallet.apiRequest("confirmPay", {
- proposalId: preparePayResult.proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- preparePayResult = await wallet.preparePay({
- talerPayUri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.AlreadyConfirmed,
- );
-
- await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:5",
- instance: "default",
- justification: "foo",
- orderId: orderResp.order_id,
- });
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- t.assertAmountEquals(orderStatus.refund_amount, "TESTKUDOS:5");
-
- // Now test what the merchant gives as a response for various requests to the
- // public order status URL!
-
- let publicOrderStatusUrl = new URL(
- `orders/${orderId}`,
- merchant.makeInstanceBaseUrl(),
- );
- publicOrderStatusUrl.searchParams.set(
- "h_contract",
- preparePayResult.contractTermsHash,
- );
-
- let publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
- validateStatus: () => true,
- });
- console.log(publicOrderStatusResp.data);
- t.assertTrue(publicOrderStatusResp.status === 200);
- t.assertAmountEquals(publicOrderStatusResp.data.refund_amount, "TESTKUDOS:5");
-
- publicOrderStatusUrl = new URL(
- `orders/${orderId}`,
- merchant.makeInstanceBaseUrl(),
- );
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
- validateStatus: () => true,
- });
- console.log(publicOrderStatusResp.data);
- // We didn't give any authentication, so we should get a fulfillment URL back
- t.assertTrue(publicOrderStatusResp.status === 202);
- const fu = publicOrderStatusResp.data.fulfillment_url;
- t.assertTrue(typeof fu === "string" && fu.startsWith("https://example.com"));
-}
-
-async function testRefundApiWithFulfillmentMessage(
- t: GlobalTestState,
- env: {
- merchant: MerchantServiceInterface;
- bank: BankServiceInterface;
- wallet: WalletCli;
- exchange: ExchangeServiceInterface;
- },
-): Promise<void> {
- const { wallet, bank, exchange, merchant } = env;
-
- // Set up order.
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_message: "Thank you for buying foobar",
- },
- refund_delay: durationFromSpec({ minutes: 5 }),
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- const talerPayUri = orderStatus.taler_pay_uri;
- const orderId = orderResp.order_id;
-
- // Make wallet pay for the order
-
- let preparePayResult = await wallet.preparePay({
- talerPayUri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.PaymentPossible,
- );
-
- const r2 = await wallet.apiRequest("confirmPay", {
- proposalId: preparePayResult.proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- preparePayResult = await wallet.preparePay({
- talerPayUri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.AlreadyConfirmed,
- );
-
- await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:5",
- instance: "default",
- justification: "foo",
- orderId: orderResp.order_id,
- });
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- t.assertAmountEquals(orderStatus.refund_amount, "TESTKUDOS:5");
-
- // Now test what the merchant gives as a response for various requests to the
- // public order status URL!
-
- let publicOrderStatusUrl = new URL(
- `orders/${orderId}`,
- merchant.makeInstanceBaseUrl(),
- );
- publicOrderStatusUrl.searchParams.set(
- "h_contract",
- preparePayResult.contractTermsHash,
- );
-
- let publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
- validateStatus: () => true,
- });
- console.log(publicOrderStatusResp.data);
- t.assertTrue(publicOrderStatusResp.status === 200);
- t.assertAmountEquals(publicOrderStatusResp.data.refund_amount, "TESTKUDOS:5");
-
- publicOrderStatusUrl = new URL(
- `orders/${orderId}`,
- merchant.makeInstanceBaseUrl(),
- );
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl.href, {
- validateStatus: () => true,
- });
- console.log(publicOrderStatusResp.data);
- // We didn't give any authentication, so we should get a fulfillment URL back
- t.assertTrue(publicOrderStatusResp.status === 403);
-}
-
-/**
- * Test case for the refund API of the merchant backend.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- await testRefundApiWithFulfillmentUrl(t, {
- wallet,
- bank,
- exchange,
- merchant,
- });
-
- await testRefundApiWithFulfillmentMessage(t, {
- wallet,
- bank,
- exchange,
- merchant,
- });
-});
diff --git a/packages/taler-integrationtests/src/test-pay-abort.ts b/packages/taler-integrationtests/src/test-pay-abort.ts
deleted file mode 100644
index 566500091..000000000
--- a/packages/taler-integrationtests/src/test-pay-abort.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Fault injection test to check aborting partial payment
- * via refunds.
- */
-
-/**
- * Imports.
- */
-import {
- runTest,
- GlobalTestState,
- MerchantService,
- ExchangeService,
- setupDb,
- BankService,
- WalletCli,
- MerchantPrivateApi,
- BankApi,
- BankAccessApi,
-} from "./harness";
-import {
- FaultInjectedExchangeService,
- FaultInjectionRequestContext,
- FaultInjectionResponseContext,
-} from "./faultInjection";
-import { PreparePayResultType, URL, TalerErrorCode } from "taler-wallet-core";
-import { defaultCoinConfig } from "./denomStructures";
-import { withdrawViaBank, makeTestPayment } from "./helpers";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(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,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- await exchange.addBankAccount("1", exchangeBankAccount);
- exchange.addOfferedCoins(defaultCoinConfig);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- const faultyExchange = new FaultInjectedExchangeService(t, exchange, 8091);
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- merchant.addExchange(faultyExchange);
-
- await merchant.start();
- await merchant.pingUntilAvailable();
-
- await merchant.addInstance({
- id: "default",
- name: "Default Instance",
- paytoUris: [`payto://x-taler-bank/merchant-default`],
- });
-
- console.log("setup done!");
-
- const wallet = new WalletCli(t);
-
- // Create withdrawal operation
-
- await withdrawViaBank(t, {
- wallet,
- exchange: faultyExchange,
- amount: "TESTKUDOS:20",
- bank,
- });
-
- // faultyExchange.faultProxy.addFault({
- // modifyRequest(ctx: FaultInjectionRequestContext) {
- // console.log("proxy request to", ctx.requestUrl);
- // }
- // });
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:15",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const preparePayResult = await wallet.preparePay({
- talerPayUri: orderStatus.taler_pay_uri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.PaymentPossible,
- );
-
- // We let only the first deposit through!
- let firstDepositUrl: string | undefined;
-
- faultyExchange.faultProxy.addFault({
- modifyRequest(ctx: FaultInjectionRequestContext) {
- const url = new URL(ctx.requestUrl);
- if (url.pathname.endsWith("/deposit")) {
- if (!firstDepositUrl) {
- firstDepositUrl = url.href;
- return;
- }
- if (url.href != firstDepositUrl) {
- url.pathname = "/doesntexist";
- ctx.requestUrl = url.href;
- }
- }
- },
- modifyResponse(ctx: FaultInjectionResponseContext) {
- const url = new URL(ctx.request.requestUrl);
- if (url.pathname.endsWith("/deposit") && url.href != firstDepositUrl) {
- ctx.responseBody = Buffer.from("{}");
- ctx.statusCode = 500;
- }
- },
- });
-
- await t.assertThrowsOperationErrorAsync(async () => {
- await wallet.confirmPay({
- proposalId: preparePayResult.proposalId,
- });
- });
-
- let txr = await wallet.getTransactions();
- console.log(JSON.stringify(txr, undefined, 2));
-
- t.assertDeepEqual(txr.transactions[1].type, "payment");
- t.assertDeepEqual(txr.transactions[1].pending, true);
- t.assertDeepEqual(
- txr.transactions[1].error?.code,
- TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
- );
-
- await wallet.abortFailedPayWithRefund({
- proposalId: preparePayResult.proposalId,
- });
-
- await wallet.runUntilDone();
-
- txr = await wallet.getTransactions();
- console.log(JSON.stringify(txr, undefined, 2));
-
- const txTypes = txr.transactions.map((x) => x.type);
-
- t.assertDeepEqual(txTypes, ["withdrawal", "payment", "refund"]);
-});
diff --git a/packages/taler-integrationtests/src/test-pay-paid.ts b/packages/taler-integrationtests/src/test-pay-paid.ts
deleted file mode 100644
index 40f7d014f..000000000
--- a/packages/taler-integrationtests/src/test-pay-paid.ts
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import {
- withdrawViaBank,
- createFaultInjectedMerchantTestkudosEnvironment,
-} from "./helpers";
-import {
- PreparePayResultType,
- codecForMerchantOrderStatusUnpaid,
- ConfirmPayResultType,
- URL,
-} from "taler-wallet-core";
-import axios from "axios";
-import { FaultInjectionRequestContext } from "./faultInjection";
-
-/**
- * Run test for the wallets repurchase detection mechanism
- * based on the fulfillment URL.
- *
- * FIXME: This test is now almost the same as test-paywall-flow,
- * since we can't initiate payment via a "claimed" private order status
- * response.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- faultyMerchant,
- } = await createFaultInjectedMerchantTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- /**
- * =========================================================================
- * Create an order and let the wallet pay under a session ID
- *
- * We check along the way that the JSON response to /orders/{order_id}
- * returns the right thing.
- * =========================================================================
- */
-
- const merchant = faultyMerchant;
-
- let orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "https://example.com/article42",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- sessionId: "mysession-one",
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- t.assertTrue(orderStatus.already_paid_order_id === undefined);
- let publicOrderStatusUrl = orderStatus.order_status_url;
-
- let publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (before claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- let pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- console.log(pubUnpaidStatus);
-
- let preparePayResp = await wallet.preparePay({
- talerPayUri: pubUnpaidStatus.taler_pay_uri,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.PaymentPossible);
-
- const proposalId = preparePayResp.proposalId;
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (after claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- const confirmPayRes = await wallet.confirmPay({
- proposalId: proposalId,
- });
-
- t.assertTrue(confirmPayRes.type === ConfirmPayResultType.Done);
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- console.log(publicOrderStatusResp.data);
-
- if (publicOrderStatusResp.status != 202) {
- console.log(publicOrderStatusResp.data);
- throw Error(
- `expected status 202 (after paying), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- /**
- * =========================================================================
- * Now change up the session ID and do payment re-play!
- * =========================================================================
- */
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- sessionId: "mysession-two",
- });
-
- console.log(
- "order status under mysession-two:",
- JSON.stringify(orderStatus, undefined, 2),
- );
-
- // Should be claimed (not paid!) because of a new session ID
- t.assertTrue(orderStatus.order_status === "claimed");
-
- let numPayRequested = 0;
- let numPaidRequested = 0;
-
- faultyMerchant.faultProxy.addFault({
- modifyRequest(ctx: FaultInjectionRequestContext) {
- const url = new URL(ctx.requestUrl);
- if (url.pathname.endsWith("/pay")) {
- numPayRequested++;
- } else if (url.pathname.endsWith("/paid")) {
- numPaidRequested++;
- }
- },
- });
-
- let orderRespTwo = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "https://example.com/article42",
- },
- });
-
- let orderStatusTwo = await MerchantPrivateApi.queryPrivateOrderStatus(
- merchant,
- {
- orderId: orderRespTwo.order_id,
- sessionId: "mysession-two",
- },
- );
-
- t.assertTrue(orderStatusTwo.order_status === "unpaid");
-
- // Pay with new taler://pay URI, which should
- // have the new session ID!
- // Wallet should now automatically re-play payment.
- preparePayResp = await wallet.preparePay({
- talerPayUri: orderStatusTwo.taler_pay_uri,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.AlreadyConfirmed);
- t.assertTrue(preparePayResp.paid);
-
- // Make sure the wallet is actually doing the replay properly.
- t.assertTrue(numPaidRequested == 1);
- t.assertTrue(numPayRequested == 0);
-});
diff --git a/packages/taler-integrationtests/src/test-payment-claim.ts b/packages/taler-integrationtests/src/test-payment-claim.ts
deleted file mode 100644
index 6aed7e9e1..000000000
--- a/packages/taler-integrationtests/src/test-payment-claim.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- 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,
- MerchantPrivateApi,
- WalletCli,
-} from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import { PreparePayResultType, TalerErrorCode } from "taler-wallet-core";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- const walletTwo = new WalletCli(t, "two");
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- const talerPayUri = orderStatus.taler_pay_uri;
-
- // Make wallet pay for the order
-
- const preparePayResult = await wallet.preparePay({
- talerPayUri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.PaymentPossible,
- );
-
- t.assertThrowsOperationErrorAsync(async () => {
- await walletTwo.preparePay({
- talerPayUri,
- });
- });
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: preparePayResult.proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- walletTwo.deleteDatabase();
-
- const err = await t.assertThrowsOperationErrorAsync(async () => {
- await walletTwo.preparePay({
- talerPayUri,
- });
- });
-
- t.assertTrue(
- err.operationError.code === TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED,
- );
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-payment-fault.ts b/packages/taler-integrationtests/src/test-payment-fault.ts
deleted file mode 100644
index ca31e8eeb..000000000
--- a/packages/taler-integrationtests/src/test-payment-fault.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Sample fault injection test.
- */
-
-/**
- * Imports.
- */
-import {
- runTest,
- GlobalTestState,
- MerchantService,
- ExchangeService,
- setupDb,
- BankService,
- WalletCli,
- MerchantPrivateApi,
- BankApi,
- BankAccessApi,
-} from "./harness";
-import {
- FaultInjectedExchangeService,
- FaultInjectionRequestContext,
- FaultInjectionResponseContext,
-} from "./faultInjection";
-import { CoreApiResponse } from "taler-wallet-core";
-import { defaultCoinConfig } from "./denomStructures";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(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,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- await exchange.addBankAccount("1", exchangeBankAccount);
- exchange.addOfferedCoins(defaultCoinConfig);
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- const faultyExchange = new FaultInjectedExchangeService(t, exchange, 8091);
-
- // Print all requests to the exchange
- faultyExchange.faultProxy.addFault({
- modifyRequest(ctx: FaultInjectionRequestContext) {
- console.log("got request", ctx);
- },
- modifyResponse(ctx: FaultInjectionResponseContext) {
- console.log("got response", ctx);
- },
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- merchant.addExchange(faultyExchange);
-
- await merchant.start();
- await merchant.pingUntilAvailable();
-
- await merchant.addInstance({
- id: "default",
- name: "Default Instance",
- paytoUris: [`payto://x-taler-bank/merchant-default`],
- });
-
- console.log("setup done!");
-
- const wallet = new WalletCli(t);
-
- // Create withdrawal operation
-
- const user = await BankApi.createRandomBankUser(bank);
- const wop = await BankAccessApi.createWithdrawalOperation(
- bank,
- user,
- "TESTKUDOS:20",
- );
-
- // Hand it to the wallet
-
- const r1 = await wallet.apiRequest("getWithdrawalDetailsForUri", {
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r1.type === "response");
-
- await wallet.runPending();
-
- // Confirm it
-
- await BankApi.confirmWithdrawalOperation(bank, user, wop);
-
- // Withdraw
-
- const r2 = await wallet.apiRequest("acceptBankIntegratedWithdrawal", {
- exchangeBaseUrl: faultyExchange.baseUrl,
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r2.type === "response");
- await wallet.runUntilDone();
-
- // Check balance
-
- const balApiResp = await wallet.apiRequest("getBalances", {});
- t.assertTrue(balApiResp.type === "response");
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- let apiResp: CoreApiResponse;
-
- apiResp = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(apiResp.type === "response");
-
- const proposalId = (apiResp.result as any).proposalId;
-
- await wallet.runPending();
-
- // Drop 3 responses from the exchange.
- let faultCount = 0;
- faultyExchange.faultProxy.addFault({
- modifyResponse(ctx: FaultInjectionResponseContext) {
- if (faultCount < 3) {
- faultCount++;
- ctx.dropResponse = true;
- }
- },
- });
-
- // confirmPay won't work, as the exchange is unreachable
-
- apiResp = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: proposalId,
- });
- t.assertTrue(apiResp.type === "error");
-
- await wallet.runUntilDone();
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-});
diff --git a/packages/taler-integrationtests/src/test-payment-idempotency.ts b/packages/taler-integrationtests/src/test-payment-idempotency.ts
deleted file mode 100644
index 85be04d59..000000000
--- a/packages/taler-integrationtests/src/test-payment-idempotency.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import { PreparePayResultType } from "taler-wallet-core";
-
-/**
- * Test the wallet-core payment API, especially that repeated operations
- * return the expected result.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- const talerPayUri = orderStatus.taler_pay_uri;
-
- // Make wallet pay for the order
-
- const preparePayResult = await wallet.preparePay({
- talerPayUri: orderStatus.taler_pay_uri,
- });
-
- const preparePayResultRep = await wallet.preparePay({
- talerPayUri: orderStatus.taler_pay_uri,
- });
-
- t.assertTrue(
- preparePayResult.status === PreparePayResultType.PaymentPossible,
- );
- t.assertTrue(
- preparePayResultRep.status === PreparePayResultType.PaymentPossible,
- );
-
- const proposalId = preparePayResult.proposalId;
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- const preparePayResultAfter = await wallet.preparePay({
- talerPayUri,
- });
-
- t.assertTrue(
- preparePayResultAfter.status === PreparePayResultType.AlreadyConfirmed,
- );
- t.assertTrue(preparePayResultAfter.paid === true);
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-payment-multiple.ts b/packages/taler-integrationtests/src/test-payment-multiple.ts
deleted file mode 100644
index c6a0868af..000000000
--- a/packages/taler-integrationtests/src/test-payment-multiple.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- 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,
- setupDb,
- BankService,
- ExchangeService,
- MerchantService,
- WalletCli,
- MerchantPrivateApi,
-} from "./harness";
-import { withdrawViaBank } from "./helpers";
-import { coin_ct10, coin_u1 } from "./denomStructures";
-
-async function setupTest(
- t: GlobalTestState,
-): Promise<{
- merchant: MerchantService;
- exchange: ExchangeService;
- bank: BankService;
-}> {
- const db = await setupDb(t);
-
- const bank = await BankService.create(t, {
- allowRegistrations: true,
- currency: "TESTKUDOS",
- database: db.connStr,
- httpPort: 8082,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
-
- exchange.addOfferedCoins([coin_ct10, coin_u1]);
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- await exchange.addBankAccount("1", exchangeBankAccount);
-
- 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!");
-
- 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.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:100" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:80",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const r1 = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(r1.type === "response");
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: (r1.result as any).proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-payment-transient.ts b/packages/taler-integrationtests/src/test-payment-transient.ts
deleted file mode 100644
index dc7ebbb1d..000000000
--- a/packages/taler-integrationtests/src/test-payment-transient.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import {
- withdrawViaBank,
- createFaultInjectedMerchantTestkudosEnvironment,
-} from "./helpers";
-import {
- PreparePayResultType,
- codecForMerchantOrderStatusUnpaid,
- ConfirmPayResultType,
- URL,
- codecForExchangeKeysJson,
- TalerErrorDetails,
- TalerErrorCode,
-} from "taler-wallet-core";
-import axios from "axios";
-import {
- FaultInjectionRequestContext,
- FaultInjectionResponseContext,
-} from "./faultInjection";
-
-/**
- * Run test for a payment where the merchant has a transient
- * failure in /pay
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- faultyMerchant,
- } = await createFaultInjectedMerchantTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- const merchant = faultyMerchant;
-
- let orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "https://example.com/article42",
- },
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- sessionId: "mysession-one",
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- t.assertTrue(orderStatus.already_paid_order_id === undefined);
- let publicOrderStatusUrl = orderStatus.order_status_url;
-
- let publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (before claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- let pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- console.log(pubUnpaidStatus);
-
- let preparePayResp = await wallet.preparePay({
- talerPayUri: pubUnpaidStatus.taler_pay_uri,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.PaymentPossible);
-
- const proposalId = preparePayResp.proposalId;
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (after claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- let faultInjected = false;
-
- faultyMerchant.faultProxy.addFault({
- modifyResponse(ctx: FaultInjectionResponseContext) {
- console.log("in modifyResponse");
- const url = new URL(ctx.request.requestUrl);
- console.log("pathname is", url.pathname);
- if (!url.pathname.endsWith("/pay")) {
- return;
- }
- if (faultInjected) {
- console.log("not injecting pay fault");
- return;
- }
- faultInjected = true;
- console.log("injecting pay fault");
- const err: TalerErrorDetails = {
- code: TalerErrorCode.GENERIC_DB_COMMIT_FAILED,
- details: {},
- hint: "huh",
- message: "something went wrong",
- };
- ctx.responseBody = Buffer.from(JSON.stringify(err));
- ctx.statusCode = 500;
- },
- });
-
- const confirmPayResp = await wallet.confirmPay({
- proposalId,
- });
-
- console.log(confirmPayResp);
-
- t.assertTrue(confirmPayResp.type === ConfirmPayResultType.Pending);
- t.assertTrue(faultInjected);
-
- const confirmPayRespTwo = await wallet.confirmPay({
- proposalId,
- });
-
- t.assertTrue(confirmPayRespTwo.type === ConfirmPayResultType.Done);
-
- // Now ask the merchant if paid
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- console.log(publicOrderStatusResp.data);
-
- if (publicOrderStatusResp.status != 202) {
- console.log(publicOrderStatusResp.data);
- throw Error(
- `expected status 202 (after paying), but got ${publicOrderStatusResp.status}`,
- );
- }
-});
diff --git a/packages/taler-integrationtests/src/test-payment.ts b/packages/taler-integrationtests/src/test-payment.ts
deleted file mode 100644
index 8a1240dab..000000000
--- a/packages/taler-integrationtests/src/test-payment.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- 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,
- withdrawViaBank,
- makeTestPayment,
-} from "./helpers";
-
-/**
- * Run test for basic, bank-integrated withdrawal and payment.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- const order = {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- };
-
- await makeTestPayment(t, { wallet, merchant, order });
-
- await wallet.runUntilDone();
-});
diff --git a/packages/taler-integrationtests/src/test-paywall-flow.ts b/packages/taler-integrationtests/src/test-paywall-flow.ts
deleted file mode 100644
index 54c8ab463..000000000
--- a/packages/taler-integrationtests/src/test-paywall-flow.ts
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import {
- PreparePayResultType,
- codecForMerchantOrderStatusUnpaid,
- ConfirmPayResultType,
-} from "taler-wallet-core";
-import axios from "axios";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- /**
- * =========================================================================
- * Create an order and let the wallet pay under a session ID
- *
- * We check along the way that the JSON response to /orders/{order_id}
- * returns the right thing.
- * =========================================================================
- */
-
- let orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "https://example.com/article42",
- },
- });
-
- const firstOrderId = orderResp.order_id;
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- sessionId: "mysession-one",
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- const talerPayUriOne = orderStatus.taler_pay_uri;
-
- t.assertTrue(orderStatus.already_paid_order_id === undefined);
- let publicOrderStatusUrl = orderStatus.order_status_url;
-
- let publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (before claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- let pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- console.log(pubUnpaidStatus);
-
- let preparePayResp = await wallet.preparePay({
- talerPayUri: pubUnpaidStatus.taler_pay_uri,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.PaymentPossible);
-
- const proposalId = preparePayResp.proposalId;
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(
- `expected status 402 (after claiming), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- const confirmPayRes = await wallet.confirmPay({
- proposalId: proposalId,
- });
-
- t.assertTrue(confirmPayRes.type === ConfirmPayResultType.Done);
-
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- console.log(publicOrderStatusResp.data);
-
- if (publicOrderStatusResp.status != 202) {
- console.log(publicOrderStatusResp.data);
- throw Error(
- `expected status 202 (after paying), but got ${publicOrderStatusResp.status}`,
- );
- }
-
- /**
- * =========================================================================
- * Now change up the session ID!
- * =========================================================================
- */
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- sessionId: "mysession-two",
- });
-
- // Should be claimed (not paid!) because of a new session ID
- t.assertTrue(orderStatus.order_status === "claimed");
-
- // Pay with new taler://pay URI, which should
- // have the new session ID!
- // Wallet should now automatically re-play payment.
- preparePayResp = await wallet.preparePay({
- talerPayUri: talerPayUriOne,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.AlreadyConfirmed);
- t.assertTrue(preparePayResp.paid);
-
- /**
- * =========================================================================
- * Now we test re-purchase detection.
- * =========================================================================
- */
-
- orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- // Same fulfillment URL as previously!
- fulfillment_url: "https://example.com/article42",
- },
- });
-
- const secondOrderId = orderResp.order_id;
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: secondOrderId,
- sessionId: "mysession-three",
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- t.assertTrue(orderStatus.already_paid_order_id === undefined);
- publicOrderStatusUrl = orderStatus.order_status_url;
-
- // Here the re-purchase detection should kick in,
- // and the wallet should re-pay for the old order
- // under the new session ID (mysession-three).
- preparePayResp = await wallet.preparePay({
- talerPayUri: orderStatus.taler_pay_uri,
- });
-
- t.assertTrue(preparePayResp.status === PreparePayResultType.AlreadyConfirmed);
- t.assertTrue(preparePayResp.paid);
-
- // The first order should now be paid under "mysession-three",
- // as the wallet did re-purchase detection
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: firstOrderId,
- sessionId: "mysession-three",
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- // Check that with a completely new session ID, the status would NOT
- // be paid.
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: firstOrderId,
- sessionId: "mysession-four",
- });
-
- t.assertTrue(orderStatus.order_status === "claimed");
-
- // Now check if the public status of the new order is correct.
-
- console.log("requesting public status", publicOrderStatusUrl);
-
- // Ask the order status of the claimed-but-unpaid order
- publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
- validateStatus: () => true,
- });
-
- if (publicOrderStatusResp.status != 402) {
- throw Error(`expected status 402, but got ${publicOrderStatusResp.status}`);
- }
-
- pubUnpaidStatus = codecForMerchantOrderStatusUnpaid().decode(
- publicOrderStatusResp.data,
- );
-
- console.log(publicOrderStatusResp.data);
-
- t.assertTrue(pubUnpaidStatus.already_paid_order_id === firstOrderId);
-});
diff --git a/packages/taler-integrationtests/src/test-refund-auto.ts b/packages/taler-integrationtests/src/test-refund-auto.ts
deleted file mode 100644
index 1a7055fd4..000000000
--- a/packages/taler-integrationtests/src/test-refund-auto.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import { CoreApiResponse, durationFromSpec } from "taler-wallet-core";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- auto_refund: {
- d_ms: 3000,
- },
- },
- refund_delay: durationFromSpec({ minutes: 5 }),
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const r1 = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(r1.type === "response");
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: (r1.result as any).proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- const ref = await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:5",
- instance: "default",
- justification: "foo",
- orderId: orderResp.order_id,
- });
-
- console.log(ref);
-
- // The wallet should now automatically pick up the refund.
- await wallet.runUntilDone();
-
- const transactions = await wallet.getTransactions();
- console.log(JSON.stringify(transactions, undefined, 2));
-
- const transactionTypes = transactions.transactions.map((x) => x.type);
- t.assertDeepEqual(transactionTypes, ["withdrawal", "payment", "refund"]);
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-refund-gone.ts b/packages/taler-integrationtests/src/test-refund-gone.ts
deleted file mode 100644
index 764d5c28d..000000000
--- a/packages/taler-integrationtests/src/test-refund-gone.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- 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, MerchantPrivateApi } from "./harness";
-import {
- createSimpleTestkudosEnvironment,
- withdrawViaBank,
- applyTimeTravel,
-} from "./helpers";
-import {
- durationFromSpec,
- timestampAddDuration,
- getTimestampNow,
- timestampTruncateToSecond,
-} from "taler-wallet-core";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- pay_deadline: timestampTruncateToSecond(
- timestampAddDuration(
- getTimestampNow(),
- durationFromSpec({
- minutes: 10,
- }),
- ),
- ),
- },
- refund_delay: durationFromSpec({ minutes: 1 }),
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const r1 = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(r1.type === "response");
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: (r1.result as any).proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- console.log(orderStatus);
-
- await applyTimeTravel(durationFromSpec({ hours: 1 }), { exchange, wallet });
-
- await exchange.runAggregatorOnce();
-
- const ref = await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:5",
- instance: "default",
- justification: "foo",
- orderId: orderResp.order_id,
- });
-
- console.log(ref);
-
- let rr = await wallet.applyRefund({
- talerRefundUri: ref.talerRefundUri,
- });
-
- t.assertAmountEquals(rr.amountRefundGone, "TESTKUDOS:5");
- console.log(rr);
-
- await wallet.runUntilDone();
-
- let r = await wallet.apiRequest("getBalances", {});
- console.log(JSON.stringify(r, undefined, 2));
-
- r = await wallet.apiRequest("getTransactions", {});
- console.log(JSON.stringify(r, undefined, 2));
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-refund-incremental.ts b/packages/taler-integrationtests/src/test-refund-incremental.ts
deleted file mode 100644
index 7ad406daf..000000000
--- a/packages/taler-integrationtests/src/test-refund-incremental.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- 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,
- delayMs,
- MerchantPrivateApi,
-} from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-import { TransactionType, Amounts, durationFromSpec } from "taler-wallet-core";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:10",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- refund_delay: durationFromSpec({ minutes: 5 }),
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const r1 = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(r1.type === "response");
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: (r1.result as any).proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- let ref = await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:2.5",
- instance: "default",
- justification: "foo",
- orderId: orderResp.order_id,
- });
-
- console.log("first refund increase response", ref);
-
- {
- let wr = await wallet.applyRefund({
- talerRefundUri: ref.talerRefundUri,
- });
- console.log(wr);
- const txs = await wallet.getTransactions();
- console.log(
- "transactions after applying first refund:",
- JSON.stringify(txs, undefined, 2),
- );
- }
-
- // Wait at least a second, because otherwise the increased
- // refund will be grouped with the previous one.
- await delayMs(1200);
-
- ref = await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:5",
- instance: "default",
- justification: "bar",
- orderId: orderResp.order_id,
- });
-
- console.log("second refund increase response", ref);
-
- // Wait at least a second, because otherwise the increased
- // refund will be grouped with the previous one.
- await delayMs(1200);
-
- ref = await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:10",
- instance: "default",
- justification: "bar",
- orderId: orderResp.order_id,
- });
-
- console.log("third refund increase response", ref);
-
- {
- let wr = await wallet.applyRefund({
- talerRefundUri: ref.talerRefundUri,
- });
- console.log(wr);
- }
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- t.assertAmountEquals(orderStatus.refund_amount, "TESTKUDOS:10");
-
- console.log(JSON.stringify(orderStatus, undefined, 2));
-
- await wallet.runUntilDone();
-
- const bal = await wallet.getBalances();
- console.log(JSON.stringify(bal, undefined, 2));
-
- {
- const txs = await wallet.getTransactions();
- console.log(JSON.stringify(txs, undefined, 2));
-
- const txTypes = txs.transactions.map((x) => x.type);
- t.assertDeepEqual(txTypes, [
- "withdrawal",
- "payment",
- "refund",
- "refund",
- "refund",
- ]);
-
- for (const tx of txs.transactions) {
- if (tx.type !== TransactionType.Refund) {
- continue;
- }
- t.assertAmountLeq(tx.amountEffective, tx.amountRaw);
- }
-
- const raw = Amounts.sum(
- txs.transactions
- .filter((x) => x.type === TransactionType.Refund)
- .map((x) => x.amountRaw),
- ).amount;
-
- t.assertAmountEquals("TESTKUDOS:10", raw);
-
- const effective = Amounts.sum(
- txs.transactions
- .filter((x) => x.type === TransactionType.Refund)
- .map((x) => x.amountEffective),
- ).amount;
-
- t.assertAmountEquals("TESTKUDOS:8.33", effective);
- }
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-refund.ts b/packages/taler-integrationtests/src/test-refund.ts
deleted file mode 100644
index 908136518..000000000
--- a/packages/taler-integrationtests/src/test-refund.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- 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 { durationFromSpec } from "taler-wallet-core";
-import { runTest, GlobalTestState, MerchantPrivateApi } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
-
- // Set up order.
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- summary: "Buy me!",
- amount: "TESTKUDOS:5",
- fulfillment_url: "taler://fulfillment-success/thx",
- },
- refund_delay: durationFromSpec({ minutes: 5 }),
- });
-
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- // Make wallet pay for the order
-
- const r1 = await wallet.apiRequest("preparePay", {
- talerPayUri: orderStatus.taler_pay_uri,
- });
- t.assertTrue(r1.type === "response");
-
- const r2 = await wallet.apiRequest("confirmPay", {
- // FIXME: should be validated, don't cast!
- proposalId: (r1.result as any).proposalId,
- });
- t.assertTrue(r2.type === "response");
-
- // Check if payment was successful.
-
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- });
-
- t.assertTrue(orderStatus.order_status === "paid");
-
- const ref = await MerchantPrivateApi.giveRefund(merchant, {
- amount: "TESTKUDOS:5",
- instance: "default",
- justification: "foo",
- orderId: orderResp.order_id,
- });
-
- console.log(ref);
-
- let r = await wallet.apiRequest("applyRefund", {
- talerRefundUri: ref.talerRefundUri,
- });
- t.assertTrue(r.type === "response");
- console.log(r);
-
- await wallet.runUntilDone();
-
- r = await wallet.apiRequest("getBalances", {});
- console.log(JSON.stringify(r, undefined, 2));
-
- r = await wallet.apiRequest("getTransactions", {});
- console.log(JSON.stringify(r, undefined, 2));
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-revocation.ts b/packages/taler-integrationtests/src/test-revocation.ts
deleted file mode 100644
index 32cb5d620..000000000
--- a/packages/taler-integrationtests/src/test-revocation.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- 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,
- MerchantPrivateApi,
- ExchangeService,
- MerchantService,
- WalletCli,
-} from "./harness";
-import {
- createSimpleTestkudosEnvironment,
- withdrawViaBank,
- makeTestPayment,
-} from "./helpers";
-import { CoinDumpJson } from "taler-wallet-core";
-
-async function revokeAllWalletCoins(req: {
- wallet: WalletCli;
- exchange: ExchangeService;
- merchant: MerchantService;
-}): Promise<void> {
- const { wallet, exchange, merchant } = req;
- const coinDump = await wallet.dumpCoins();
- console.log(coinDump);
- const usedDenomHashes = new Set<string>();
- for (const coin of coinDump.coins) {
- usedDenomHashes.add(coin.denom_pub_hash);
- }
-
- await exchange.stop();
-
- for (const x of usedDenomHashes.values()) {
- await exchange.revokeDenomination(x);
- }
-
- await exchange.keyup();
-
- await exchange.start();
- await exchange.pingUntilAvailable();
- await merchant.stop();
- await merchant.start();
- await merchant.pingUntilAvailable();
-}
-
-/**
- * Basic time travel test.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:15" });
-
- await revokeAllWalletCoins({ wallet, exchange, merchant });
-
- // FIXME: this shouldn't be necessary once https://bugs.taler.net/n/6565
- // is implemented.
- await wallet.forceUpdateExchange({ exchangeBaseUrl: exchange.baseUrl });
- await wallet.runUntilDone();
- await wallet.runUntilDone();
- const bal = await wallet.getBalances();
- console.log("wallet balance", bal);
-
- const order = {
- summary: "Buy me!",
- amount: "TESTKUDOS:10",
- fulfillment_url: "taler://fulfillment-success/thx",
- };
-
- await makeTestPayment(t, { wallet, merchant, order });
-
- wallet.deleteDatabase();
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:15" });
-
- const coinDump = await wallet.dumpCoins();
- console.log(coinDump);
- const coinPubList = coinDump.coins.map((x) => x.coin_pub);
- await wallet.forceRefresh({
- coinPubList,
- });
- await wallet.runUntilDone();
-
- await revokeAllWalletCoins({ wallet, exchange, merchant });
-
- // FIXME: this shouldn't be necessary once https://bugs.taler.net/n/6565
- // is implemented.
- await wallet.forceUpdateExchange({ exchangeBaseUrl: exchange.baseUrl });
- await wallet.runUntilDone();
- await wallet.runUntilDone();
- {
- const bal = await wallet.getBalances();
- console.log("wallet balance", bal);
- }
-
- await makeTestPayment(t, { wallet, merchant, order });
-});
diff --git a/packages/taler-integrationtests/src/test-timetravel-autorefresh.ts b/packages/taler-integrationtests/src/test-timetravel-autorefresh.ts
deleted file mode 100644
index 382051c8a..000000000
--- a/packages/taler-integrationtests/src/test-timetravel-autorefresh.ts
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- 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 {
- ConfirmPayResultType,
- Duration,
- durationFromSpec,
- PendingOperationsResponse,
- PreparePayResultType,
-} from "taler-wallet-core";
-import { makeNoFeeCoinConfig } from "./denomStructures";
-import {
- BankService,
- ExchangeService,
- GlobalTestState,
- MerchantPrivateApi,
- MerchantService,
- runTest,
- setupDb,
- WalletCli,
-} from "./harness";
-import { startWithdrawViaBank, withdrawViaBank } from "./helpers";
-
-async function applyTimeTravel(
- timetravelDuration: Duration,
- s: {
- exchange?: ExchangeService;
- merchant?: MerchantService;
- wallet?: WalletCli;
- },
-): Promise<void> {
- if (s.exchange) {
- await s.exchange.stop();
- s.exchange.setTimetravel(timetravelDuration);
- await s.exchange.start();
- await s.exchange.pingUntilAvailable();
- }
-
- if (s.merchant) {
- await s.merchant.stop();
- s.merchant.setTimetravel(timetravelDuration);
- await s.merchant.start();
- await s.merchant.pingUntilAvailable();
- }
-
- if (s.wallet) {
- s.wallet.setTimetravel(timetravelDuration);
- }
-}
-
-/**
- * Basic time travel test.
- */
-runTest(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,
- });
-
- const exchange = ExchangeService.create(t, {
- name: "testexchange-1",
- currency: "TESTKUDOS",
- httpPort: 8081,
- database: db.connStr,
- });
-
- const merchant = await MerchantService.create(t, {
- name: "testmerchant-1",
- currency: "TESTKUDOS",
- httpPort: 8083,
- database: db.connStr,
- });
-
- const exchangeBankAccount = await bank.createExchangeAccount(
- "MyExchange",
- "x",
- );
- exchange.addBankAccount("1", exchangeBankAccount);
-
- bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
-
- await bank.start();
-
- await bank.pingUntilAvailable();
-
- exchange.addCoinConfigList(makeNoFeeCoinConfig("TESTKUDOS"));
-
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- 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!");
-
- const wallet = new WalletCli(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:15" });
-
- // Travel into the future, the deposit expiration is two years
- // into the future.
- await applyTimeTravel(durationFromSpec({ days: 400 }), {
- wallet,
- exchange,
- merchant,
- });
-
- await wallet.runUntilDone();
-
- let p: PendingOperationsResponse;
- p = await wallet.getPendingOperations();
-
- console.log("pending operations after first time travel");
- console.log(JSON.stringify(p, undefined, 2));
-
- await startWithdrawViaBank(t, {
- wallet,
- bank,
- exchange,
- amount: "TESTKUDOS:20",
- });
-
- await wallet.runUntilDone();
-
- // Travel into the future, the deposit expiration is two years
- // into the future.
- await applyTimeTravel(durationFromSpec({ years: 2, months: 6 }), {
- wallet,
- exchange,
- merchant,
- });
-
- await wallet.runUntilDone();
-
- const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
- order: {
- fulfillment_url: "http://example.com",
- summary: "foo",
- amount: "TESTKUDOS:30",
- },
- });
-
- const orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
- merchant,
- {
- orderId: orderResp.order_id,
- instance: "default",
- },
- );
-
- t.assertTrue(orderStatus.order_status === "unpaid");
-
- const r = await wallet.preparePay({
- talerPayUri: orderStatus.taler_pay_uri,
- });
-
- console.log(r);
-
- t.assertTrue(r.status === PreparePayResultType.PaymentPossible);
-
- const cpr = await wallet.confirmPay({
- proposalId: r.proposalId,
- });
-
- t.assertTrue(cpr.type === ConfirmPayResultType.Done);
-});
diff --git a/packages/taler-integrationtests/src/test-timetravel-withdraw.ts b/packages/taler-integrationtests/src/test-timetravel-withdraw.ts
deleted file mode 100644
index e0124d462..000000000
--- a/packages/taler-integrationtests/src/test-timetravel-withdraw.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- 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,
- withdrawViaBank,
- startWithdrawViaBank,
-} from "./helpers";
-import { Duration, TransactionType } from "taler-wallet-core";
-
-/**
- * Basic time travel test.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- // Withdraw digital cash into the wallet.
-
- await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:15" });
-
- // Travel 400 days into the future,
- // as the deposit expiration is two years
- // into the future.
- const timetravelDuration: Duration = {
- d_ms: 1000 * 60 * 60 * 24 * 400,
- };
-
- await exchange.stop();
- exchange.setTimetravel(timetravelDuration);
- await exchange.keyup();
- await exchange.start();
- await exchange.pingUntilAvailable();
-
- await merchant.stop();
- merchant.setTimetravel(timetravelDuration);
- await merchant.start();
- await merchant.pingUntilAvailable();
-
- // This should fail, as the wallet didn't time travel yet.
- await startWithdrawViaBank(t, {
- wallet,
- bank,
- exchange,
- amount: "TESTKUDOS:20",
- });
-
- // Check that transactions are correct for the failed withdrawal
- {
- await wallet.runUntilDone({ maxRetries: 5 });
- const transactions = await wallet.getTransactions();
- console.log(transactions);
- const types = transactions.transactions.map((x) => x.type);
- t.assertDeepEqual(types, ["withdrawal", "withdrawal"]);
- const wtrans = transactions.transactions[1];
- t.assertTrue(wtrans.type === TransactionType.Withdrawal);
- t.assertTrue(wtrans.pending);
- }
-
- // Now we also let the wallet time travel
-
- wallet.setTimetravel(timetravelDuration);
-
- // This doesn't work yet, see https://bugs.taler.net/n/6585
-
- // await wallet.runUntilDone({ maxRetries: 5 });
-});
diff --git a/packages/taler-integrationtests/src/test-tipping.ts b/packages/taler-integrationtests/src/test-tipping.ts
deleted file mode 100644
index 4735de81a..000000000
--- a/packages/taler-integrationtests/src/test-tipping.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- 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,
- MerchantPrivateApi,
- BankApi,
-} from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const {
- wallet,
- bank,
- exchange,
- merchant,
- exchangeBankAccount,
- } = await createSimpleTestkudosEnvironment(t);
-
- const mbu = await BankApi.createRandomBankUser(bank);
-
- const tipReserveResp = await MerchantPrivateApi.createTippingReserve(
- merchant,
- "default",
- {
- exchange_url: exchange.baseUrl,
- initial_balance: "TESTKUDOS:10",
- wire_method: "x-taler-bank",
- },
- );
-
- console.log("tipReserveResp:", tipReserveResp);
-
- t.assertDeepEqual(
- tipReserveResp.payto_uri,
- exchangeBankAccount.accountPaytoUri,
- );
-
- await BankApi.adminAddIncoming(bank, {
- amount: "TESTKUDOS:10",
- debitAccountPayto: mbu.accountPaytoUri,
- exchangeBankAccount,
- reservePub: tipReserveResp.reserve_pub,
- });
-
- await exchange.runWirewatchOnce();
- await merchant.stop();
- await merchant.start();
- await merchant.pingUntilAvailable();
-
- const r = await MerchantPrivateApi.queryTippingReserves(merchant, "default");
- console.log("tipping reserves:", JSON.stringify(r, undefined, 2));
-
- t.assertTrue(r.reserves.length === 1);
- t.assertDeepEqual(
- r.reserves[0].exchange_initial_amount,
- r.reserves[0].merchant_initial_amount,
- );
-
- const tip = await MerchantPrivateApi.giveTip(merchant, "default", {
- amount: "TESTKUDOS:5",
- justification: "why not?",
- next_url: "https://example.com/after-tip",
- });
-
- console.log("created tip", tip);
-
- const doTip = async (): Promise<void> => {
- const ptr = await wallet.prepareTip({
- talerTipUri: tip.taler_tip_uri,
- });
-
- console.log(ptr);
-
- t.assertAmountEquals(ptr.tipAmountRaw, "TESTKUDOS:5");
- t.assertAmountEquals(ptr.tipAmountEffective, "TESTKUDOS:4.85");
-
- await wallet.acceptTip({
- walletTipId: ptr.walletTipId,
- });
-
- await wallet.runUntilDone();
-
- const bal = await wallet.getBalances();
-
- console.log(bal);
-
- t.assertAmountEquals(bal.balances[0].available, "TESTKUDOS:4.85");
-
- const txns = await wallet.getTransactions();
-
- console.log("Transactions:", JSON.stringify(txns, undefined, 2));
-
- t.assertDeepEqual(txns.transactions[0].type, "tip");
- t.assertDeepEqual(txns.transactions[0].pending, false);
- t.assertAmountEquals(
- txns.transactions[0].amountEffective,
- "TESTKUDOS:4.85",
- );
- t.assertAmountEquals(txns.transactions[0].amountRaw, "TESTKUDOS:5.0");
- };
-
- // Check twice so make sure tip handling is idempotent
- await doTip();
- await doTip();
-});
diff --git a/packages/taler-integrationtests/src/test-wallettesting.ts b/packages/taler-integrationtests/src/test-wallettesting.ts
deleted file mode 100644
index a6014a88d..000000000
--- a/packages/taler-integrationtests/src/test-wallettesting.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- 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/>
- */
-
-/**
- * Integration test for the wallet testing functionality used by the exchange
- * test cases.
- */
-
-/**
- * Imports.
- */
-import { runTest, GlobalTestState } from "./harness";
-import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
-
- await wallet.runIntegrationTest({
- amountToSpend: "TESTKUDOS:5",
- amountToWithdraw: "TESTKUDOS:10",
- bankBaseUrl: bank.baseUrl,
- exchangeBaseUrl: exchange.baseUrl,
- merchantApiKey: "sandbox",
- merchantBaseUrl: merchant.makeInstanceBaseUrl(),
- });
-
- let txns = await wallet.getTransactions();
- console.log(JSON.stringify(txns, undefined, 2));
- let txTypes = txns.transactions.map((x) => x.type);
-
- t.assertDeepEqual(txTypes, [
- "withdrawal",
- "payment",
- "withdrawal",
- "payment",
- "refund",
- "payment",
- ]);
-
- wallet.deleteDatabase();
-
- await wallet.withdrawTestBalance({
- amount: "TESTKUDOS:10",
- bankBaseUrl: bank.baseUrl,
- exchangeBaseUrl: exchange.baseUrl,
- });
-
- await wallet.runUntilDone();
-
- await wallet.testPay({
- amount: "TESTKUDOS:5",
- merchantApiKey: "sandbox",
- merchantBaseUrl: merchant.makeInstanceBaseUrl(),
- summary: "foo",
- });
-
- await wallet.runUntilDone();
-
- txns = await wallet.getTransactions();
- console.log(JSON.stringify(txns, undefined, 2));
- txTypes = txns.transactions.map((x) => x.type);
-
- t.assertDeepEqual(txTypes, ["withdrawal", "payment"]);
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-withdrawal-abort-bank.ts b/packages/taler-integrationtests/src/test-withdrawal-abort-bank.ts
deleted file mode 100644
index dd848b93d..000000000
--- a/packages/taler-integrationtests/src/test-withdrawal-abort-bank.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- 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, BankApi, BankAccessApi } from "./harness";
-import { createSimpleTestkudosEnvironment } from "./helpers";
-import { codecForBalancesResponse, TalerErrorCode } from "taler-wallet-core";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const { wallet, bank, exchange } = await createSimpleTestkudosEnvironment(t);
-
- // Create a withdrawal operation
-
- const user = await BankApi.createRandomBankUser(bank);
- const wop = await BankAccessApi.createWithdrawalOperation(
- bank,
- user,
- "TESTKUDOS:10",
- );
-
- // Hand it to the wallet
-
- const r1 = await wallet.apiRequest("getWithdrawalDetailsForUri", {
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r1.type === "response");
-
- await wallet.runPending();
-
- // Confirm it
-
- await BankApi.abortWithdrawalOperation(bank, user, wop);
-
- // Withdraw
-
- const r2 = await wallet.apiRequest("acceptBankIntegratedWithdrawal", {
- exchangeBaseUrl: exchange.baseUrl,
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r2.type === "error");
- t.assertTrue(
- r2.error.code ===
- TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK,
- );
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts b/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts
deleted file mode 100644
index d54309b31..000000000
--- a/packages/taler-integrationtests/src/test-withdrawal-bank-integrated.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- 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, BankApi, BankAccessApi } from "./harness";
-import { createSimpleTestkudosEnvironment } from "./helpers";
-import { codecForBalancesResponse } from "taler-wallet-core";
-
-/**
- * Run test for basic, bank-integrated withdrawal.
- */
-runTest(async (t: GlobalTestState) => {
- // Set up test environment
-
- const { wallet, bank, exchange } = await createSimpleTestkudosEnvironment(t);
-
- // Create a withdrawal operation
-
- const user = await BankApi.createRandomBankUser(bank);
- const wop = await BankAccessApi.createWithdrawalOperation(
- bank,
- user,
- "TESTKUDOS:10",
- );
-
- // Hand it to the wallet
-
- const r1 = await wallet.apiRequest("getWithdrawalDetailsForUri", {
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r1.type === "response");
-
- await wallet.runPending();
-
- // Confirm it
-
- await BankApi.confirmWithdrawalOperation(bank, user, wop);
-
- // Withdraw
-
- const r2 = await wallet.apiRequest("acceptBankIntegratedWithdrawal", {
- exchangeBaseUrl: exchange.baseUrl,
- talerWithdrawUri: wop.taler_withdraw_uri,
- });
- t.assertTrue(r2.type === "response");
- await wallet.runUntilDone();
-
- // Check balance
-
- const balApiResp = await wallet.apiRequest("getBalances", {});
- t.assertTrue(balApiResp.type === "response");
- const balResp = codecForBalancesResponse().decode(balApiResp.result);
- t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available);
-
- await t.shutdown();
-});
diff --git a/packages/taler-integrationtests/src/test-withdrawal-manual.ts b/packages/taler-integrationtests/src/test-withdrawal-manual.ts
deleted file mode 100644
index aeac74d9f..000000000
--- a/packages/taler-integrationtests/src/test-withdrawal-manual.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- 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, BankApi } from "./harness";
-import { createSimpleTestkudosEnvironment } from "./helpers";
-import { CoreApiResponse } from "taler-wallet-core";
-import { codecForBalancesResponse } from "taler-wallet-core";
-
-/**
- * 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 BankApi.createRandomBankUser(bank);
-
- 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 BankApi.adminAddIncoming(bank, {
- 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 = codecForBalancesResponse().decode(balApiResp.result);
- t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available);
-
- await t.shutdown();
-});