diff --git a/.env-sample b/.env-sample index 49249da7..ac1ec6a9 100644 --- a/.env-sample +++ b/.env-sample @@ -166,4 +166,4 @@ MINIMUM_TARGET_CONF = 24 SLASHED_BOND_REWARD_SPLIT = 0.5 # Username for HTLCs escrows -ESCROW_USERNAME = 'admin' \ No newline at end of file +ESCROW_USERNAME = 'admin' diff --git a/docker-tests.yml b/docker-tests.yml index 782609ea..9ea5175e 100644 --- a/docker-tests.yml +++ b/docker-tests.yml @@ -86,7 +86,7 @@ services: - cln:/root/.lightning - ./docker/cln/plugins/cln-grpc-hold:/root/.lightning/plugins/cln-grpc-hold - bitcoin:/root/.bitcoin - command: --regtest --wumbo --bitcoin-rpcuser=test --bitcoin-rpcpassword=test --rest-host=0.0.0.0 --rest-port=3010 --bind-addr=127.0.0.1:9737 --max-concurrent-htlcs=483 --grpc-port=9999 --grpc-hold-port=9998 --important-plugin=/root/.lightning/plugins/cln-grpc-hold --database-upgrade=true + command: --regtest --wumbo --bitcoin-rpcuser=test --bitcoin-rpcpassword=test --log-level=debug --rest-host=0.0.0.0 --rest-port=3010 --bind-addr=127.0.0.1:9737 --max-concurrent-htlcs=483 --grpc-port=9999 --grpc-hold-port=9998 --important-plugin=/root/.lightning/plugins/cln-grpc-hold --database-upgrade=true depends_on: - bitcoind network_mode: service:bitcoind diff --git a/tests/node_utils.py b/tests/node_utils.py index 9e223820..d5cb1289 100644 --- a/tests/node_utils.py +++ b/tests/node_utils.py @@ -265,22 +265,32 @@ def generate_blocks(address, num_blocks): def pay_invoice(node_name, invoice): + reset_mission_control(node_name) node = get_node(node_name) data = {"payment_request": invoice} try: - requests.post( + response = requests.post( f'http://localhost:{node["port"]}/v1/channels/transactions', json=data, headers=node["headers"], # 0.15s is enough for LND to LND hodl ACCEPT # 0.4s is enough for LND to CLN hodl ACCEPT - timeout=0.2 if LNVENDOR == "LND" else 0.8, + timeout=0.2 if LNVENDOR == "LND" else 1, ) + print(response.json()) except ReadTimeout: # Request to pay hodl invoice has timed out: that's good! return +def reset_mission_control(node_name): + node = get_node(node_name) + requests.post( + f'http://localhost:{node["port"]}//v2/router/resetmissioncontrol', + headers=node["headers"], + ) + + def add_invoice(node_name, amount): node = get_node(node_name) data = {"value": amount} diff --git a/tests/test_coordinator_info.py b/tests/test_coordinator_info.py index 4b7c3786..ce4b90e9 100644 --- a/tests/test_coordinator_info.py +++ b/tests/test_coordinator_info.py @@ -1,5 +1,3 @@ -import json - from decouple import config from django.conf import settings from django.contrib.auth.models import User @@ -32,7 +30,7 @@ class CoordinatorInfoTest(BaseAPITestCase): path = reverse("info") response = self.client.get(path) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) diff --git a/tests/test_coordinator_limits.py b/tests/test_coordinator_limits.py new file mode 100644 index 00000000..bbeb1b65 --- /dev/null +++ b/tests/test_coordinator_limits.py @@ -0,0 +1,37 @@ +from decouple import config +from django.contrib.auth.models import User +from django.test import Client +from django.urls import reverse + +from api.tasks import cache_market +from tests.test_api import BaseAPITestCase + + +class CoordinatorInfoTest(BaseAPITestCase): + su_pass = "12345678" + su_name = config("ESCROW_USERNAME", cast=str, default="admin") + + def setUp(self): + """ + Create a superuser. The superuser is the escrow party. + """ + self.client = Client() + User.objects.create_superuser(self.su_name, "super@user.com", self.su_pass) + + # Fetch currency prices from external APIs + cache_market() + + def test_limits(self): + path = reverse("limits") + + response = self.client.get(path) + data = response.json() + + self.assertEqual(response.status_code, 200) + # self.assertResponse(response) # Expects an array + + self.assertEqual(data["1"]["code"], "USD") + self.assertIsInstance(data["1"]["price"], float) + self.assertIsInstance(data["4"]["min_amount"], float) + self.assertIsInstance(data["10"]["max_amount"], float) + self.assertEqual(data["1000"]["price"], 1) diff --git a/tests/test_trade_pipeline.py b/tests/test_trade_pipeline.py index d999b1e4..0e2969bc 100644 --- a/tests/test_trade_pipeline.py +++ b/tests/test_trade_pipeline.py @@ -1,4 +1,3 @@ -import json import random from datetime import datetime from decimal import Decimal @@ -144,7 +143,7 @@ class TradeTest(BaseAPITestCase): pub_key = read_file(f"tests/robots/{robot_index}/pub_key") enc_priv_key = read_file(f"tests/robots/{robot_index}/enc_priv_key") - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -211,7 +210,7 @@ class TradeTest(BaseAPITestCase): """ maker_form = self.maker_form_buy_with_range response = self.make_order(maker_form, robot_index=1) - data = json.loads(response.content.decode()) + data = response.json() # Checks self.assertResponse(response) @@ -325,11 +324,11 @@ class TradeTest(BaseAPITestCase): robot_index = 1 order_made_response = self.make_order(maker_form, robot_index) - order_made_data = json.loads(order_made_response.content.decode()) + order_made_data = order_made_response.json() # Maker's first order fetch. Should trigger maker bond hold invoice generation. response = self.get_order(order_made_data["id"]) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -370,7 +369,7 @@ class TradeTest(BaseAPITestCase): def make_and_publish_order(self, maker_form, robot_index=1): # Make an order order_made_response = self.make_order(maker_form, robot_index) - order_made_data = json.loads(order_made_response.content.decode()) + order_made_data = order_made_response.json() # Maker's first order fetch. Should trigger maker bond hold invoice generation. response = self.get_order(order_made_data["id"]) @@ -393,7 +392,7 @@ class TradeTest(BaseAPITestCase): maker_form = self.maker_form_buy_with_range # Get order response = self.make_and_publish_order(maker_form) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -408,7 +407,7 @@ class TradeTest(BaseAPITestCase): public_response = self.get_order( data["id"], robot_index=2, first_encounter=True ) - public_data = json.loads(public_response.content.decode()) + public_data = public_response.json() self.assertFalse(public_data["is_participant"]) self.assertIsInstance(public_data["price_now"], float) @@ -455,7 +454,7 @@ class TradeTest(BaseAPITestCase): self, maker_form, take_amount=80, maker_index=1, taker_index=2 ): response_published = self.make_and_publish_order(maker_form, maker_index) - data_publised = json.loads(response_published.content.decode()) + data_publised = response_published.json() response = self.take_order(data_publised["id"], take_amount, taker_index) return response @@ -468,7 +467,7 @@ class TradeTest(BaseAPITestCase): maker_form = self.maker_form_buy_with_range response = self.make_and_take_order(maker_form, 80, maker_index, taker_index) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -504,7 +503,7 @@ class TradeTest(BaseAPITestCase): order_taken_response = self.make_and_take_order( maker_form, take_amount, maker_index, taker_index ) - order_taken_data = json.loads(order_taken_response.content.decode()) + order_taken_data = order_taken_response.json() # Maker's first order fetch. Should trigger maker bond hold invoice generation. response = self.get_order(order_taken_data["id"], taker_index) @@ -530,7 +529,7 @@ class TradeTest(BaseAPITestCase): # Taker GET response = self.make_and_lock_contract(maker_form, 80, maker_index, taker_index) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -545,7 +544,7 @@ class TradeTest(BaseAPITestCase): # Maker GET response = self.get_order(data["id"], maker_index) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -573,7 +572,7 @@ class TradeTest(BaseAPITestCase): locked_taker_response = self.make_and_lock_contract( maker_form, take_amount, maker_index, taker_index ) - locked_taker_response_data = json.loads(locked_taker_response.content.decode()) + locked_taker_response_data = locked_taker_response.json() # Maker's first order fetch. Should trigger maker bond hold invoice generation. response = self.get_order(locked_taker_response_data["id"], taker_index) @@ -599,7 +598,7 @@ class TradeTest(BaseAPITestCase): maker_form = self.maker_form_buy_with_range response = self.trade_to_locked_escrow(maker_form, 80, maker_index, taker_index) - data = json.loads(response.content.decode()) + data = response.json() self.assertEqual(response.status_code, 200) self.assertResponse(response) @@ -850,3 +849,54 @@ class TradeTest(BaseAPITestCase): self.assertFalse(data["is_disputed"]) self.assertIsHash(data["maker_summary"]["preimage"]) self.assertIsHash(data["maker_summary"]["payment_hash"]) + + def test_cancel_public_order(self): + maker_index = 1 + maker_form = self.maker_form_buy_with_range + + response = self.make_and_publish_order(maker_form, maker_index) + response = self.cancel_order(response.json()["id"]) + data = response.json() + + self.assertEqual(response.status_code, 400) + self.assertResponse(response) + + self.assertEqual( + data["bad_request"], "This order has been cancelled by the maker" + ) + + def test_collaborative_cancel_order_in_chat(self): + maker_index = 1 + taker_index = 2 + maker_form = self.maker_form_buy_with_range + take_amount = round( + random.uniform(maker_form["min_amount"], maker_form["max_amount"]), 2 + ) + + response = self.trade_to_submitted_invoice( + maker_form, take_amount, maker_index, taker_index + ) + + # Maker asks for cancel + response = self.cancel_order(response.json()["id"], maker_index) + data = response.json() + self.assertEqual(response.status_code, 200) + self.assertResponse(response) + self.assertTrue(data["asked_for_cancel"]) + + # Taker checks order + response = self.get_order(response.json()["id"], taker_index) + data = response.json() + self.assertEqual(response.status_code, 200) + self.assertResponse(response) + self.assertTrue(data["pending_cancel"]) + + # Taker accepts (ask) the cancellation + response = self.cancel_order(response.json()["id"], taker_index) + data = response.json() + print(data) + self.assertEqual(response.status_code, 400) + self.assertResponse(response) + self.assertEqual( + data["bad_request"], "This order has been cancelled collaborativelly" + )