diff options
author | Florian Dold <florian@dold.me> | 2021-03-03 21:20:05 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-03-03 21:20:05 +0100 |
commit | 1a0610f222f841237f9940a3a3a55635eec7d324 (patch) | |
tree | b80c67be371a006080cd26b2d61f26cd3aa77697 | |
parent | 186a38250ff4a11f88c8956db4da574f08e741dc (diff) |
WIP: wallet backup integration test
6 files changed, 219 insertions, 5 deletions
diff --git a/packages/taler-wallet-cli/src/integrationtests/harness.ts b/packages/taler-wallet-cli/src/integrationtests/harness.ts index 118bc35d4..a2d2b8e13 100644 --- a/packages/taler-wallet-cli/src/integrationtests/harness.ts +++ b/packages/taler-wallet-cli/src/integrationtests/harness.ts @@ -99,6 +99,7 @@ import { import { ApplyRefundResponse } from "@gnu-taler/taler-wallet-core"; import { PendingOperationsResponse } from "@gnu-taler/taler-wallet-core"; import { CoinConfig } from "./denomStructures"; +import { AddBackupProviderRequest, BackupInfo } from "@gnu-taler/taler-wallet-core/src/operations/backup"; const exec = util.promisify(require("child_process").exec); @@ -396,7 +397,11 @@ export interface TalerConfig { } export interface DbInfo { + /** + * Postgres connection string. + */ connStr: string; + dbname: string; } @@ -418,7 +423,7 @@ export interface BankConfig { maxDebt?: string; } -function setPaths(config: Configuration, home: string) { +function setTalerPaths(config: Configuration, home: string) { config.setString("paths", "taler_home", home); // We need to make sure that the path of taler_runtime_dir isn't too long, // as it contains unix domain sockets (108 character limit). @@ -647,7 +652,7 @@ export class BankService implements BankServiceInterface { bc: BankConfig, ): Promise<BankService> { const config = new Configuration(); - setPaths(config, gc.testDir + "/talerhome"); + setTalerPaths(config, gc.testDir + "/talerhome"); config.setString("taler", "currency", bc.currency); config.setString("bank", "database", bc.database); config.setString("bank", "http_port", `${bc.httpPort}`); @@ -860,7 +865,7 @@ export class ExchangeService implements ExchangeServiceInterface { "currency_round_unit", e.roundUnit ?? `${e.currency}:0.01`, ); - setPaths(config, gc.testDir + "/talerhome"); + setTalerPaths(config, gc.testDir + "/talerhome"); config.setString( "exchange", @@ -1425,7 +1430,7 @@ export class MerchantService implements MerchantServiceInterface { config.setString("taler", "currency", mc.currency); const cfgFilename = gc.testDir + `/merchant-${mc.name}.conf`; - setPaths(config, gc.testDir + "/talerhome"); + setTalerPaths(config, gc.testDir + "/talerhome"); config.setString("merchant", "serve", "tcp"); config.setString("merchant", "port", `${mc.httpPort}`); config.setString( @@ -1846,4 +1851,20 @@ export class WalletCli { } throw new OperationFailedError(resp.error); } + + async addBackupProvider(req: AddBackupProviderRequest): Promise<void> { + const resp = await this.apiRequest("addBackupProvider", req); + if (resp.type === "response") { + return; + } + throw new OperationFailedError(resp.error); + } + + async getBackupInfo(): Promise<BackupInfo> { + const resp = await this.apiRequest("getBackupInfo", {}); + if (resp.type === "response") { + return resp.result as BackupInfo; + } + throw new OperationFailedError(resp.error); + } } diff --git a/packages/taler-wallet-cli/src/integrationtests/sync.ts b/packages/taler-wallet-cli/src/integrationtests/sync.ts new file mode 100644 index 000000000..7aa4b2893 --- /dev/null +++ b/packages/taler-wallet-cli/src/integrationtests/sync.ts @@ -0,0 +1,121 @@ +/* + This file is part of GNU Taler + (C) 2021 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/> + */ + +/** + * Imports. + */ +import axios from "axios"; +import { Configuration, URL } from "@gnu-taler/taler-wallet-core"; +import { getRandomIban, getRandomString } from "./helpers"; +import * as fs from "fs"; +import * as util from "util"; +import { + GlobalTestState, + DbInfo, + pingProc, + ProcessWrapper, + runCommand, + setupDb, + sh, +} from "./harness"; + +const exec = util.promisify(require("child_process").exec); + +export interface SyncConfig { + /** + * Human-readable name used in the test harness logs. + */ + name: string; + + httpPort: number; + + /** + * Database connection string (ony postgres is supported). + */ + database: string; + + annualFee: string; + + currency: string; + + uploadLimitMb: number; + + /** + * Fulfillment URL used for contract terms related to + * sync. + */ + fulfillmentUrl: string; + + paymentBackendUrl: string; +} + +function setSyncPaths(config: Configuration, home: string) { + config.setString("paths", "sync_home", home); + // We need to make sure that the path of taler_runtime_dir isn't too long, + // as it contains unix domain sockets (108 character limit). + const runDir = fs.mkdtempSync("/tmp/taler-test-"); + config.setString("paths", "sync_runtime_dir", runDir); + config.setString("paths", "sync_data_home", "$SYNC_HOME/.local/share/sync/"); + config.setString("paths", "sync_config_home", "$SYNC_HOME/.config/sync/"); + config.setString("paths", "sync_cache_home", "$SYNC_HOME/.config/sync/"); +} + +export class SyncService { + static async create( + gc: GlobalTestState, + sc: SyncConfig, + ): Promise<SyncService> { + const config = new Configuration(); + + const cfgFilename = gc.testDir + `/sync-${sc.name}.conf`; + setSyncPaths(config, gc.testDir + "/synchome"); + config.setString("taler", "currency", sc.currency); + config.setString("sync", "serve", "tcp"); + config.setString("sync", "port", `${sc.httpPort}`); + config.setString("sync", "db", "postgres"); + config.setString("syncdb-postgres", "config", sc.database); + config.write(cfgFilename); + + return new SyncService(gc, sc, cfgFilename); + } + + proc: ProcessWrapper | undefined; + + get baseUrl(): string { + return `http://localhost:${this.syncConfig.httpPort}/`; + } + + async start(): Promise<void> { + await exec(`sync-dbinit -c "${this.configFilename}"`); + + this.proc = this.globalState.spawnService( + "sync-httpd", + ["-LDEBUG", "-c", this.configFilename], + `sync-${this.syncConfig.name}`, + ); + } + + async pingUntilAvailable(): Promise<void> { + const url = new URL("config", this.baseUrl).href; + await pingProc(this.proc, url, "sync"); + } + + constructor( + private globalState: GlobalTestState, + private syncConfig: SyncConfig, + private configFilename: string, + ) {} +} diff --git a/packages/taler-wallet-cli/src/integrationtests/test-wallet-backup-basic.ts b/packages/taler-wallet-cli/src/integrationtests/test-wallet-backup-basic.ts new file mode 100644 index 000000000..9201c558c --- /dev/null +++ b/packages/taler-wallet-cli/src/integrationtests/test-wallet-backup-basic.ts @@ -0,0 +1,66 @@ +/* + This file is part of GNU Taler + (C) 2020 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/> + */ + +/** + * Imports. + */ +import { GlobalTestState, BankApi, BankAccessApi } from "./harness"; +import { createSimpleTestkudosEnvironment } from "./helpers"; +import { codecForBalancesResponse } from "@gnu-taler/taler-wallet-core"; +import { SyncService } from "./sync"; + +/** + * Run test for basic, bank-integrated withdrawal. + */ +export async function runWalletBackupBasicTest(t: GlobalTestState) { + // Set up test environment + + const { commonDb, merchant, wallet, bank, exchange } = await createSimpleTestkudosEnvironment(t); + + const sync = await SyncService.create(t, { + currency: "TESTKUDOS", + annualFee: "TESTKUDOS:0.5", + database: commonDb.connStr, + fulfillmentUrl: "taler://fulfillment-success", + httpPort: 8089, + name: "sync1", + paymentBackendUrl: merchant.makeInstanceBaseUrl(), + uploadLimitMb: 10, + }); + + await sync.start(); + await sync.pingUntilAvailable(); + + await wallet.addBackupProvider({ + backupProviderBaseUrl: sync.baseUrl, + activate: false, + }); + + { + const bi = await wallet.getBackupInfo(); + t.assertDeepEqual(bi.providers[0].active, false); + } + + await wallet.addBackupProvider({ + backupProviderBaseUrl: sync.baseUrl, + activate: false, + }); + + { + const bi = await wallet.getBackupInfo(); + t.assertDeepEqual(bi.providers[0].active, true); + } +} diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts index 9aeb7ac73..6b158e8d0 100644 --- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts +++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts @@ -61,6 +61,7 @@ import { runDepositTest } from "./test-deposit"; import CancellationToken from "cancellationtoken"; import { runMerchantInstancesTest } from "./test-merchant-instances"; import { runMerchantInstancesUrlsTest } from "./test-merchant-instances-urls"; +import { runWalletBackupBasicTest } from "./test-wallet-backup-basic"; /** * Test runner. @@ -107,6 +108,7 @@ const allTests: TestMainFunction[] = [ runTimetravelAutorefreshTest, runTimetravelWithdrawTest, runTippingTest, + runWalletBackupBasicTest, runWallettestingTest, runWithdrawalAbortBankTest, runWithdrawalBankIntegratedTest, diff --git a/packages/taler-wallet-core/src/types/backupTypes.ts b/packages/taler-wallet-core/src/types/backupTypes.ts index 5e4844b51..d4b1625f6 100644 --- a/packages/taler-wallet-core/src/types/backupTypes.ts +++ b/packages/taler-wallet-core/src/types/backupTypes.ts @@ -189,7 +189,7 @@ export interface WalletBackupContentV1 { /** * Clock when the purchase was deleted */ - clock_deleted: number; + clock_deleted: ClockStamp; /** * Proposal ID identifying the purchase. diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 5aa951d5f..8f9999cc1 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1159,6 +1159,10 @@ export class Wallet { await runBackupCycle(this.ws); return {}; } + case "getBackupInfo": { + const resp = await getBackupInfo(this.ws); + return resp; + } case "createDepositGroup": { const req = codecForCreateDepositGroupRequest().decode(payload); return await createDepositGroup(this.ws, req); |