taler-typescript-core

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

commit f72c1fcc314d534db443e0c50aec42a6810e04f1
parent cbc5ad536599f62f7fdddaf912cca91699ded00e
Author: Florian Dold <dold@taler.net>
Date:   Wed, 22 Jul 2026 17:28:13 +0200

wallet: test that a repeated global currency entry changes nothing

The duplicates share a transaction with another write, so the case also covers
that they do not take that write down with them.

Diffstat:
Mpackages/taler-wallet-core/src/dbtx-conformance-cases.ts | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+), 0 deletions(-)

diff --git a/packages/taler-wallet-core/src/dbtx-conformance-cases.ts b/packages/taler-wallet-core/src/dbtx-conformance-cases.ts @@ -2782,6 +2782,64 @@ export const conformanceCases: ConformanceCase[] = [ }, { + name: "global currency: adding the same entry twice is a no-op", + async run(t, runner) { + const exch = { + currency: "TESTKUDOS", + exchangeBaseUrl: "https://exchange.example.com/", + exchangeMasterPub: ck("gc-master-1"), + }; + const auditor = { + currency: "TESTKUDOS", + auditorBaseUrl: "https://auditor.example.com/", + auditorPub: ck("gc-auditor-1"), + }; + await runner.runReadWriteTx(async (tx) => { + await tx.upsertGlobalCurrencyExchange(exch); + await tx.upsertGlobalCurrencyAuditor(auditor); + }); + + // The duplicates go in the same transaction as a write that must + // survive them: on a store keyed by a generated id, a second row for the + // same entry violates the unique index, and that takes down everything + // else the transaction did. + await runner.runReadWriteTx(async (tx) => { + await tx.upsertGlobalCurrencyExchange(exch); + await tx.upsertGlobalCurrencyAuditor(auditor); + await tx.upsertGlobalCurrencyExchange({ + ...exch, + exchangeMasterPub: ck("gc-master-2"), + }); + }); + + const exchanges = await runner.runReadWriteTx((tx) => + tx.listGlobalCurrencyExchanges(), + ); + t.equal( + exchanges.filter((x) => x.exchangeMasterPub === ck("gc-master-1")) + .length, + 1, + "the duplicate must not have added a row", + ); + t.equal( + exchanges.filter((x) => x.exchangeMasterPub === ck("gc-master-2")) + .length, + 1, + "the write alongside the duplicates must have survived", + ); + + const auditors = await runner.runReadWriteTx((tx) => + tx.listGlobalCurrencyAuditors(), + ); + t.equal( + auditors.filter((x) => x.auditorPub === ck("gc-auditor-1")).length, + 1, + "the duplicate auditor must not have added a row", + ); + }, + }, + + { name: "transaction meta: the timestamp cursor cannot separate a tie", async run(t, runner) { // Timestamps are not unique, and the pagination cursor is a bound on