-fix tests

This commit is contained in:
Florian Dold 2023-10-16 13:19:10 +02:00
parent 9504687813
commit 925a97c2e3
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
10 changed files with 123 additions and 49 deletions

View File

@ -654,6 +654,9 @@ export class FakebankService
return this.baseUrl; return this.baseUrl;
} }
// FIXME: Why do we have this function at all?
// We now have a unified corebank API, we should just use that
// to create bank accounts, also for the exchange.
async createExchangeAccount( async createExchangeAccount(
accountName: string, accountName: string,
password: string, password: string,

View File

@ -136,20 +136,22 @@ export async function runTimetravelAutorefreshTest(t: GlobalTestState) {
}, },
); );
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
let p: PendingOperationsResponse; let p: PendingOperationsResponse;
p = await walletClient.call(WalletApiOperation.GetPendingOperations, {}); p = await walletClient.call(WalletApiOperation.GetPendingOperations, {});
console.log("pending operations after first time travel"); console.log("pending operations after first time travel");
console.log(JSON.stringify(p, undefined, 2)); console.log(JSON.stringify(p, undefined, 2));
await withdrawViaBankV2(t, { await walletClient.call(WalletApiOperation.TestingWaitTasksProcessed, {});
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
const wres2 = await withdrawViaBankV2(t, {
walletClient, walletClient,
bank, bank,
exchange, exchange,
amount: "TESTKUDOS:20", amount: "TESTKUDOS:20",
}); });
await wres2.withdrawalFinishedCond;
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
@ -165,12 +167,13 @@ export async function runTimetravelAutorefreshTest(t: GlobalTestState) {
}, },
); );
await walletClient.call(WalletApiOperation.TestingWaitTasksProcessed, {});
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
// At this point, the original coins should've been refreshed. // At this point, the original coins should've been refreshed.
// It would be too late to refresh them now, as we're past // It would be too late to refresh them now, as we're past
// the two year deposit expiration. // the two year deposit expiration.
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
const orderResp = await merchantClient.createOrder({ const orderResp = await merchantClient.createOrder({
order: { order: {
fulfillment_url: "http://example.com", fulfillment_url: "http://example.com",
@ -195,7 +198,7 @@ export async function runTimetravelAutorefreshTest(t: GlobalTestState) {
t.assertTrue(r.status === PreparePayResultType.PaymentPossible); t.assertTrue(r.status === PreparePayResultType.PaymentPossible);
const cpr = await walletClient.call(WalletApiOperation.ConfirmPay, { const cpr = await walletClient.call(WalletApiOperation.ConfirmPay, {
proposalId: r.proposalId, transactionId: r.transactionId,
}); });
t.assertTrue(cpr.type === ConfirmPayResultType.Done); t.assertTrue(cpr.type === ConfirmPayResultType.Done);

View File

@ -55,12 +55,14 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) {
accountName: "exchange", accountName: "exchange",
accountPassword: "x", accountPassword: "x",
wireGatewayApiBaseUrl: new URL( wireGatewayApiBaseUrl: new URL(
"/accounts/exchange/taler-wire-gateway", "/accounts/exchange/taler-wire-gateway/",
bank.baseUrl, bank.baseUrl,
).href, ).href,
accountPaytoUri: "payto://x-taler-bank/localhost/exchange", accountPaytoUri: "payto://x-taler-bank/localhost/exchange",
}); });
await bank.createExchangeAccount("exchange", "x");
await bank.start(); await bank.start();
await bank.pingUntilAvailable(); await bank.pingUntilAvailable();
@ -93,8 +95,6 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) {
const balResp = await wallet.client.call(WalletApiOperation.GetBalances, {}); const balResp = await wallet.client.call(WalletApiOperation.GetBalances, {});
t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available); t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available);
await t.shutdown();
} }
runWithdrawalFakebankTest.suites = ["wallet"]; runWithdrawalFakebankTest.suites = ["wallet"];

View File

@ -1585,7 +1585,7 @@ export const codecForWithdrawResponse = (): Codec<ExchangeWithdrawResponse> =>
.property("ev_sig", codecForBlindedDenominationSignature()) .property("ev_sig", codecForBlindedDenominationSignature())
.build("WithdrawResponse"); .build("WithdrawResponse");
export const codecForWithdrawBatchResponse = export const codecForExchangeWithdrawBatchResponse =
(): Codec<ExchangeWithdrawBatchResponse> => (): Codec<ExchangeWithdrawBatchResponse> =>
buildCodecForObject<ExchangeWithdrawBatchResponse>() buildCodecForObject<ExchangeWithdrawBatchResponse>()
.property("ev_sigs", codecForList(codecForWithdrawResponse())) .property("ev_sigs", codecForList(codecForWithdrawResponse()))

