commit 0eb745768568c6340ba6e5d080b128052928c945
parent 857a6824ba894dc95c172d5a63ba9e154263ae1e
Author: Florian Dold <dold@taler.net>
Date: Sun, 19 Jul 2026 17:51:52 +0200
harness: check database contents in wallet-dbcheck, not just counts
Diffstat:
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts
@@ -376,15 +376,25 @@ async function doDbChecks(
walletClient: WalletClient,
indir: string,
): Promise<void> {
- // Check that balance didn't break
+ // Balances: amounts, not just how many there are. Comparing only the
+ // count passes a wallet that loads an old database and then reports the
+ // wrong money, which is the failure that would actually matter.
const balPath = `${indir}/wallet-balances.json`;
const expectedBal: BalancesResponse = JSON.parse(
fs.readFileSync(balPath, { encoding: "utf8" }),
) as BalancesResponse;
const actualBal = await walletClient.call(WalletApiOperation.GetBalances, {});
t.assertDeepEqual(actualBal.balances.length, expectedBal.balances.length);
+ const balKey = (b: BalancesResponse["balances"][0]) =>
+ `${b.scopeInfo.currency}:${b.available}:${b.pendingIncoming}:${b.pendingOutgoing}`;
+ t.assertDeepEqual(
+ actualBal.balances.map(balKey).sort(),
+ expectedBal.balances.map(balKey).sort(),
+ );
- // Check that transactions didn't break
+ // Transactions: id, type and state. The ids are what a UI holds on to
+ // across an upgrade, and the state is what the status-enum digit bug
+ // corrupted -- a count-only check saw nothing wrong with either.
const txnPath = `${indir}/wallet-transactions.json`;
const expectedTxn: TransactionsResponse = JSON.parse(
fs.readFileSync(txnPath, { encoding: "utf8" }),
@@ -397,6 +407,24 @@ async function doDbChecks(
actualTxn.transactions.length,
expectedTxn.transactions.length,
);
+ const txnKey = (x: TransactionsResponse["transactions"][0]) =>
+ `${x.transactionId}|${x.type}|${x.txState.major}|${x.txState.minor ?? ""}`;
+ t.assertDeepEqual(
+ actualTxn.transactions.map(txnKey).sort(),
+ expectedTxn.transactions.map(txnKey).sort(),
+ );
+
+ // Every transaction must also be individually retrievable, and agree with
+ // what the list said. getTransactionById goes through a different code
+ // path than the list, and it is the one that dereferenced an undefined
+ // state in the bug this check failed to catch.
+ for (const txn of actualTxn.transactions) {
+ const one = await walletClient.call(WalletApiOperation.GetTransactionById, {
+ transactionId: txn.transactionId,
+ });
+ t.assertDeepEqual(one.type, txn.type);
+ t.assertDeepEqual(one.txState.major, txn.txState.major);
+ }
}
advancedCli