From b1fd7d09a605558bc61ed113331e0e065e0e2681 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 24 Aug 2020 11:52:12 +0530 Subject: test case for order claiming; more accurate EC --- packages/taler-integrationtests/src/harness.ts | 24 +++++++++++----------- .../taler-integrationtests/src/test-payment.ts | 2 +- packages/taler-wallet-core/src/TalerErrorCode.ts | 7 +++++++ .../taler-wallet-core/src/headless/NodeHttpLib.ts | 5 +++++ packages/taler-wallet-core/src/operations/pay.ts | 23 ++++++++++++++++----- .../taler-wallet-webextension/src/pages/pay.tsx | 4 ++-- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/taler-integrationtests/src/harness.ts b/packages/taler-integrationtests/src/harness.ts index 545ea3097..f4429d43f 100644 --- a/packages/taler-integrationtests/src/harness.ts +++ b/packages/taler-integrationtests/src/harness.ts @@ -1266,22 +1266,24 @@ function shellWrap(s: string) { } export class WalletCli { - constructor(private globalTestState: GlobalTestState) {} + constructor(private globalTestState: GlobalTestState, private name: string = "default") {} + + get dbfile(): string { + return this.globalTestState.testDir + `/walletdb-${this.name}.json`; + } deleteDatabase() { - const wdb = this.globalTestState.testDir + "/walletdb.json"; - fs.unlinkSync(wdb); + fs.unlinkSync(this.dbfile); } async apiRequest( request: string, payload: unknown, ): Promise { - const wdb = this.globalTestState.testDir + "/walletdb.json"; const resp = await sh( this.globalTestState, - "wallet", - `taler-wallet-cli --no-throttle --wallet-db '${wdb}' api '${request}' ${shellWrap( + `wallet-${this.name}`, + `taler-wallet-cli --no-throttle --wallet-db '${this.dbfile}' api '${request}' ${shellWrap( JSON.stringify(payload), )}`, ); @@ -1290,20 +1292,18 @@ export class WalletCli { } async runUntilDone(): Promise { - const wdb = this.globalTestState.testDir + "/walletdb.json"; await sh( this.globalTestState, - "wallet", - `taler-wallet-cli --no-throttle --wallet-db ${wdb} run-until-done`, + `wallet-${this.name}`, + `taler-wallet-cli --no-throttle --wallet-db ${this.dbfile} run-until-done`, ); } async runPending(): Promise { - const wdb = this.globalTestState.testDir + "/walletdb.json"; await sh( this.globalTestState, - "wallet", - `taler-wallet-cli --no-throttle --wallet-db ${wdb} run-pending`, + `wallet-${this.name}`, + `taler-wallet-cli --no-throttle --wallet-db ${this.dbfile} run-pending`, ); } diff --git a/packages/taler-integrationtests/src/test-payment.ts b/packages/taler-integrationtests/src/test-payment.ts index d2cbb10f4..d2401e072 100644 --- a/packages/taler-integrationtests/src/test-payment.ts +++ b/packages/taler-integrationtests/src/test-payment.ts @@ -17,7 +17,7 @@ /** * Imports. */ -import { runTest, GlobalTestState, MerchantPrivateApi } from "./harness"; +import { runTest, GlobalTestState, MerchantPrivateApi, WalletCli } from "./harness"; import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers"; import { PreparePayResultType } from "taler-wallet-core"; diff --git a/packages/taler-wallet-core/src/TalerErrorCode.ts b/packages/taler-wallet-core/src/TalerErrorCode.ts index ff8511046..7285a0fbe 100644 --- a/packages/taler-wallet-core/src/TalerErrorCode.ts +++ b/packages/taler-wallet-core/src/TalerErrorCode.ts @@ -3209,6 +3209,13 @@ export enum TalerErrorCode { */ WALLET_HTTP_REQUEST_TIMEOUT = 7013, + /** + * The order has already been claimed by another wallet. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + WALLET_ORDER_ALREADY_CLAIMED = 7014, + /** * End of error code range. * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). diff --git a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts b/packages/taler-wallet-core/src/headless/NodeHttpLib.ts index 85f37cfa3..62ab9caf6 100644 --- a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts +++ b/packages/taler-wallet-core/src/headless/NodeHttpLib.ts @@ -30,6 +30,9 @@ import Axios from "axios"; import { OperationFailedError, makeErrorDetails } from "../operations/errors"; import { TalerErrorCode } from "../TalerErrorCode"; import { URL } from "../util/url"; +import { Logger } from "../util/logging"; + +const logger = new Logger("NodeHttpLib.ts"); /** * Implementation of the HTTP request library interface for node. @@ -96,6 +99,7 @@ export class NodeHttpLib implements HttpRequestLibrary { try { responseJson = JSON.parse(respText); } catch (e) { + logger.trace(`invalid json: '${respText}'`); throw new OperationFailedError( makeErrorDetails( TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, @@ -109,6 +113,7 @@ export class NodeHttpLib implements HttpRequestLibrary { ); } if (responseJson === null || typeof responseJson !== "object") { + logger.trace(`invalid json (not an object): '${respText}'`); throw new OperationFailedError( makeErrorDetails( TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts index f20632344..0d1d4f993 100644 --- a/packages/taler-wallet-core/src/operations/pay.ts +++ b/packages/taler-wallet-core/src/operations/pay.ts @@ -71,6 +71,7 @@ import { readSuccessResponseJsonOrThrow, throwUnexpectedRequestError, getHttpResponseErrorDetails, + readSuccessResponseJsonOrErrorCode, } from "../util/http"; import { TalerErrorCode } from "../TalerErrorCode"; import { URL } from "../util/url"; @@ -638,13 +639,25 @@ async function processDownloadProposalImpl( requestBody.token = proposal.claimToken; } - const resp = await ws.http.postJson(orderClaimUrl, requestBody, { + const httpResponse = await ws.http.postJson(orderClaimUrl, requestBody, { timeout: getProposalRequestTimeout(proposal), }); - const proposalResp = await readSuccessResponseJsonOrThrow( - resp, - codecForProposal(), - ); + const r = await readSuccessResponseJsonOrErrorCode(httpResponse, codecForProposal()); + if (r.isError) { + switch (r.talerErrorResponse.code) { + case TalerErrorCode.ORDERS_ALREADY_CLAIMED: + throw OperationFailedError.fromCode( + TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED, + "order already claimed (likely by other wallet)", + { + orderId: proposal.orderId, + claimUrl: orderClaimUrl, + }); + default: + throwUnexpectedRequestError(httpResponse, r.talerErrorResponse); + } + } + const proposalResp = r.response; // The proposalResp contains the contract terms as raw JSON, // as the coded to parse them doesn't necessarily round-trip. diff --git a/packages/taler-wallet-webextension/src/pages/pay.tsx b/packages/taler-wallet-webextension/src/pages/pay.tsx index f1ba2c2b3..a7c5526ed 100644 --- a/packages/taler-wallet-webextension/src/pages/pay.tsx +++ b/packages/taler-wallet-webextension/src/pages/pay.tsx @@ -59,11 +59,11 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }): JSX.Element { } let insufficientBalance = false; - if (payStatus.status == "insufficient-balance") { + if (payStatus.status == PreparePayResultType.InsufficientBalance) { insufficientBalance = true; } - if (payStatus.status === "payment-possible") { + if (payStatus.status === PreparePayResultType.PaymentPossible) { amountEffective = Amounts.parseOrThrow(payStatus.amountEffective); } -- cgit v1.2.3