From 676ae5102b618e7e52ba289d453a470fe77ce9d5 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 13 Sep 2022 15:28:34 +0200 Subject: [PATCH] fix test and logging --- packages/taler-wallet-cli/src/index.ts | 3 + .../test-exchange-management.ts | 16 +---- .../integrationtests/test-payment-claim.ts | 9 +-- packages/taler-wallet-core/src/errors.ts | 2 +- packages/taler-wallet-core/src/wallet.ts | 59 +++++++++++-------- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 2ed371420..5fd608f77 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -226,6 +226,9 @@ async function withWallet( const wallet = await getDefaultNodeWallet({ persistentStoragePath: dbPath, httpLib: myHttpLib, + notifyHandler: (n) => { + logger.info(`wallet notification: ${j2s(n)}`); + }, }); if (checkEnvFlag("TALER_WALLET_BATCH_WITHDRAWAL")) { diff --git a/packages/taler-wallet-cli/src/integrationtests/test-exchange-management.ts b/packages/taler-wallet-cli/src/integrationtests/test-exchange-management.ts index 0193322fd..56c3cf23f 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-exchange-management.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-exchange-management.ts @@ -189,17 +189,10 @@ export async function runExchangeManagementTest( }); }); - // Updating the exchange from the base URL is technically a pending operation - // and it will be retried later. - t.assertTrue( - err1.hasErrorCode(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED), - ); - // Response is malformed, since it didn't even contain a version code // in a format the wallet can understand. t.assertTrue( - err1.errorDetail.innerError.code === - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + err1.errorDetail.code === TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, ); exchangesList = await wallet.client.call( @@ -238,12 +231,9 @@ export async function runExchangeManagementTest( }); t.assertTrue( - err2.hasErrorCode(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED), - ); - - t.assertTrue( - err2.errorDetail.innerError.code === + err2.hasErrorCode( TalerErrorCode.WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE, + ), ); exchangesList = await wallet.client.call( diff --git a/packages/taler-wallet-cli/src/integrationtests/test-payment-claim.ts b/packages/taler-wallet-cli/src/integrationtests/test-payment-claim.ts index e878854f8..e93d2c44c 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-payment-claim.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-payment-claim.ts @@ -102,14 +102,7 @@ export async function runPaymentClaimTest(t: GlobalTestState) { }); }); - t.assertTrue( - err.hasErrorCode(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED), - ); - - t.assertTrue( - err.errorDetail.innerError.code === - TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED, - ); + t.assertTrue(err.hasErrorCode(TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED)); await t.shutdown(); } diff --git a/packages/taler-wallet-core/src/errors.ts b/packages/taler-wallet-core/src/errors.ts index 56017cc00..d56e936c0 100644 --- a/packages/taler-wallet-core/src/errors.ts +++ b/packages/taler-wallet-core/src/errors.ts @@ -102,7 +102,7 @@ export function summarizeTalerErrorDetail(ed: TalerErrorDetail): string { export class TalerError extends Error { errorDetail: TalerErrorDetail & T; private constructor(d: TalerErrorDetail & T) { - super(); + super(d.hint ?? `Error (code ${d.code})`); this.errorDetail = d; Object.setPrototypeOf(this, TalerError.prototype); } diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 58e11e90f..0e7772259 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -289,8 +289,9 @@ async function callOperationHandler( forceNow, }); case PendingTaskType.Withdraw: - await processWithdrawalGroup(ws, pending.withdrawalGroupId, { forceNow }); - break; + return await processWithdrawalGroup(ws, pending.withdrawalGroupId, { + forceNow, + }); case PendingTaskType.ProposalDownload: return await processDownloadProposal(ws, pending.proposalId, { forceNow, @@ -319,7 +320,7 @@ async function callOperationHandler( default: return assertUnreachable(pending); } - throw Error("not reached"); + throw Error(`not reached ${pending.type}`); } export async function storeOperationError( @@ -330,12 +331,17 @@ export async function storeOperationError( await ws.db .mktx((x) => [x.operationRetries]) .runReadWrite(async (tx) => { - const retryRecord = await tx.operationRetries.get(pendingTaskId); + let retryRecord = await tx.operationRetries.get(pendingTaskId); if (!retryRecord) { - return; + retryRecord = { + id: pendingTaskId, + lastError: e, + retryInfo: RetryInfo.reset(), + }; + } else { + retryRecord.lastError = e; + retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo); } - retryRecord.lastError = e; - retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo); await tx.operationRetries.put(retryRecord); }); } @@ -358,12 +364,16 @@ export async function storeOperationPending( await ws.db .mktx((x) => [x.operationRetries]) .runReadWrite(async (tx) => { - const retryRecord = await tx.operationRetries.get(pendingTaskId); + let retryRecord = await tx.operationRetries.get(pendingTaskId); if (!retryRecord) { - return; + retryRecord = { + id: pendingTaskId, + retryInfo: RetryInfo.reset(), + }; + } else { + delete retryRecord.lastError; + retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo); } - delete retryRecord.lastError; - retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo); await tx.operationRetries.put(retryRecord); }); } @@ -392,24 +402,18 @@ async function processOnePendingOperation( case OperationAttemptResultType.Longpoll: break; } - } catch (e: any) { - if ( - e instanceof TalerError && - e.hasErrorCode(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED) - ) { + } catch (e) { + if (e instanceof TalerError) { logger.warn("operation processed resulted in error"); logger.warn(`error was: ${j2s(e.errorDetail)}`); maybeError = e.errorDetail; - } else { + return await storeOperationError(ws, pending.id, maybeError!); + } else if (e instanceof Error) { // This is a bug, as we expect pending operations to always // do their own error handling and only throw WALLET_PENDING_OPERATION_FAILED // or return something. - logger.error("Uncaught exception", e); - ws.notify({ - type: NotificationType.InternalError, - message: "uncaught exception", - exception: e, - }); + logger.error(`Uncaught exception: ${e.message}`); + logger.error(`Stack: ${e.stack}`); maybeError = makeErrorDetail( TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, { @@ -417,6 +421,15 @@ async function processOnePendingOperation( }, `unexpected exception (message: ${e.message})`, ); + return await storeOperationError(ws, pending.id, maybeError); + } else { + logger.error("Uncaught exception, value is not even an error."); + maybeError = makeErrorDetail( + TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, + {}, + `unexpected exception (not even an error)`, + ); + return await storeOperationError(ws, pending.id, maybeError); } } }