From 64e340541ffcf10df4ef6400232c423aaecf81b9 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 29 Jan 2024 12:24:46 +0100 Subject: wallet-core: implement db migration check --- packages/taler-harness/src/index.ts | 115 ++++++++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 5 deletions(-) (limited to 'packages/taler-harness/src/index.ts') diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts index 5a0ccbd12..787ea1933 100644 --- a/packages/taler-harness/src/index.ts +++ b/packages/taler-harness/src/index.ts @@ -20,6 +20,7 @@ import { AmountString, Amounts, + BalancesResponse, Configuration, Duration, HttpStatusCode, @@ -28,6 +29,7 @@ import { MerchantInstanceConfig, RegisterAccountRequest, TalerCorebankApiClient, + TransactionsResponse, addPaytoQueryParams, decodeCrock, generateIban, @@ -58,12 +60,16 @@ import { runEnvFull } from "./env-full.js"; import { runEnv1 } from "./env1.js"; import { GlobalTestState, + WalletClient, delayMs, runTestWithState, } from "./harness/harness.js"; import { getTestInfo, runTests } from "./integrationtests/testrunner.js"; import { lintExchangeDeployment } from "./lint.js"; -import { createSimpleTestkudosEnvironmentV2 } from "./harness/helpers.js"; +import { + createSimpleTestkudosEnvironmentV2, + createWalletDaemonWithClient, +} from "./harness/helpers.js"; const logger = new Logger("taler-harness:index.ts"); @@ -179,6 +185,88 @@ advancedCli await runTestWithState(testState, runEnv1, "env1", true); }); +async function doDbChecks( + t: GlobalTestState, + walletClient: WalletClient, + indir: string, +): Promise { + // Check that balance didn't break + 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); + + // Check that transactions didn't break + const txnPath = `${indir}/wallet-transactions.json`; + const expectedTxn: TransactionsResponse = JSON.parse( + fs.readFileSync(txnPath, { encoding: "utf8" }), + ) as TransactionsResponse; + const actualTxn = await walletClient.call( + WalletApiOperation.GetTransactions, + { includeRefreshes: true }, + ); + t.assertDeepEqual( + actualTxn.transactions.length, + expectedTxn.transactions.length, + ); +} + +advancedCli + .subcommand("walletDbcheck", "wallet-dbcheck", { + help: "Check a wallet database (used for migration testing).", + }) + .requiredArgument("indir", clk.STRING) + .action(async (args) => { + const indir = args.walletDbcheck.indir; + if (!fs.existsSync(indir)) { + throw Error("directory to be checked does not exist"); + } + + const testRootDir = fs.mkdtempSync(path.join(os.tmpdir(), "taler-dbchk-")); + const t: GlobalTestState = new GlobalTestState({ + testDir: testRootDir, + }); + const walletDbPath = `${indir}/wallet-db.sqlite3`; + if (!fs.existsSync(walletDbPath)) { + throw new Error("wallet db to be checked does not exist"); + } + const { walletClient, walletService } = await createWalletDaemonWithClient( + t, + { name: "wallet-loaded", overrideDbPath: walletDbPath }, + ); + + await walletService.pingUntilAvailable(); + + // Do DB checks with the DB we loaded. + await doDbChecks(t, walletClient, indir); + + const { + walletClient: freshWalletClient, + walletService: freshWalletService, + } = await createWalletDaemonWithClient(t, { + name: "wallet-fresh", + persistent: false, + }); + + // Check that we can still import the backup JSON. + + const backupPath = `${indir}/wallet-backup.json`; + const backupData = JSON.parse( + fs.readFileSync(backupPath, { encoding: "utf8" }), + ); + await freshWalletClient.call(WalletApiOperation.ImportDb, { + dump: backupData, + }); + + // Repeat same checks with wallet that we restored from backup + // instead of from the DB file. + await doDbChecks(t, freshWalletClient, indir); + + await t.shutdown(); + }); + advancedCli .subcommand("walletDbgen", "wallet-dbgen", { help: "Generate a wallet test database (to be used for migration testing).", @@ -186,6 +274,9 @@ advancedCli .requiredArgument("outdir", clk.STRING) .action(async (args) => { const outdir = args.walletDbgen.outdir; + if (fs.existsSync(outdir)) { + throw new Error("outdir already exists, please delete first"); + } fs.mkdirSync(outdir, { recursive: true, }); @@ -209,16 +300,24 @@ advancedCli {}, ); - const transactionsJson = walletClient.call( + const transactionsJson = await walletClient.call( WalletApiOperation.GetTransactions, { includeRefreshes: true, }, ); - const balancesJson = walletClient.call(WalletApiOperation.GetBalances, {}); + const balancesJson = await walletClient.call( + WalletApiOperation.GetBalances, + {}, + ); + + const backupJson = await walletClient.call(WalletApiOperation.ExportDb, {}); - const backupJson = walletClient.call(WalletApiOperation.ExportDb, {}); + const versionJson = await walletClient.call( + WalletApiOperation.GetVersion, + {}, + ); await walletService.stop(); @@ -233,6 +332,13 @@ advancedCli ); fs.writeFileSync(`${outdir}/wallet-balances.json`, j2s(balancesJson)); fs.writeFileSync(`${outdir}/wallet-backup.json`, j2s(backupJson)); + fs.writeFileSync(`${outdir}/wallet-version.json`, j2s(versionJson)); + fs.writeFileSync( + `${outdir}/meta.json`, + j2s({ + timestamp: new Date(), + }), + ); }); const configCli = testingCli.subcommand("configArgs", "config", { @@ -317,7 +423,6 @@ deploymentCli const paytoUri = addPaytoQueryParams(tipReserveResp.accounts[0].payto_uri, { message: `tip-reserve ${tipReserveResp.reserve_pub}`, }); - console.log("payto URI:", paytoUri); const transactions = await bankAccessApiClient.getTransactions( -- cgit v1.2.3