View File

@ -49,6 +49,9 @@ import {
Logger, Logger,
parsePaytoUri, parsePaytoUri,
UnblindedSignature, UnblindedSignature,
ExchangeBatchWithdrawRequest,
ExchangeWithdrawBatchResponse,
codecForExchangeWithdrawBatchResponse,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {
HttpRequestLibrary, HttpRequestLibrary,
@ -165,25 +168,29 @@ export async function withdrawCoin(args: {
value: Amounts.parseOrThrow(denom.value), value: Amounts.parseOrThrow(denom.value),
}); });
const reqBody: ExchangeWithdrawRequest = { const reqBody: ExchangeBatchWithdrawRequest = {
denom_pub_hash: planchet.denomPubHash, planchets: [
reserve_sig: planchet.withdrawSig, {
coin_ev: planchet.coinEv, denom_pub_hash: planchet.denomPubHash,
reserve_sig: planchet.withdrawSig,
coin_ev: planchet.coinEv,
},
],
}; };
const reqUrl = new URL( const reqUrl = new URL(
`reserves/${planchet.reservePub}/withdraw`, `reserves/${planchet.reservePub}/batch-withdraw`,
exchangeBaseUrl, exchangeBaseUrl,
).href; ).href;
const resp = await http.postJson(reqUrl, reqBody); const resp = await http.fetch(reqUrl, { method: "POST", body: reqBody });
const r = await readSuccessResponseJsonOrThrow( const rBatch = await readSuccessResponseJsonOrThrow(
resp, resp,
codecForWithdrawResponse(), codecForExchangeWithdrawBatchResponse(),
); );
const ubSig = await cryptoApi.unblindDenominationSignature({ const ubSig = await cryptoApi.unblindDenominationSignature({
planchet, planchet,
evSig: r.ev_sig, evSig: rBatch.ev_sigs[0].ev_sig,
}); });
return { return {

View File

@ -101,14 +101,14 @@ async function gatherExchangePending(
case ExchangeEntryDbUpdateStatus.Failed: case ExchangeEntryDbUpdateStatus.Failed:
return; return;
} }
const opTag = TaskIdentifiers.forExchangeUpdate(exch); const opUpdateExchangeTag = TaskIdentifiers.forExchangeUpdate(exch);
let opr = await tx.operationRetries.get(opTag); let opr = await tx.operationRetries.get(opUpdateExchangeTag);
const timestampDue = opr?.retryInfo.nextRetry ?? exch.nextRefreshCheckStamp; const timestampDue = opr?.retryInfo.nextRetry ?? exch.nextRefreshCheckStamp;
resp.pendingOperations.push({ resp.pendingOperations.push({
type: PendingTaskType.ExchangeUpdate, type: PendingTaskType.ExchangeUpdate,
...getPendingCommon( ...getPendingCommon(
ws, ws,
opTag, opUpdateExchangeTag,
AbsoluteTime.fromPreciseTimestamp(timestampPreciseFromDb(timestampDue)), AbsoluteTime.fromPreciseTimestamp(timestampPreciseFromDb(timestampDue)),
), ),
givesLifeness: false, givesLifeness: false,
@ -119,11 +119,12 @@ async function gatherExchangePending(
// We only schedule a check for auto-refresh if the exchange update // We only schedule a check for auto-refresh if the exchange update
// was successful. // was successful.
if (!opr?.lastError) { if (!opr?.lastError) {
const opCheckRefreshTag = TaskIdentifiers.forExchangeCheckRefresh(exch);
resp.pendingOperations.push({ resp.pendingOperations.push({
type: PendingTaskType.ExchangeCheckRefresh, type: PendingTaskType.ExchangeCheckRefresh,
...getPendingCommon( ...getPendingCommon(
ws, ws,
opTag, opCheckRefreshTag,
AbsoluteTime.fromPreciseTimestamp( AbsoluteTime.fromPreciseTimestamp(
timestampPreciseFromDb(timestampDue), timestampPreciseFromDb(timestampDue),
), ),

View File

@ -74,6 +74,7 @@ import {
import { initiatePeerPushDebit } from "./pay-peer-push-debit.js"; import { initiatePeerPushDebit } from "./pay-peer-push-debit.js";
import { OpenedPromise, openPromise } from "../index.js"; import { OpenedPromise, openPromise } from "../index.js";
import { getTransactionById, getTransactions } from "./transactions.js"; import { getTransactionById, getTransactions } from "./transactions.js";
import { getPendingOperations } from "./pending.js";
const logger = new Logger("operations/testing.ts"); const logger = new Logger("operations/testing.ts");
@ -290,7 +291,7 @@ export async function runIntegrationTest(
corebankApiBaseUrl: args.corebankApiBaseUrl, corebankApiBaseUrl: args.corebankApiBaseUrl,
exchangeBaseUrl: args.exchangeBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl,
}); });
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.info("done withdrawing test balance"); logger.info("done withdrawing test balance");
const balance = await getBalances(ws); const balance = await getBalances(ws);
@ -305,7 +306,7 @@ export async function runIntegrationTest(
await makePayment(ws, myMerchant, args.amountToSpend, "hello world"); await makePayment(ws, myMerchant, args.amountToSpend, "hello world");
// Wait until the refresh is done // Wait until the refresh is done
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.trace("withdrawing test balance for refund"); logger.trace("withdrawing test balance for refund");
const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`); const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`);
@ -320,7 +321,7 @@ export async function runIntegrationTest(
}); });
// Wait until the withdraw is done // Wait until the withdraw is done
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
const { orderId: refundOrderId } = await makePayment( const { orderId: refundOrderId } = await makePayment(
ws, ws,
@ -344,7 +345,7 @@ export async function runIntegrationTest(
logger.trace("integration test: applied refund"); logger.trace("integration test: applied refund");
// Wait until the refund is done // Wait until the refund is done
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.trace("integration test: making payment after refund"); logger.trace("integration test: making payment after refund");
@ -357,12 +358,17 @@ export async function runIntegrationTest(
logger.trace("integration test: make payment done"); logger.trace("integration test: make payment done");
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.trace("integration test: all done!"); logger.trace("integration test: all done!");
} }
export async function waitUntilDone(ws: InternalWalletState): Promise<void> { /**
* Wait until all transactions are in a final state.
*/
export async function waitUntilTransactionsFinal(
ws: InternalWalletState,
): Promise<void> {
logger.info("waiting until all transactions are in a final state"); logger.info("waiting until all transactions are in a final state");
ws.ensureTaskLoopRunning(); ws.ensureTaskLoopRunning();
let p: OpenedPromise<void> | undefined = undefined; let p: OpenedPromise<void> | undefined = undefined;
@ -410,6 +416,44 @@ export async function waitUntilDone(ws: InternalWalletState): Promise<void> {
logger.info("done waiting until all transactions are in a final state"); logger.info("done waiting until all transactions are in a final state");
} }
/**
* Wait until pending work is processed.
*/
export async function waitUntilTasksProcessed(
ws: InternalWalletState,
): Promise<void> {
logger.info("waiting until pending work is processed");
ws.ensureTaskLoopRunning();
let p: OpenedPromise<void> | undefined = undefined;
const cancelNotifs = ws.addNotificationListener((notif) => {
if (!p) {
return;
}
if (notif.type === NotificationType.PendingOperationProcessed) {
p.resolve();
}
});
while (1) {
p = openPromise();
const pendingTasksResp = await getPendingOperations(ws);
logger.info(`waiting on pending ops: ${j2s(pendingTasksResp)}`);
let finished = true;
for (const task of pendingTasksResp.pendingOperations) {
if (task.isDue) {
finished = false;
}
logger.info(`continuing waiting for task ${task.id}`);
}
if (finished) {
break;
}
// Wait until task is done
await p.promise;
}
logger.info("done waiting until pending work is processed");
cancelNotifs();
}
export async function waitUntilRefreshesDone( export async function waitUntilRefreshesDone(
ws: InternalWalletState, ws: InternalWalletState,
): Promise<void> { ): Promise<void> {
@ -463,7 +507,7 @@ export async function waitUntilRefreshesDone(
logger.info("done waiting until all refreshes are in a final state"); logger.info("done waiting until all refreshes are in a final state");
} }
async function waitUntilPendingReady( async function waitUntilTransactionPendingReady(
ws: InternalWalletState, ws: InternalWalletState,
transactionId: string, transactionId: string,
): Promise<void> { ): Promise<void> {
@ -560,7 +604,7 @@ export async function runIntegrationTest2(
corebankApiBaseUrl: args.corebankApiBaseUrl, corebankApiBaseUrl: args.corebankApiBaseUrl,
exchangeBaseUrl: args.exchangeBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl,
}); });
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.info("done withdrawing test balance"); logger.info("done withdrawing test balance");
const balance = await getBalances(ws); const balance = await getBalances(ws);
@ -580,7 +624,7 @@ export async function runIntegrationTest2(
); );
// Wait until the refresh is done // Wait until the refresh is done
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.trace("withdrawing test balance for refund"); logger.trace("withdrawing test balance for refund");
const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`); const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`);
@ -595,7 +639,7 @@ export async function runIntegrationTest2(
}); });
// Wait until the withdraw is done // Wait until the withdraw is done
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
const { orderId: refundOrderId } = await makePayment( const { orderId: refundOrderId } = await makePayment(
ws, ws,
@ -619,7 +663,7 @@ export async function runIntegrationTest2(
logger.trace("integration test: applied refund"); logger.trace("integration test: applied refund");
// Wait until the refund is done // Wait until the refund is done
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.trace("integration test: making payment after refund"); logger.trace("integration test: making payment after refund");
@ -632,7 +676,7 @@ export async function runIntegrationTest2(
logger.trace("integration test: make payment done"); logger.trace("integration test: make payment done");
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
const peerPushInit = await initiatePeerPushDebit(ws, { const peerPushInit = await initiatePeerPushDebit(ws, {
partialContractTerms: { partialContractTerms: {
@ -647,7 +691,7 @@ export async function runIntegrationTest2(
}, },
}); });
await waitUntilPendingReady(ws, peerPushInit.transactionId); await waitUntilTransactionPendingReady(ws, peerPushInit.transactionId);
const peerPushCredit = await preparePeerPushCredit(ws, { const peerPushCredit = await preparePeerPushCredit(ws, {
talerUri: peerPushInit.talerUri, talerUri: peerPushInit.talerUri,
@ -670,7 +714,7 @@ export async function runIntegrationTest2(
}, },
}); });
await waitUntilPendingReady(ws, peerPullInit.transactionId); await waitUntilTransactionPendingReady(ws, peerPullInit.transactionId);
const peerPullInc = await preparePeerPullDebit(ws, { const peerPullInc = await preparePeerPullDebit(ws, {
talerUri: peerPullInit.talerUri, talerUri: peerPullInit.talerUri,
@ -680,7 +724,7 @@ export async function runIntegrationTest2(
peerPullDebitId: peerPullInc.peerPullDebitId, peerPullDebitId: peerPullInc.peerPullDebitId,
}); });
await waitUntilDone(ws); await waitUntilTransactionsFinal(ws);
logger.trace("integration test: all done!"); logger.trace("integration test: all done!");
} }

View File

@ -33,7 +33,7 @@ import {
codecForReserveStatus, codecForReserveStatus,
codecForTalerConfigResponse, codecForTalerConfigResponse,
codecForWalletKycUuid, codecForWalletKycUuid,
codecForWithdrawBatchResponse, codecForExchangeWithdrawBatchResponse,
codecForWithdrawOperationStatusResponse, codecForWithdrawOperationStatusResponse,
codecForWithdrawResponse, codecForWithdrawResponse,
CoinStatus, CoinStatus,
@ -939,7 +939,7 @@ async function processPlanchetExchangeBatchRequest(
} }
const r = await readSuccessResponseJsonOrThrow( const r = await readSuccessResponseJsonOrThrow(
resp, resp,
codecForWithdrawBatchResponse(), codecForExchangeWithdrawBatchResponse(),
); );
return { return {
coinIdxs: requestCoinIdxs, coinIdxs: requestCoinIdxs,

View File

@ -224,6 +224,7 @@ export enum WalletApiOperation {
DeleteStoredBackup = "deleteStoredBackup", DeleteStoredBackup = "deleteStoredBackup",
RecoverStoredBackup = "recoverStoredBackup", RecoverStoredBackup = "recoverStoredBackup",
UpdateExchangeEntry = "updateExchangeEntry", UpdateExchangeEntry = "updateExchangeEntry",
TestingWaitTasksProcessed = "testingWaitTasksProcessed",
} }
// group: Initialization // group: Initialization
@ -1007,7 +1008,7 @@ export type TestingSetTimetravelOp = {
/** /**
* Wait until all transactions are in a final state. * Wait until all transactions are in a final state.
*/ */
export type TestingWaitTransactionsFinal = { export type TestingWaitTransactionsFinalOp = {
op: WalletApiOperation.TestingWaitTransactionsFinal; op: WalletApiOperation.TestingWaitTransactionsFinal;
request: EmptyObject; request: EmptyObject;
response: EmptyObject; response: EmptyObject;
@ -1016,12 +1017,21 @@ export type TestingWaitTransactionsFinal = {
/** /**
* Wait until all refresh transactions are in a final state. * Wait until all refresh transactions are in a final state.
*/ */
export type TestingWaitRefreshesFinal = { export type TestingWaitRefreshesFinalOp = {
op: WalletApiOperation.TestingWaitRefreshesFinal; op: WalletApiOperation.TestingWaitRefreshesFinal;
request: EmptyObject; request: EmptyObject;
response: EmptyObject; response: EmptyObject;
}; };
/**
* Wait until all tasks have been processed and the wallet is idle.
*/
export type TestingWaitTasksProcessedOp = {
op: WalletApiOperation.TestingWaitTasksProcessed;
request: EmptyObject;
response: EmptyObject;
};
/** /**
* Wait until a transaction is in a particular state. * Wait until a transaction is in a particular state.
*/ */
@ -1132,8 +1142,9 @@ export type WalletOperations = {
[WalletApiOperation.Recycle]: RecycleOp; [WalletApiOperation.Recycle]: RecycleOp;
[WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp; [WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp;
[WalletApiOperation.ValidateIban]: ValidateIbanOp; [WalletApiOperation.ValidateIban]: ValidateIbanOp;
[WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal; [WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinalOp;
[WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinal; [WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinalOp;
[WalletApiOperation.TestingWaitTasksProcessed]: TestingWaitTasksProcessedOp;
[WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp; [WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp;
[WalletApiOperation.TestingWaitTransactionState]: TestingWaitTransactionStateOp; [WalletApiOperation.TestingWaitTransactionState]: TestingWaitTransactionStateOp;
[WalletApiOperation.GetCurrencySpecification]: GetCurrencySpecificationOp; [WalletApiOperation.GetCurrencySpecification]: GetCurrencySpecificationOp;

View File

@ -252,9 +252,10 @@ import {
runIntegrationTest2, runIntegrationTest2,
testPay, testPay,
waitTransactionState, waitTransactionState,
waitUntilDone, waitUntilTransactionsFinal,
waitUntilRefreshesDone, waitUntilRefreshesDone,
withdrawTestBalance, withdrawTestBalance,
waitUntilTasksProcessed,
} from "./operations/testing.js"; } from "./operations/testing.js";
import { import {
acceptTip, acceptTip,
@ -927,9 +928,9 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
ageCommitmentProof: c.ageCommitmentProof, ageCommitmentProof: c.ageCommitmentProof,
spend_allocation: c.spendAllocation spend_allocation: c.spendAllocation
? { ? {
amount: c.spendAllocation.amount, amount: c.spendAllocation.amount,
id: c.spendAllocation.id, id: c.spendAllocation.id,
} }
: undefined, : undefined,
}); });
} }
@ -1427,6 +1428,10 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
await waitTransactionState(ws, req.transactionId, req.txState); await waitTransactionState(ws, req.transactionId, req.txState);
return {}; return {};
} }
case WalletApiOperation.TestingWaitTasksProcessed: {
await waitUntilTasksProcessed(ws);
return {};
}
case WalletApiOperation.GetCurrencySpecification: { case WalletApiOperation.GetCurrencySpecification: {
// Ignore result, just validate in this mock implementation // Ignore result, just validate in this mock implementation
const req = codecForGetCurrencyInfoRequest().decode(payload); const req = codecForGetCurrencyInfoRequest().decode(payload);
@ -1600,7 +1605,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
return getVersion(ws); return getVersion(ws);
} }
case WalletApiOperation.TestingWaitTransactionsFinal: case WalletApiOperation.TestingWaitTransactionsFinal:
return await waitUntilDone(ws); return await waitUntilTransactionsFinal(ws);
case WalletApiOperation.TestingWaitRefreshesFinal: case WalletApiOperation.TestingWaitRefreshesFinal:
return await waitUntilRefreshesDone(ws); return await waitUntilRefreshesDone(ws);
case WalletApiOperation.TestingSetTimetravel: { case WalletApiOperation.TestingSetTimetravel: {