pluto/core/tests/test_transactions.py

588 lines
20 KiB
Python

import logging
from unittest.mock import patch
from django.test import TransactionTestCase
from core.clients.aggregator import AggregatorClient
from core.models import Aggregator, Platform, Trade, Transaction, User
class TestTransactions(TransactionTestCase):
def setUp(self):
logging.disable(logging.CRITICAL)
self.user = User.objects.create_user(
username="testuser", email="test@example.com", password="test"
)
self.aggregator = Aggregator.objects.create(
user=self.user,
name="Test",
service="nordigen",
secret_id="a",
secret_key="a",
)
self.agg_client = AggregatorClient()
self.agg_client.instance = self.aggregator
self.platform = Platform.objects.create(
user=self.user,
name="Test",
service="agora",
token="a",
password="a",
otp_token="a",
username="myuser",
)
self.transaction = Transaction.objects.create(
aggregator=self.aggregator,
account_id="my account id",
transaction_id="BANKTX",
amount=1,
currency="GBP",
note="TEST-1",
)
self.trades = {
1: {
"contact_id": "uuid1",
"buyer": "test_buyer_1",
"currency": "GBP",
"asset": "XMR",
"amount_fiat": 1,
"amount_crypto": 0.3,
"reference": "TEST-1",
"provider": "REVOLUT",
},
2: {
"contact_id": "uuid2",
"buyer": "test_buyer_2",
"currency": "GBP",
"asset": "XMR",
"amount_fiat": 1,
"amount_crypto": 0.3,
"reference": "TEST-2",
"provider": "REVOLUT",
},
3: {
"contact_id": "uuid3",
"buyer": "test_buyer_3",
"currency": "GBP",
"asset": "XMR",
"amount_fiat": 1000,
"amount_crypto": 3,
"reference": "TEST-3",
"provider": "REVOLUT",
},
4: {
"contact_id": "uuid4",
"buyer": "test_buyer_4",
"currency": "GBP",
"asset": "XMR",
"amount_fiat": 10,
"amount_crypto": 0.5,
"reference": "TEST-4",
"provider": "REVOLUT",
},
5: { # to conflict with 1
"contact_id": "uuid1",
"buyer": "test_buyer_2",
"currency": "GBP",
"asset": "XMR",
"amount_fiat": 1,
"amount_crypto": 0.3,
"reference": "TEST-1",
"provider": "REVOLUT",
},
}
def create_trades(self, *numbers):
for trade_key in self.trades.keys():
if trade_key in numbers:
Trade.objects.create(
platform=self.platform,
# open=True,
**self.trades[trade_key],
)
def mock_to_usd(self, amount, currency):
if currency == "GBP":
return amount * 1.3
elif currency == "USD":
return amount
# fuck it who cares
elif currency == "SEK":
return 100
elif currency == "EUR":
return 10
@patch("core.lib.notify.sendmsg")
async def test_reference_partial_check(self, _):
self.create_trades(1, 2, 3, 4)
result = await self.agg_client.reference_partial_check(
self.platform,
"TEST-1",
"for notifications only",
"GBP",
1,
)
self.assertEqual(result, "TEST-1")
@patch("core.lib.notify.sendmsg")
async def test_reference_partial_check_subset(self, _):
self.create_trades(1, 2, 3, 4)
result = await self.agg_client.reference_partial_check(
self.platform,
"the TEST-1 in string",
"for notifications only",
"GBP",
1,
)
self.assertEqual(result, "TEST-1")
@patch("core.lib.notify.sendmsg")
async def test_reference_partial_check_multiple_match(self, _):
self.create_trades(1, 2, 3, 4, 5)
result = await self.agg_client.reference_partial_check(
self.platform,
"TEST-1",
"for notifications only",
"GBP",
1,
)
self.assertEqual(result, False)
@patch("core.lib.notify.sendmsg")
async def test_reference_partial_check_none(self, _):
# self.create_trades(1, 2, 3, 4, 5)
result = await self.agg_client.reference_partial_check(
self.platform,
"TEST-1",
"for notifications only",
"GBP",
1,
)
self.assertEqual(result, None)
@patch("core.lib.notify.sendmsg")
async def test_reference_partial_check_none_match(self, _):
self.create_trades(1, 2, 3, 4, 5)
result = await self.agg_client.reference_partial_check(
self.platform,
"NOWHERE",
"for notifications only",
"GBP",
1,
)
self.assertEqual(result, None)
def test_valid_transaction(self):
result = self.agg_client.valid_transaction(self.transaction)
self.assertEqual(result, True)
def test_valid_transaction_fail(self):
self.transaction.amount = -100
result = self.agg_client.valid_transaction(self.transaction)
self.assertEqual(result, False)
self.transaction.amount = 1
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
async def test_can_alt_lookup(self, *args):
result = await self.agg_client.can_alt_lookup(
self.platform,
999999999, # ignored
"GBP",
"IGNORED",
)
self.assertEqual(result, True)
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=500)
async def test_can_alt_lookup_fail(self, *args):
result = await self.agg_client.can_alt_lookup(
self.platform,
999999999, # ignored
"GBP",
"IGNORED",
)
self.assertEqual(result, False)
def test_find_trade(self):
self.create_trades(1, 3, 4)
result = self.agg_client.find_trade(
self.platform,
"BANKTX",
"GBP",
1,
)
self.assertEqual(result.reference, "TEST-1")
self.assertEqual(result.currency, "GBP")
self.assertEqual(result.amount_fiat, 1)
def test_find_trade_fail_two_match(self):
self.create_trades(1, 2, 3, 4) # 2 trades with same amount and currency
result = self.agg_client.find_trade(
self.platform,
"BANKTX",
"GBP",
1,
)
self.assertEqual(result, False)
def test_find_trade_fail_two_match_alt(self):
self.create_trades(1, 3, 4)
result = self.agg_client.find_trade(
self.platform,
"BANKTX",
"GBP",
88,
)
self.assertEqual(result, False)
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
async def test_amount_currency_lookup(self, *args):
self.create_trades(1, 3, 4)
result = await self.agg_client.amount_currency_lookup(
self.platform,
1,
"GBP",
"BANKTX",
"TEST-1",
)
self.assertEqual(result.reference, "TEST-1")
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
async def test_amount_currency_lookup_fail(self, *args):
self.create_trades(1, 3, 4)
result = await self.agg_client.amount_currency_lookup(
self.platform,
88,
"GBP",
"BANKTX",
"TEST-1",
)
self.assertEqual(result, None)
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=500)
async def test_amount_currency_lookup_fail_too_high(self, *args):
self.create_trades(1, 3, 4)
result = await self.agg_client.amount_currency_lookup(
self.platform,
1,
"GBP",
"BANKTX",
"TEST-1",
)
self.assertEqual(result, False)
@patch("core.lib.notify.sendmsg")
async def test_normal_lookup(self, _):
self.create_trades(1, 2, 3, 4)
result = await self.agg_client.normal_lookup(
self.platform,
"TEST-1",
"BANKTX",
"GBP",
1,
)
self.assertEqual(result.reference, "TEST-1")
self.assertEqual(result.currency, "GBP")
self.assertEqual(result.amount_fiat, 1)
@patch("core.lib.notify.sendmsg")
async def test_currency_check(self, _):
self.create_trades(1)
trade = Trade.objects.all().first()
result = await self.agg_client.currency_check(
"GBP",
trade,
)
self.assertEqual(result, True)
@patch("core.lib.notify.sendmsg")
async def test_currency_check_fail(self, _):
self.create_trades(1)
trade = Trade.objects.all().first()
result = await self.agg_client.currency_check(
"AYZ",
trade,
)
self.assertEqual(result, False)
@patch("core.lib.notify.sendmsg")
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
async def test_alt_amount_check(self, *args):
self.create_trades(1)
trade = Trade.objects.all().first()
result = await self.agg_client.alt_amount_check(
self.platform,
1.123,
"GBP",
trade,
)
self.assertEqual(result, True)
@patch("core.lib.notify.sendmsg")
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
async def test_alt_amount_check_fail(self, *args):
self.create_trades(1)
trade = Trade.objects.all().first()
result = await self.agg_client.alt_amount_check(
self.platform,
1.501,
"GBP",
trade,
)
self.assertEqual(result, False)
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_called_once_with("uuid1", "TEST-1")
self.assertEqual(self.transaction.reconciled, True)
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_second(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.note = "TEST-2"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_called_once_with("uuid2", "TEST-2")
self.assertEqual(self.transaction.reconciled, True)
self.transaction.note = "TEST-1"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_invalid(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.amount = -1
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.amount = 1
# def test_transaction_malformed(self):
# malformed_data = self.test_data_copy
# del malformed_data["amount"]
# self.transactions.transaction(malformed_data)
# self.transactions.release_funds.assert_not_called()
# malformed_data = self.test_data_copy
# del malformed_data["currency"]
# self.transactions.transaction(malformed_data)
# self.transactions.release_funds.assert_not_called()
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_no_reference_fail(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.note = "none"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.note = "TEST-1"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1.5)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_no_reference_pass(self, release, gam, to_usd, sendmsg):
self.create_trades(1)
self.transaction.note = "none"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_called_with("uuid1", "TEST-1")
self.assertEqual(self.transaction.reconciled, True)
self.transaction.note = "TEST-1"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1000)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_large(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.amount = 1000
self.transaction.note = "TEST-3"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_called_once_with("uuid3", "TEST-3")
self.assertEqual(self.transaction.reconciled, True)
self.transaction_amount_fiat = 1
self.transaction.note = "TEST-1"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=1000)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_no_reference_exceeds_max(
self, release, gam, to_usd, sendmsg
):
self.create_trades(1, 2, 3, 4)
self.transaction.amount = 1000
self.transaction.note = "noref"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.amount = 1
self.transaction.note = "TEST-1"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_wrong_currency(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.currency = "EUR"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.currency = "GBP"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_wrong_currency_noref(
self, release, gam, to_usd, sendmsg
):
self.transaction.currency = "EUR"
self.transaction.note = "none"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.currency = "GBP"
self.transaction.note = "TEST-1"
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.8, 1.8)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_wrong_amount(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.amount = 10
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.amount = 1
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.8, 1.8)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_wrong_amount_noref(self, release, gam, to_usd, sendmsg):
self.transaction.amount = 10
self.transaction.note = "none"
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.amount = 1
self.transaction.note = "TEST-1"
# def test_transaction_pending(self):
# pending_tx = self.test_data_copy
# pending_tx["data"]["state"] = "pending"
# self.transactions.transaction(pending_tx)
# self.transactions.release_funds.assert_not_called()
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_too_low(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.amount = 5
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.amount = 1
@patch("core.lib.notify.sendmsg")
@patch("core.clients.aggregator.money.to_usd", return_value=100)
@patch(
"core.clients.aggregator.money.get_acceptable_margins", return_value=(0.5, 1)
)
@patch("core.clients.aggregator.AgoraClient.release_trade_escrow")
async def test_transaction_too_high(self, release, gam, to_usd, sendmsg):
self.create_trades(1, 2, 3, 4)
self.transaction.amount = 15
await self.agg_client.transaction([self.platform], self.transaction)
release.assert_not_called()
self.assertEqual(self.transaction.reconciled, False)
self.transaction.amount = 1