test case for order claiming; more accurate EC

This commit is contained in:
Florian Dold 2020-08-24 11:52:12 +05:30
parent 1548086f50
commit b1fd7d09a6
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 45 additions and 20 deletions

View File

@ -1266,22 +1266,24 @@ function shellWrap(s: string) {
} }
export class WalletCli { 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() { deleteDatabase() {
const wdb = this.globalTestState.testDir + "/walletdb.json"; fs.unlinkSync(this.dbfile);
fs.unlinkSync(wdb);
} }
async apiRequest( async apiRequest(
request: string, request: string,
payload: unknown, payload: unknown,
): Promise<CoreApiResponse> { ): Promise<CoreApiResponse> {
const wdb = this.globalTestState.testDir + "/walletdb.json";
const resp = await sh( const resp = await sh(
this.globalTestState, this.globalTestState,
"wallet", `wallet-${this.name}`,
`taler-wallet-cli --no-throttle --wallet-db '${wdb}' api '${request}' ${shellWrap( `taler-wallet-cli --no-throttle --wallet-db '${this.dbfile}' api '${request}' ${shellWrap(
JSON.stringify(payload), JSON.stringify(payload),
)}`, )}`,
); );
@ -1290,20 +1292,18 @@ export class WalletCli {
} }
async runUntilDone(): Promise<void> { async runUntilDone(): Promise<void> {
const wdb = this.globalTestState.testDir + "/walletdb.json";
await sh( await sh(
this.globalTestState, this.globalTestState,
"wallet", `wallet-${this.name}`,
`taler-wallet-cli --no-throttle --wallet-db ${wdb} run-until-done`, `taler-wallet-cli --no-throttle --wallet-db ${this.dbfile} run-until-done`,
); );
} }
async runPending(): Promise<void> { async runPending(): Promise<void> {
const wdb = this.globalTestState.testDir + "/walletdb.json";
await sh( await sh(
this.globalTestState, this.globalTestState,
"wallet", `wallet-${this.name}`,
`taler-wallet-cli --no-throttle --wallet-db ${wdb} run-pending`, `taler-wallet-cli --no-throttle --wallet-db ${this.dbfile} run-pending`,
); );
} }

View File

@ -17,7 +17,7 @@
/** /**
* Imports. * Imports.
*/ */
import { runTest, GlobalTestState, MerchantPrivateApi } from "./harness"; import { runTest, GlobalTestState, MerchantPrivateApi, WalletCli } from "./harness";
import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers"; import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
import { PreparePayResultType } from "taler-wallet-core"; import { PreparePayResultType } from "taler-wallet-core";

View File

@ -3209,6 +3209,13 @@ export enum TalerErrorCode {
*/ */
WALLET_HTTP_REQUEST_TIMEOUT = 7013, 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. * End of error code range.
* Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0).

View File

@ -30,6 +30,9 @@ import Axios from "axios";
import { OperationFailedError, makeErrorDetails } from "../operations/errors"; import { OperationFailedError, makeErrorDetails } from "../operations/errors";
import { TalerErrorCode } from "../TalerErrorCode"; import { TalerErrorCode } from "../TalerErrorCode";
import { URL } from "../util/url"; 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. * Implementation of the HTTP request library interface for node.
@ -96,6 +99,7 @@ export class NodeHttpLib implements HttpRequestLibrary {
try { try {
responseJson = JSON.parse(respText); responseJson = JSON.parse(respText);
} catch (e) { } catch (e) {
logger.trace(`invalid json: '${respText}'`);
throw new OperationFailedError( throw new OperationFailedError(
makeErrorDetails( makeErrorDetails(
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
@ -109,6 +113,7 @@ export class NodeHttpLib implements HttpRequestLibrary {
); );
} }
if (responseJson === null || typeof responseJson !== "object") { if (responseJson === null || typeof responseJson !== "object") {
logger.trace(`invalid json (not an object): '${respText}'`);
throw new OperationFailedError( throw new OperationFailedError(
makeErrorDetails( makeErrorDetails(
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,

View File

@ -71,6 +71,7 @@ import {
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
throwUnexpectedRequestError, throwUnexpectedRequestError,
getHttpResponseErrorDetails, getHttpResponseErrorDetails,
readSuccessResponseJsonOrErrorCode,
} from "../util/http"; } from "../util/http";
import { TalerErrorCode } from "../TalerErrorCode"; import { TalerErrorCode } from "../TalerErrorCode";
import { URL } from "../util/url"; import { URL } from "../util/url";
@ -638,13 +639,25 @@ async function processDownloadProposalImpl(
requestBody.token = proposal.claimToken; requestBody.token = proposal.claimToken;
} }
const resp = await ws.http.postJson(orderClaimUrl, requestBody, { const httpResponse = await ws.http.postJson(orderClaimUrl, requestBody, {
timeout: getProposalRequestTimeout(proposal), timeout: getProposalRequestTimeout(proposal),
}); });
const proposalResp = await readSuccessResponseJsonOrThrow( const r = await readSuccessResponseJsonOrErrorCode(httpResponse, codecForProposal());
resp, if (r.isError) {
codecForProposal(), 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, // The proposalResp contains the contract terms as raw JSON,
// as the coded to parse them doesn't necessarily round-trip. // as the coded to parse them doesn't necessarily round-trip.

View File

@ -59,11 +59,11 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }): JSX.Element {
} }
let insufficientBalance = false; let insufficientBalance = false;
if (payStatus.status == "insufficient-balance") { if (payStatus.status == PreparePayResultType.InsufficientBalance) {
insufficientBalance = true; insufficientBalance = true;
} }
if (payStatus.status === "payment-possible") { if (payStatus.status === PreparePayResultType.PaymentPossible) {
amountEffective = Amounts.parseOrThrow(payStatus.amountEffective); amountEffective = Amounts.parseOrThrow(payStatus.amountEffective);
} }