test cases
This commit is contained in:
parent
08c3209dbc
commit
7e34b6699a
@ -40,7 +40,6 @@ export async function getBalancesInsideTransaction(
|
||||
ws: InternalWalletState,
|
||||
tx: TransactionHandle,
|
||||
): Promise<BalancesResponse> {
|
||||
|
||||
const balanceStore: Record<string, WalletBalance> = {};
|
||||
|
||||
/**
|
||||
@ -57,11 +56,17 @@ export async function getBalancesInsideTransaction(
|
||||
};
|
||||
}
|
||||
return balanceStore[currency];
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize balance to zero, even if we didn't start withdrawing yet.
|
||||
await tx.iter(Stores.reserves).forEach((r) => {
|
||||
initBalance(r.currency);
|
||||
const b = initBalance(r.currency);
|
||||
if (!r.initialWithdrawalStarted) {
|
||||
b.pendingIncoming = Amounts.add(
|
||||
b.pendingIncoming,
|
||||
r.initialDenomSel.totalCoinValue,
|
||||
).amount;
|
||||
}
|
||||
});
|
||||
|
||||
await tx.iter(Stores.coins).forEach((c) => {
|
||||
@ -95,23 +100,28 @@ export async function getBalancesInsideTransaction(
|
||||
return;
|
||||
}
|
||||
const b = initBalance(wds.denomsSel.totalWithdrawCost.currency);
|
||||
b.pendingIncoming = Amounts.add(b.pendingIncoming, wds.denomsSel.totalCoinValue).amount;
|
||||
b.pendingIncoming = Amounts.add(
|
||||
b.pendingIncoming,
|
||||
wds.denomsSel.totalCoinValue,
|
||||
).amount;
|
||||
});
|
||||
|
||||
const balancesResponse: BalancesResponse = {
|
||||
balances: [],
|
||||
};
|
||||
|
||||
Object.keys(balanceStore).sort().forEach((c) => {
|
||||
const v = balanceStore[c];
|
||||
balancesResponse.balances.push({
|
||||
available: Amounts.stringify(v.available),
|
||||
pendingIncoming: Amounts.stringify(v.pendingIncoming),
|
||||
pendingOutgoing: Amounts.stringify(v.pendingOutgoing),
|
||||
hasPendingTransactions: false,
|
||||
requiresUserInput: false,
|
||||
Object.keys(balanceStore)
|
||||
.sort()
|
||||
.forEach((c) => {
|
||||
const v = balanceStore[c];
|
||||
balancesResponse.balances.push({
|
||||
available: Amounts.stringify(v.available),
|
||||
pendingIncoming: Amounts.stringify(v.pendingIncoming),
|
||||
pendingOutgoing: Amounts.stringify(v.pendingOutgoing),
|
||||
hasPendingTransactions: false,
|
||||
requiresUserInput: false,
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
return balancesResponse;
|
||||
}
|
||||
|
@ -20,8 +20,6 @@
|
||||
import { InternalWalletState } from "./state";
|
||||
import {
|
||||
Stores,
|
||||
ReserveRecordStatus,
|
||||
PurchaseRecord,
|
||||
WithdrawalSourceType,
|
||||
} from "../types/dbTypes";
|
||||
import { Amounts, AmountJson } from "../util/amounts";
|
||||
@ -182,14 +180,6 @@ export async function getTransactions(
|
||||
if (shouldSkipSearch(transactionsRequest, [])) {
|
||||
return;
|
||||
}
|
||||
switch (r.reserveStatus) {
|
||||
case ReserveRecordStatus.WAIT_CONFIRM_BANK:
|
||||
break;
|
||||
case ReserveRecordStatus.WITHDRAWING:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (r.initialWithdrawalStarted) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
from taler.util.amount import Amount
|
||||
|
||||
|
||||
def check_single_balance(balances, available, pending_in="TESTKUDOS:0", pending_out="TESTKUDOS:0",
|
||||
has_pending=False):
|
||||
def check_single_balance(
|
||||
balances,
|
||||
available,
|
||||
pending_in=Amount.parse("TESTKUDOS:0"),
|
||||
pending_out=Amount.parse("TESTKUDOS:0"),
|
||||
):
|
||||
assert len(balances) == 1
|
||||
assert balances[0]["available"] == available
|
||||
assert balances[0]["pendingIncoming"] == pending_in
|
||||
assert balances[0]["pendingOutgoing"] == pending_out
|
||||
assert balances[0]["hasPendingTransactions"] == has_pending
|
||||
assert Amount.parse(balances[0]["available"]) == available
|
||||
assert Amount.parse(balances[0]["pendingIncoming"]) == pending_in
|
||||
assert Amount.parse(balances[0]["pendingOutgoing"]) == pending_out
|
||||
|
||||
|
||||
def json_to_amount(d):
|
||||
|
@ -3,8 +3,24 @@ from subprocess import run
|
||||
|
||||
import psutil
|
||||
|
||||
import requests
|
||||
|
||||
import secrets
|
||||
|
||||
from .taler_service import TalerService
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class BankUser:
|
||||
username: str
|
||||
password: str
|
||||
|
||||
@dataclass
|
||||
class WithdrawUriResponse:
|
||||
taler_withdraw_uri: str
|
||||
withdrawal_id: str
|
||||
|
||||
|
||||
class Bank(TalerService):
|
||||
|
||||
@ -14,7 +30,7 @@ class Bank(TalerService):
|
||||
# get localhost port and store bank URL
|
||||
r = run(["taler-config", "-c", config.conf, "-s", "BANK", "-o", "HTTP_PORT"],
|
||||
check=True, text=True, capture_output=True)
|
||||
self.url = "http://localhost:%s" % r.stdout.rstrip()
|
||||
self.url = "http://localhost:%s/" % r.stdout.rstrip()
|
||||
|
||||
def start(self):
|
||||
db = "postgres:///%s" % self.config.db
|
||||
@ -33,6 +49,35 @@ class Bank(TalerService):
|
||||
|
||||
self.request.addfinalizer(close_log)
|
||||
|
||||
def register_random_user(self):
|
||||
username = f"testuser-{secrets.token_hex(10)}"
|
||||
password = f"testpw-{secrets.token_hex(10)}"
|
||||
requests.post(
|
||||
f"{self.url}testing/register",
|
||||
json=dict(username=username, password=password)
|
||||
)
|
||||
return BankUser(username, password)
|
||||
|
||||
def generate_withdraw_uri(self, bankuser, amount):
|
||||
auth = (bankuser.username, bankuser.password)
|
||||
resp = requests.post(
|
||||
f"{self.url}accounts/{bankuser.username}/withdrawals",
|
||||
json=dict(amount=amount),
|
||||
auth=auth
|
||||
)
|
||||
rj = resp.json()
|
||||
return WithdrawUriResponse(
|
||||
taler_withdraw_uri=rj["taler_withdraw_uri"],
|
||||
withdrawal_id=rj["withdrawal_id"],
|
||||
)
|
||||
|
||||
def confirm_withdrawal(self, bankuser, withdrawal_id):
|
||||
auth = (bankuser.username, bankuser.password)
|
||||
resp = requests.post(
|
||||
f"{self.url}accounts/{bankuser.username}/withdrawals/{withdrawal_id}/confirm",
|
||||
auth=auth
|
||||
)
|
||||
|
||||
# Alternative way to check if the bank came up.
|
||||
# Testing the URL has the issue that on the CI, django keeps closing the connection.
|
||||
@staticmethod
|
||||
|
@ -37,11 +37,15 @@ class Wallet:
|
||||
], timeout=10, check=True, text=True, capture_output=True)
|
||||
self.write_to_log(r.stderr)
|
||||
|
||||
def gen_withdraw_uri(self, amount, bank_url):
|
||||
r = run(["taler-wallet-cli", self.arg_db, "testing", "gen-withdraw-uri",
|
||||
"-a", amount,
|
||||
"-b", bank_url
|
||||
], timeout=10, check=True, text=True, capture_output=True)
|
||||
def run_pending(self):
|
||||
r = run(["taler-wallet-cli", self.arg_db, "run-pending"],
|
||||
timeout=10, check=True, text=True, capture_output=True)
|
||||
self.write_to_log(r.stderr)
|
||||
return r.stdout.rstrip()
|
||||
|
||||
def run_until_done(self):
|
||||
r = run(["taler-wallet-cli", self.arg_db, "run-until-done"],
|
||||
timeout=10, check=True, text=True, capture_output=True)
|
||||
self.write_to_log(r.stderr)
|
||||
return r.stdout.rstrip()
|
||||
|
||||
|
@ -6,17 +6,19 @@ from tests import check_single_balance
|
||||
|
||||
|
||||
def test_withdrawal(exchange, bank, wallet):
|
||||
bank_user = bank.register_random_user()
|
||||
|
||||
# assert that we start with no transactions
|
||||
result = wallet.cmd("getTransactions")
|
||||
assert not result["transactions"]
|
||||
|
||||
# test withdrawal
|
||||
amount_raw = "TESTKUDOS:5"
|
||||
wallet.testing_withdraw(amount_raw, exchange.url, bank.url)
|
||||
amount_raw = Amount.parse("TESTKUDOS:5")
|
||||
wallet.testing_withdraw(amount_raw.stringify(), exchange.url, bank.url)
|
||||
|
||||
# check that balance is correct
|
||||
result = wallet.cmd("getBalances")
|
||||
amount_effective = Amount("TESTKUDOS", 4, 84000000).stringify()
|
||||
amount_effective = Amount("TESTKUDOS", 4, 84000000)
|
||||
check_single_balance(result["balances"], amount_effective)
|
||||
|
||||
# assert that withdrawal shows up properly in transactions
|
||||
@ -24,8 +26,8 @@ def test_withdrawal(exchange, bank, wallet):
|
||||
assert len(result["transactions"]) == 1
|
||||
transaction = result["transactions"][0]
|
||||
assert transaction["type"] == "withdrawal"
|
||||
assert transaction["amountEffective"] == amount_effective
|
||||
assert transaction["amountRaw"] == amount_raw
|
||||
assert Amount.parse(transaction["amountEffective"]) == amount_effective
|
||||
assert Amount.parse(transaction["amountRaw"]) == amount_raw
|
||||
assert transaction["exchangeBaseUrl"] == exchange.url
|
||||
assert not transaction["pending"]
|
||||
withdrawal_details = transaction["withdrawalDetails"]
|
||||
@ -34,12 +36,13 @@ def test_withdrawal(exchange, bank, wallet):
|
||||
assert withdrawal_details["exchangePaytoUris"] == payto_list
|
||||
|
||||
# get a withdrawal URI
|
||||
uri = wallet.gen_withdraw_uri(amount_raw, bank.url)
|
||||
bank_uri_resp = bank.generate_withdraw_uri(bank_user, "TESTKUDOS:5")
|
||||
uri = bank_uri_resp.taler_withdraw_uri
|
||||
assert uri.startswith("taler+http://withdraw")
|
||||
|
||||
# get withdrawal details from URI
|
||||
result = wallet.cmd("getWithdrawalDetailsForUri", {"talerWithdrawUri": uri})
|
||||
assert result["amount"] == amount_raw
|
||||
assert Amount.parse(result["amount"]) == amount_raw
|
||||
assert result["defaultExchangeBaseUrl"] == exchange.url
|
||||
assert len(result["possibleExchanges"]) == 1
|
||||
assert result["possibleExchanges"][0]["exchangeBaseUrl"] == exchange.url
|
||||
@ -47,10 +50,10 @@ def test_withdrawal(exchange, bank, wallet):
|
||||
assert result["possibleExchanges"][0]["paytoUris"] == payto_list
|
||||
|
||||
# check withdrawal details for amount
|
||||
request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw}
|
||||
request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw.stringify()}
|
||||
result = wallet.cmd("getWithdrawalDetailsForAmount", request)
|
||||
assert result["amountRaw"] == amount_raw
|
||||
assert result["amountEffective"] == amount_effective
|
||||
assert Amount.parse(result["amountRaw"]) == amount_raw
|
||||
assert Amount.parse(result["amountEffective"]) == amount_effective
|
||||
assert result["paytoUris"] == payto_list
|
||||
assert not result["tosAccepted"]
|
||||
|
||||
@ -64,29 +67,33 @@ def test_withdrawal(exchange, bank, wallet):
|
||||
wallet.cmd("setExchangeTosAccepted", request)
|
||||
|
||||
# check that ToS are now shown as accepted
|
||||
request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw}
|
||||
request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw.stringify()}
|
||||
result = wallet.cmd("getWithdrawalDetailsForAmount", request)
|
||||
assert result["tosAccepted"]
|
||||
|
||||
# accept withdrawal
|
||||
request = {"exchangeBaseUrl": exchange.url, "talerWithdrawUri": uri}
|
||||
result = wallet.cmd("acceptBankIntegratedWithdrawal", request)
|
||||
assert result["confirmTransferUrl"].startswith(bank.url + "/confirm-withdrawal/")
|
||||
assert result["confirmTransferUrl"].startswith(bank.url + "confirm-withdrawal/")
|
||||
confirm_url = result["confirmTransferUrl"]
|
||||
|
||||
# Let the wallet do its work. At this point, the bank-integrated
|
||||
# withdrawal won't have succeeded yet, as it's not confirmed at the bank
|
||||
# side.
|
||||
wallet.run_pending()
|
||||
|
||||
# check that balance is correct
|
||||
result = wallet.cmd("getBalances")
|
||||
# TODO pendingIncoming and hasPendingTransactions are wrong, right?
|
||||
print(result)
|
||||
# check_single_balance(result["balances"], amount_effective, amount_effective, has_pending=True)
|
||||
check_single_balance(result["balances"], amount_effective, amount_effective)
|
||||
|
||||
# assert that 2nd withdrawal shows up properly in transactions
|
||||
result = wallet.cmd("getTransactions")
|
||||
assert len(result["transactions"]) == 2
|
||||
transaction = result["transactions"][0]
|
||||
assert transaction["type"] == "withdrawal"
|
||||
assert transaction["amountEffective"] == amount_effective
|
||||
assert transaction["amountRaw"] == amount_raw
|
||||
assert Amount.parse(transaction["amountEffective"]) == amount_effective
|
||||
assert Amount.parse(transaction["amountRaw"]) == amount_raw
|
||||
assert transaction["exchangeBaseUrl"] == exchange.url
|
||||
assert transaction["pending"]
|
||||
withdrawal_details = transaction["withdrawalDetails"]
|
||||
@ -99,22 +106,35 @@ def test_withdrawal(exchange, bank, wallet):
|
||||
timestamp1 = result["transactions"][1]["timestamp"]["t_ms"]
|
||||
assert timestamp0 > timestamp1
|
||||
|
||||
# now we actually confirm the withdrawal
|
||||
bank.confirm_withdrawal(bank_user, bank_uri_resp.withdrawal_id)
|
||||
# It might take some time until the exchange knows about the reserve,
|
||||
# so we'll try until it works.
|
||||
wallet.run_until_done()
|
||||
|
||||
# check that balance is correct
|
||||
result = wallet.cmd("getBalances")
|
||||
print(result)
|
||||
check_single_balance(
|
||||
result["balances"], Amount.parse("TESTKUDOS:9.68"), Amount.parse("TESTKUDOS:0"),
|
||||
)
|
||||
|
||||
# one more manual withdrawal
|
||||
request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw}
|
||||
request = {"exchangeBaseUrl": exchange.url, "amount": amount_raw.stringify()}
|
||||
result = wallet.cmd("acceptManualWithdrawal", request)
|
||||
assert len(result["exchangePaytoUris"]) == 1
|
||||
result["exchangePaytoUris"][0].startswith(payto_list[0])
|
||||
|
||||
# check that balance is correct
|
||||
result = wallet.cmd("getBalances")
|
||||
# TODO pendingIncoming and hasPendingTransactions are wrong, right?
|
||||
print(result)
|
||||
# check_single_balance(result["balances"], amount_effective, TODO, has_pending=True)
|
||||
check_single_balance(
|
||||
result["balances"], amount_effective + amount_effective, amount_effective
|
||||
)
|
||||
|
||||
# assert that 3nd withdrawal shows up properly in transactions
|
||||
result = wallet.cmd("getTransactions")
|
||||
# TODO where is the manual withdrawal!??
|
||||
# assert len(result["transactions"]) == 3
|
||||
assert len(result["transactions"]) == 3
|
||||
for t in result["transactions"]:
|
||||
print(t)
|
||||
print()
|
||||
|
Loading…
Reference in New Issue
Block a user