commit 7f966ae5de07fabd09f9cfcf9e0d6309a378063e
parent 27d6013f31a15ccf7b582ea5b90f459757740883
Author: Florian Dold <dold@taler.net>
Date: Wed, 29 Jul 2026 13:48:11 +0200
wallet-core: add a dev experiment that blocks order claims
Lets a test observe how the wallet retries a claim without taking the order
away from the nonce it claims with.
Issue: https://bugs.taler.net/n/11087
Diffstat:
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -49,6 +49,7 @@ import {
j2s,
} from "@gnu-taler/taler-util";
import {
+ HeadersImpl,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
@@ -125,6 +126,8 @@ export interface DevExperimentState {
blockPayResponse?: boolean;
+ blockClaimResponse?: boolean;
+
/** Migration test for confirmPay */
flagConfirmPayNoWait?: boolean;
@@ -513,6 +516,12 @@ export async function applyDevExperiment(
wex.ws.devExperimentState.blockPayResponse = val;
return;
}
+ case "block-claim-response": {
+ const val = getValFlag(parsedUri);
+ logger.info(`setting dev experiment blockClaimResponse=${val}`);
+ wex.ws.devExperimentState.blockClaimResponse = val;
+ return;
+ }
case "pretend-no-denoms": {
wex.ws.devExperimentState.pretendNoDenoms = true;
return;
@@ -857,7 +866,13 @@ function mockResponseReplacementJson(
};
}
-function mockInternalServerError(resp: HttpResponse): HttpResponse {
+/**
+ * Fake a 500 for a request. Takes only the request-identifying part of a
+ * response, so that a request that is never sent on can be faked as well.
+ */
+function mockInternalServerError(
+ resp: Pick<HttpResponse, "requestMethod" | "requestUrl" | "headers">,
+): HttpResponse {
const textEncoder = new TextEncoder();
const respJson = {
code: TalerErrorCode.GENERIC_INTERNAL_INVARIANT_FAILURE,
@@ -942,6 +957,18 @@ export class DevExperimentHttpLib implements HttpRequestLibrary {
const realResp = await this.underlyingLib.fetch(url, opt);
return mockInternalServerError(realResp);
}
+ } else if (this.devExperimentState.blockClaimResponse) {
+ if (method === "post" && url.endsWith("/claim")) {
+ logger.warn(`blocking /claim response`);
+ // The claim is not sent on at all: the merchant would hand the order
+ // to our nonce, and every further attempt would then be a repeated
+ // claim instead of a first one.
+ return mockInternalServerError({
+ requestMethod: "POST",
+ requestUrl: url,
+ headers: new HeadersImpl(),
+ });
+ }
}
if (
evalFailProbability(this.devExperimentState.tc?.dropRequestProbability)