mirror of
https://github.com/RoboSats/robosats.git
synced 2025-07-23 03:13:23 +00:00
Add order creation tests
This commit is contained in:
@ -118,8 +118,6 @@ class MakerView(CreateAPIView):
|
|||||||
if has_range is None:
|
if has_range is None:
|
||||||
has_range = False
|
has_range = False
|
||||||
|
|
||||||
# TODO add a check - if `is_explicit` is true then `satoshis` need to be specified
|
|
||||||
|
|
||||||
# An order can either have an amount or a range (min_amount and max_amount)
|
# An order can either have an amount or a range (min_amount and max_amount)
|
||||||
if has_range:
|
if has_range:
|
||||||
amount = None
|
amount = None
|
||||||
|
1
tests/robots/2/b91_token
Normal file
1
tests/robots/2/b91_token
Normal file
@ -0,0 +1 @@
|
|||||||
|
ltdCXV@ZH=5aR;^,"gQHJ*S#|o/H,RD;:m^>0p[D
|
18
tests/robots/2/enc_priv_key
Normal file
18
tests/robots/2/enc_priv_key
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
xYYEZUepOxYJKwYBBAHaRw8BAQdAM/asZMBNC2n1cNL7nQjfF6D5pjaQ4JyX
|
||||||
|
ChldvSOxF6T+CQMIydehiycpJtLgL1oH/9M+VBYWfRk0pxm4ut/UCArptMAA
|
||||||
|
myrAl7drgV44g1XNMZSNh8z4VeJ+9NB59VNpf+XETgQHDxueBHQDs8gP0Guw
|
||||||
|
OM1MUm9ib1NhdHMgSUQgZTRjMGQ0MDE0ZmY3Y2E5MGUyZWI2Yjg4OTg3YTdm
|
||||||
|
OTg2NWMzYjViMTFjY2QxMTkxYjZjZmJkN2FmYzQ4ZjFhMsKMBBAWCgA+BYJl
|
||||||
|
R6k7BAsJBwgJkF6N1APT+xgtAxUICgQWAAIBAhkBApsDAh4BFiEE6qRwE6NG
|
||||||
|
7J8cgwUnXo3UA9P7GC0AALfZAP9UKi14KtDPz7E41diuyxbUux339WxzSWDW
|
||||||
|
qZKLXXhmpwEAmaeYM682fqcugFWhaqybLmJZJxr79OISluA2op5EBQ7HiwRl
|
||||||
|
R6k7EgorBgEEAZdVAQUBAQdAau/drRt10gnaO2365mKJpLIyjERKu+GlAfPV
|
||||||
|
tBXeaSUDAQgH/gkDCN8Sih6mM3/14KSBHq833UnFq0ZCR9al7aFSxv4R0XR+
|
||||||
|
2/bnXwwA2OnluYYuBDWM76AuFMbtWM26PDXEHnqypjK62ys9lkYaLmW1cqnn
|
||||||
|
SZHCeAQYFggAKgWCZUepOwmQXo3UA9P7GC0CmwwWIQTqpHATo0bsnxyDBSde
|
||||||
|
jdQD0/sYLQAAX3oBAO31udzR6wTfMOTH3HRpVe1vC/vAPvmsvDEITsrSLQtR
|
||||||
|
APoChbViJLFxeA9c5b8inUCG9jgAfqeIevoKDaDS1O2EDw==
|
||||||
|
=3D/z
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
1
tests/robots/2/nickname
Normal file
1
tests/robots/2/nickname
Normal file
@ -0,0 +1 @@
|
|||||||
|
EquivalentWool707
|
14
tests/robots/2/pub_key
Normal file
14
tests/robots/2/pub_key
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEZUepOxYJKwYBBAHaRw8BAQdAM/asZMBNC2n1cNL7nQjfF6D5pjaQ4JyXChld
|
||||||
|
vSOxF6S0TFJvYm9TYXRzIElEIGU0YzBkNDAxNGZmN2NhOTBlMmViNmI4ODk4N2E3
|
||||||
|
Zjk4NjVjM2I1YjExY2NkMTE5MWI2Y2ZiZDdhZmM0OGYxYTKIjAQQFgoAPgWCZUep
|
||||||
|
OwQLCQcICZBejdQD0/sYLQMVCAoEFgACAQIZAQKbAwIeARYhBOqkcBOjRuyfHIMF
|
||||||
|
J16N1APT+xgtAAC32QD/VCoteCrQz8+xONXYrssW1Lsd9/Vsc0lg1qmSi114ZqcB
|
||||||
|
AJmnmDOvNn6nLoBVoWqsmy5iWSca+/TiEpbgNqKeRAUOuDgEZUepOxIKKwYBBAGX
|
||||||
|
VQEFAQEHQGrv3a0bddIJ2jtt+uZiiaSyMoxESrvhpQHz1bQV3mklAwEIB4h4BBgW
|
||||||
|
CAAqBYJlR6k7CZBejdQD0/sYLQKbDBYhBOqkcBOjRuyfHIMFJ16N1APT+xgtAABf
|
||||||
|
egEA7fW53NHrBN8w5MfcdGlV7W8L+8A++ay8MQhOytItC1EA+gKFtWIksXF4D1zl
|
||||||
|
vyKdQIb2OAB+p4h6+goNoNLU7YQP
|
||||||
|
=8g49
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
0
tests/robots/2/token
Normal file
0
tests/robots/2/token
Normal file
@ -1,18 +1,25 @@
|
|||||||
import json
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from decouple import config
|
from decouple import config
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
|
|
||||||
|
from api.models import Currency, Order
|
||||||
|
from api.tasks import cache_market
|
||||||
|
|
||||||
|
|
||||||
class TradeTest(TestCase):
|
class TradeTest(TestCase):
|
||||||
su_pass = "12345678"
|
su_pass = "12345678"
|
||||||
su_name = config("ESCROW_USERNAME", cast=str, default="admin")
|
su_name = config("ESCROW_USERNAME", cast=str, default="admin")
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create a superuser. The superuser is the escrow party.
|
||||||
|
"""
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
User.objects.create_superuser(self.su_name, "super@user.com", self.su_pass)
|
User.objects.create_superuser(self.su_name, "super@user.com", self.su_pass)
|
||||||
print("Super user created")
|
|
||||||
|
|
||||||
def test_login_superuser(self):
|
def test_login_superuser(self):
|
||||||
path = "/coordinator/login/"
|
path = "/coordinator/login/"
|
||||||
@ -20,12 +27,16 @@ class TradeTest(TestCase):
|
|||||||
response = self.client.post(path, data)
|
response = self.client.post(path, data)
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
def get_robot_auth(self, index):
|
def get_robot_auth(self, robot_index):
|
||||||
with open(f"tests/robots/{index}/b91_token", "r") as file:
|
"""
|
||||||
|
Crates an AUTH header that embeds token, pub_key and enc_priv_key into a single string
|
||||||
|
just as requested by the robosats token middleware.
|
||||||
|
"""
|
||||||
|
with open(f"tests/robots/{robot_index}/b91_token", "r") as file:
|
||||||
b91_token = file.read()
|
b91_token = file.read()
|
||||||
with open(f"tests/robots/{index}/pub_key", "r") as file:
|
with open(f"tests/robots/{robot_index}/pub_key", "r") as file:
|
||||||
pub_key = file.read()
|
pub_key = file.read()
|
||||||
with open(f"tests/robots/{index}/enc_priv_key", "r") as file:
|
with open(f"tests/robots/{robot_index}/enc_priv_key", "r") as file:
|
||||||
enc_priv_key = file.read()
|
enc_priv_key = file.read()
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
@ -33,24 +44,24 @@ class TradeTest(TestCase):
|
|||||||
}
|
}
|
||||||
return headers, pub_key, enc_priv_key
|
return headers, pub_key, enc_priv_key
|
||||||
|
|
||||||
def create_robot(self, index):
|
def create_robot(self, robot_index):
|
||||||
"""
|
"""
|
||||||
Creates the robots in /tests/robots/{index}/
|
Creates the robots in /tests/robots/{robot_index}
|
||||||
"""
|
"""
|
||||||
path = "/api/robot/"
|
path = "/api/robot/"
|
||||||
headers, pub_key, enc_priv_key = self.get_robot_auth(index)
|
headers, pub_key, enc_priv_key = self.get_robot_auth(robot_index)
|
||||||
|
|
||||||
response = self.client.get(path, **headers)
|
response = self.client.get(path, **headers)
|
||||||
data = json.loads(response.content.decode())
|
data = json.loads(response.content.decode())
|
||||||
|
|
||||||
with open(f"tests/robots/{index}/nickname", "r") as file:
|
with open(f"tests/robots/{robot_index}/nickname", "r") as file:
|
||||||
expected_nickname = file.read()
|
expected_nickname = file.read()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["nickname"],
|
data["nickname"],
|
||||||
expected_nickname,
|
expected_nickname,
|
||||||
f"Robot {index} created nickname is not MyopicRacket333",
|
f"Robot {robot_index} created nickname is not MyopicRacket333",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["public_key"], pub_key, "Returned public Kky does not match"
|
data["public_key"], pub_key, "Returned public Kky does not match"
|
||||||
@ -77,6 +88,128 @@ class TradeTest(TestCase):
|
|||||||
|
|
||||||
def test_create_robots(self):
|
def test_create_robots(self):
|
||||||
"""
|
"""
|
||||||
Creates two robots to test trades
|
Creates two robots to be used in the trade tests
|
||||||
"""
|
"""
|
||||||
self.create_robot(index=1)
|
self.create_robot(robot_index=1)
|
||||||
|
self.create_robot(robot_index=2)
|
||||||
|
|
||||||
|
def test_cache_market(self):
|
||||||
|
cache_market()
|
||||||
|
|
||||||
|
usd = Currency.objects.get(id=1)
|
||||||
|
self.assertTrue(
|
||||||
|
isinstance(usd.exchange_rate, Decimal), "Exchange rate is not decimal"
|
||||||
|
)
|
||||||
|
self.assertLess(0, usd.exchange_rate, "Exchange rate is not higher than zero")
|
||||||
|
self.assertTrue(
|
||||||
|
isinstance(usd.timestamp, datetime),
|
||||||
|
"Externa price timestamp is not datetime",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_create_order(
|
||||||
|
self,
|
||||||
|
robot_index=1,
|
||||||
|
payment_method="Advcash Cash F2F",
|
||||||
|
min_amount=21,
|
||||||
|
max_amount=101.7,
|
||||||
|
premium=3.34,
|
||||||
|
public_duration=69360,
|
||||||
|
escrow_duration=8700,
|
||||||
|
bond_size=3.5,
|
||||||
|
latitude=34.7455,
|
||||||
|
longitude=135.503,
|
||||||
|
):
|
||||||
|
# Requisites
|
||||||
|
# Cache market prices
|
||||||
|
self.test_cache_market()
|
||||||
|
path = "/api/make/"
|
||||||
|
# Get valid robot auth headers
|
||||||
|
headers, _, _ = self.get_robot_auth(robot_index)
|
||||||
|
|
||||||
|
# Prepare request body
|
||||||
|
maker_form = {
|
||||||
|
"type": Order.Types.BUY,
|
||||||
|
"currency": 1,
|
||||||
|
"has_range": True,
|
||||||
|
"min_amount": min_amount,
|
||||||
|
"max_amount": max_amount,
|
||||||
|
"payment_method": payment_method,
|
||||||
|
"is_explicit": False,
|
||||||
|
"premium": premium,
|
||||||
|
"public_duration": public_duration,
|
||||||
|
"escrow_duration": escrow_duration,
|
||||||
|
"bond_size": bond_size,
|
||||||
|
"latitude": latitude,
|
||||||
|
"longitude": longitude,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.client.post(path, maker_form, **headers)
|
||||||
|
data = json.loads(response.content.decode())
|
||||||
|
|
||||||
|
# Checks
|
||||||
|
self.assertTrue(isinstance(data["id"], int), "Order ID is not an integer")
|
||||||
|
self.assertEqual(
|
||||||
|
data["status"],
|
||||||
|
Order.Status.WFB,
|
||||||
|
"Newly created order status is not 'Waiting for maker bond'",
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
isinstance(datetime.fromisoformat(data["created_at"]), datetime),
|
||||||
|
"Order creation timestamp is not datetime",
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
isinstance(datetime.fromisoformat(data["expires_at"]), datetime),
|
||||||
|
"Order expiry time is not datetime",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
data["type"], Order.Types.BUY, "Buy order is not of type value BUY"
|
||||||
|
)
|
||||||
|
self.assertEqual(data["currency"], 1, "Order for USD is not of currency USD")
|
||||||
|
self.assertIsNone(
|
||||||
|
data["amount"], "Order with range has a non null simple amount"
|
||||||
|
)
|
||||||
|
self.assertTrue(data["has_range"], "Order with range has a False has_range")
|
||||||
|
self.assertEqual(
|
||||||
|
float(data["min_amount"]), min_amount, "Order min amount does not match"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
float(data["max_amount"]), max_amount, "Order max amount does not match"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
data["payment_method"],
|
||||||
|
payment_method,
|
||||||
|
"Order payment method does not match",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
data["escrow_duration"],
|
||||||
|
escrow_duration,
|
||||||
|
"Order escrow duration does not match",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
float(data["bond_size"]), bond_size, "Order bond size does not match"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
float(data["latitude"]), latitude, "Order latitude does not match"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
float(data["longitude"]), longitude, "Order longitude does not match"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
float(data["premium"]), premium, "Order premium does not match"
|
||||||
|
)
|
||||||
|
self.assertFalse(
|
||||||
|
data["is_explicit"], "Relative pricing order has True is_explicit"
|
||||||
|
)
|
||||||
|
self.assertIsNone(
|
||||||
|
data["satoshis"], "Relative pricing order has non null Satoshis"
|
||||||
|
)
|
||||||
|
self.assertIsNone(data["taker"], "New order's taker is not null")
|
||||||
|
|
||||||
|
with open(f"tests/robots/{robot_index}/nickname", "r") as file:
|
||||||
|
maker_nickname = file.read()
|
||||||
|
maker_id = User.objects.get(username=maker_nickname).id
|
||||||
|
self.assertEqual(
|
||||||
|
data["maker"],
|
||||||
|
maker_id,
|
||||||
|
"Maker user ID is not that of robot index {robot_index}",
|
||||||
|
)
|
||||||
|
Reference in New Issue
Block a user