taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit c33029b2ecba72420f0500ea25228c59ab6f1d2f
parent 3830cf3476372f3299beaf018be030d3c990aee7
Author: Florian Dold <dold@taler.net>
Date:   Wed, 22 Jul 2026 16:23:04 +0200

wallet: test what happens when a crypto worker stops answering

Uses the existing test worker, which already has an operation that never
responds, and records whether a worker was terminated.

Diffstat:
Mpackages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts | 47+++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts @@ -93,17 +93,23 @@ export class MyCryptoWorker implements CryptoWorker { }); } + terminated = false; + /** * Forcibly terminate the worker thread. */ terminate(): void { - // This is a no-op. + this.terminated = true; } } export class MyCryptoWorkerFactory implements CryptoWorkerFactory { + readonly started: MyCryptoWorker[] = []; + startWorker(): CryptoWorker { - return new MyCryptoWorker(); + const w = new MyCryptoWorker(); + this.started.push(w); + return w; } getConcurrency(): number { @@ -127,3 +133,40 @@ test("continues after error", async (t) => { const resp3 = await cryptoDisp.doRpc("testSuccess", 0, {}); assert.ok((resp3 as any).testResult === 42); }); + +test("a worker that stops answering fails the caller", async (t) => { + const factory = new MyCryptoWorkerFactory(); + const cryptoDisp = new CryptoDispatcher(factory, { + workerHangTimeoutMs: 1, + }); + + await assert.rejects( + async () => cryptoDisp.doRpc("testTimeout", 0, {}), + /timed out/, + "the caller must be rejected instead of waiting forever", + ); + + assert.strictEqual(factory.started.length, 1); + assert.strictEqual( + factory.started[0].terminated, + true, + "the worker that did not answer must be terminated", + ); + + // The worker slot has to be free again, otherwise the dispatcher queues + // every later request forever. + const resp = await cryptoDisp.doRpc("testSuccess", 0, {}); + assert.ok((resp as any).testResult === 42); +}); + +test("a worker that does answer is not terminated", async (t) => { + const factory = new MyCryptoWorkerFactory(); + // Far longer than the answer takes, so the timeout must not trigger. + const cryptoDisp = new CryptoDispatcher(factory, { + workerHangTimeoutMs: 60_000, + }); + + const resp = await cryptoDisp.doRpc("testSuccess", 0, {}); + assert.ok((resp as any).testResult === 42); + assert.strictEqual(factory.started[0].terminated, false); +});