commit d983ff060560c0e0807020047676d46d97077cc3
parent 75f1058c4555854ee3718f8c3c7bb80b48feec07
Author: Florian Dold <dold@taler.net>
Date: Thu, 3 Sep 2026 15:44:44 +0200
wallet-core: test that a released lock goes to its waiter first
Diffstat:
1 file changed, 56 insertions(+), 0 deletions(-)
diff --git a/packages/taler-wallet-core/src/sequential-locks.test.ts b/packages/taler-wallet-core/src/sequential-locks.test.ts
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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/>
+ */
+
+
+import assert from "node:assert";
+import { test } from "node:test";
+import { SequentialLocks } from "./sequential-locks.js";
+
+test("a lock is handed to its waiter before a newcomer can take it", async () => {
+ const locks = new SequentialLocks();
+ const token = "coins";
+ let active = 0;
+ let maxActive = 0;
+ const order: string[] = [];
+ const section = (name: string) => async () => {
+ active++;
+ maxActive = Math.max(maxActive, active);
+ order.push(name);
+ await null;
+ await null;
+ active--;
+ };
+
+ let newcomer: Promise<void> | undefined;
+ const holder = locks.run([token], async () => {
+ // Queue the newcomer so that it checks the lock right after the holder
+ // released it, in the same microtask checkpoint that resumes the waiter.
+ Promise.resolve().then(() => {
+ queueMicrotask(() => {
+ newcomer = locks.run([token], section("newcomer"));
+ });
+ });
+ });
+ const waiter = locks.run([token], section("waiter"));
+
+ await holder;
+ await waiter;
+ assert.ok(newcomer);
+ await newcomer;
+
+ assert.strictEqual(maxActive, 1);
+ assert.deepStrictEqual(order, ["waiter", "newcomer"]);
+});