1
0
Fork 0
mirror of https://github.com/Blockstream/satellite-api.git synced 2025-03-14 11:57:48 +01:00
blockstream-satellite-api/server/tests/test_order.py

789 lines
31 KiB
Python
Raw Normal View History

import io
import os
import pytest
from http import HTTPStatus
from unittest.mock import patch
from uuid import uuid4
from constants import InvoiceStatus, OrderStatus, Regions
from database import db
from error import assert_error, get_http_error_resp
from models import Invoice, Order, RxConfirmation, TxConfirmation
from invoice_helpers import pay_invoice
from order_helpers import adjust_bids, _paid_invoices_total,\
_unpaid_invoices_total
from utils import hmac_sha256_digest
import bidding
import constants
import server
from common import check_invoice, check_upload, new_invoice,\
place_order, generate_test_order, rnd_string, upload_test_file
@pytest.fixture
def client():
app = server.create_app(from_test=True)
app.app_context().push()
with app.test_client() as client:
yield client
server.teardown_app(app)
def check_received_message(order_uuid, received_message):
path = os.path.join(constants.MSG_STORE_PATH, order_uuid)
assert os.path.exists(path)
with open(path, 'rb') as fd:
sent_message = fd.read()
assert sent_message == received_message
@patch('orders.new_invoice')
def test_file_upload(mock_new_invoice, client):
n_bytes = 500
bid = bidding.get_min_bid(n_bytes)
msg = rnd_string(n_bytes)
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bid))
rv = upload_test_file(client, msg, bid)
assert rv.status_code == HTTPStatus.OK
check_upload(rv.get_json()['uuid'], msg)
check_invoice(rv.get_json()['lightning_invoice'], rv.get_json()['uuid'])
@patch('orders.new_invoice')
def test_text_msg_upload(mock_new_invoice, client):
n_bytes = 500
bid = bidding.get_min_bid(n_bytes)
msg = rnd_string(n_bytes)
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bid))
rv = client.post('/order', data={'bid': bid, 'message': msg.encode()})
assert rv.status_code == HTTPStatus.OK
check_upload(rv.get_json()['uuid'], msg)
check_invoice(rv.get_json()['lightning_invoice'], rv.get_json()['uuid'])
def test_uploaded_file_too_small(client):
n_bytes = 0
rv = place_order(client, n_bytes)
assert_error(rv.get_json(), 'MESSAGE_FILE_TOO_SMALL')
assert rv.status_code == HTTPStatus.BAD_REQUEST
def test_uploaded_file_too_large(client):
n_bytes = constants.MAX_MESSAGE_SIZE + 1
rv = place_order(client, n_bytes)
assert_error(rv.get_json(), 'MESSAGE_FILE_TOO_LARGE')
assert rv.status_code == HTTPStatus.REQUEST_ENTITY_TOO_LARGE
@patch('orders.new_invoice')
def test_uploaded_file_max_size(mock_new_invoice, client):
n_bytes = constants.MAX_MESSAGE_SIZE
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bidding.get_min_bid(n_bytes)))
rv = place_order(client, n_bytes)
assert rv.status_code == HTTPStatus.OK
def test_uploaded_text_msg_too_large(client):
n_bytes = constants.MAX_TEXT_MSG_LEN + 1
bid = bidding.get_min_bid(n_bytes)
msg = rnd_string(n_bytes)
rv = client.post('/order', data={'bid': bid, 'message': msg.encode()})
assert rv.status_code == HTTPStatus.BAD_REQUEST
@patch('orders.new_invoice')
def test_uploaded_text_msg_max_size(mock_new_invoice, client):
n_bytes = constants.MAX_TEXT_MSG_LEN
bid = bidding.get_min_bid(n_bytes)
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bid))
bid = bidding.get_min_bid(n_bytes)
msg = rnd_string(n_bytes)
rv = client.post('/order', data={'bid': bid, 'message': msg.encode()})
assert rv.status_code == HTTPStatus.OK
@patch('orders.new_invoice')
def test_both_msg_and_file_provided(mock_new_invoice, client):
n_bytes = 500
bid = bidding.get_min_bid(n_bytes)
msg = rnd_string(n_bytes)
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bid))
rv = client.post('/order',
data={
'bid': bid,
'message': msg.encode(),
'file': (io.BytesIO(msg.encode()), 'testfile')
})
assert rv.status_code == HTTPStatus.BAD_REQUEST
def test_negative_bid(client):
n_bytes = 500
bid = -1
msg = rnd_string(n_bytes)
rv = upload_test_file(client, msg, bid)
assert 'bid' in rv.get_json()
assert rv.get_json()['bid'][0] == 'Must be greater than or equal to 0.'
assert rv.status_code == HTTPStatus.BAD_REQUEST
def test_bid_too_low(client):
n_bytes = 1000
bid = 1051
msg = rnd_string(n_bytes)
rv = upload_test_file(client, msg, bid)
assert_error(rv.get_json(), 'BID_TOO_SMALL')
assert rv.status_code == HTTPStatus.BAD_REQUEST
def test_order_without_message(client):
n_bytes = 500
bid = bidding.get_min_bid(n_bytes)
rv = client.post('/order', data={'bid': bid})
assert_error(rv.get_json(), 'MESSAGE_MISSING')
assert rv.status_code == HTTPStatus.BAD_REQUEST
@patch('orders.new_invoice')
def test_invoice_generation_failure(mock_new_invoice, client):
mock_new_invoice.return_value =\
(False,
get_http_error_resp('LIGHTNING_CHARGE_INVOICE_ERROR'))
n_bytes = 500
rv = place_order(client, n_bytes)
assert rv.status_code == HTTPStatus.BAD_REQUEST
mock_new_invoice.return_value =\
(False,
get_http_error_resp(
'LIGHTNING_CHARGE_WEBHOOK_REGISTRATION_ERROR'
))
rv = place_order(client, n_bytes)
assert rv.status_code == HTTPStatus.BAD_REQUEST
@patch('orders.new_invoice')
def test_get_order(mock_new_invoice, client):
json_response = generate_test_order(mock_new_invoice, client)
uuid = json_response['uuid']
get_rv = client.get(f'/order/{uuid}',
headers={'X-Auth-Token': json_response['auth_token']})
get_json_resp = get_rv.get_json()
assert get_rv.status_code == HTTPStatus.OK
assert get_json_resp['uuid'] == uuid
@patch('orders.new_invoice')
def test_get_order_auth_token_as_param(mock_new_invoice, client):
json_response = generate_test_order(mock_new_invoice, client)
uuid = json_response['uuid']
get_rv = client.get(f'/order/{uuid}',
data={'auth_token': json_response['auth_token']})
get_json_resp = get_rv.get_json()
assert get_rv.status_code == HTTPStatus.OK
assert get_json_resp['uuid'] == uuid
def test_get_nonexistent_order(client):
uuid = str(uuid4())
rv = client.get(f'/order/{uuid}',
headers={'X-Auth-Token': 'test-auth-token'})
assert_error(rv.get_json(), 'ORDER_NOT_FOUND')
assert rv.status_code == HTTPStatus.NOT_FOUND
@patch('orders.new_invoice')
def test_get_order_wrong_auth_token(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client)['uuid']
get_rv = client.get(f'/order/{uuid}',
headers={'X-Auth-Token': 'wrong-auth-token'})
assert_error(get_rv.get_json(), 'INVALID_AUTH_TOKEN')
assert get_rv.status_code == HTTPStatus.UNAUTHORIZED
@patch('orders.new_invoice')
def test_get_order_missing_auth_token(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client)['uuid']
get_rv = client.get(f'/order/{uuid}')
assert_error(get_rv.get_json(), 'INVALID_AUTH_TOKEN')
assert get_rv.status_code == HTTPStatus.UNAUTHORIZED
def test_adjust_bids(client):
# if the values like bid, unpaid_bid, bid_per_byte are wrong or become
# obsolete due to changes in the invoices, the adjust_bids function should
# be able to fix them all
n_bytes = 1000
paid_bid = 1000
unpaid_bid = 10000
order = Order(id=1,
uuid='a-b-c',
bid=123,
message_size=n_bytes,
bid_per_byte=56.0,
message_digest='abcd',
status=OrderStatus.pending.value,
unpaid_bid=2345,
invoices=[
new_invoice(1, InvoiceStatus.pending,
int(0.4 * unpaid_bid)),
new_invoice(1, InvoiceStatus.pending,
int(0.6 * unpaid_bid)),
new_invoice(1, InvoiceStatus.paid, int(0.3 * paid_bid)),
new_invoice(1, InvoiceStatus.paid, int(0.7 * paid_bid))
])
assert _paid_invoices_total(order) == paid_bid
assert _unpaid_invoices_total(order) == unpaid_bid
adjust_bids(order)
assert order.bid == paid_bid
assert order.unpaid_bid == unpaid_bid
expected_bid_per_byte = paid_bid / (n_bytes + 52) # w/ 52 overhead bytes
assert order.bid_per_byte == round(expected_bid_per_byte, 2)
@patch('orders.new_invoice')
def test_negative_bid_increase_error(mock_new_invoice, client):
initial_bid = 1000
json_response = generate_test_order(mock_new_invoice,
client,
bid=initial_bid)
uuid = json_response['uuid']
auth_token = json_response['auth_token']
# Bump the bid with a negative value
bump_rv = client.post(f'/order/{uuid}/bump',
data={
'bid_increase': -1,
},
headers={'X-Auth-Token': auth_token})
assert bump_rv.status_code == HTTPStatus.BAD_REQUEST
@patch('orders.new_invoice')
def test_bump_order(mock_new_invoice, client):
initial_bid = 1000
json_response = generate_test_order(mock_new_invoice,
client,
bid=initial_bid)
uuid = json_response['uuid']
auth_token = json_response['auth_token']
get_rv = client.get(f'/order/{uuid}', headers={'X-Auth-Token': auth_token})
assert get_rv.status_code == HTTPStatus.OK
get_json_resp = get_rv.get_json()
assert get_json_resp['unpaid_bid'] == initial_bid
db_order = Order.query.filter_by(uuid=uuid).first()
assert len(db_order.invoices) == 1
# Bump the bid on the existing order
bid_increase = 2500
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bid_increase))
bump_rv = client.post(f'/order/{uuid}/bump',
data={
'bid_increase': bid_increase,
},
headers={'X-Auth-Token': auth_token})
assert bump_rv.status_code == HTTPStatus.OK
# Get the order and check if the bid was bumped successfully
get_rv = client.get(f'/order/{uuid}', headers={'X-Auth-Token': auth_token})
assert get_rv.status_code == HTTPStatus.OK
get_json_resp = get_rv.get_json()
assert get_json_resp['unpaid_bid'] == initial_bid + bid_increase
db_order = Order.query.filter_by(uuid=uuid).first()
assert len(db_order.invoices) == 2
# If a bump request fails, the order should stay untouched
second_bid_increase = 3000
mock_new_invoice.return_value = \
(False,
get_http_error_resp('LIGHTNING_CHARGE_INVOICE_ERROR'))
bump_rv = client.post(f'/order/{uuid}/bump',
data={
'bid_increase': second_bid_increase,
},
headers={'X-Auth-Token': auth_token})
assert bump_rv.status_code == HTTPStatus.BAD_REQUEST
# Get the order and verify the second bid increase (which failed) was
# completely ignored
get_rv = client.get(f'/order/{uuid}', headers={'X-Auth-Token': auth_token})
assert get_rv.status_code == HTTPStatus.OK
get_json_resp = get_rv.get_json()
assert get_json_resp['unpaid_bid'] == initial_bid + bid_increase
db_order = Order.query.filter_by(uuid=uuid).first()
assert len(db_order.invoices) == 2
@patch('orders.new_invoice')
def test_cancel_order(mock_new_invoice, client):
bid = 1000
json_response = generate_test_order(mock_new_invoice, client, bid=bid)
uuid = json_response['uuid']
auth_token = json_response['auth_token']
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status == OrderStatus.pending.value
assert db_order.cancelled_at is None
# Only pending and paid orders can be cancelled
for status in OrderStatus:
db_order.status = status.value
db.session.commit()
if status in [OrderStatus.paid, OrderStatus.pending]:
delete_rv = client.delete(f'/order/{uuid}',
headers={'X-Auth-Token': auth_token})
assert delete_rv.status_code == HTTPStatus.OK
else:
delete_rv = client.delete(f'/order/{uuid}',
headers={'X-Auth-Token': auth_token})
assert delete_rv.status_code == HTTPStatus.BAD_REQUEST
assert_error(delete_rv.get_json(), 'ORDER_CANCELLATION_ERROR')
@patch('orders.new_invoice')
def test_cancel_order_twice(mock_new_invoice, client):
bid = 1000
json_response = generate_test_order(mock_new_invoice, client, bid=bid)
uuid = json_response['uuid']
auth_token = json_response['auth_token']
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status == OrderStatus.pending.value
assert db_order.cancelled_at is None
message_path = os.path.join(constants.MSG_STORE_PATH, uuid)
assert os.path.exists(message_path)
# Cancel the order
delete_rv = client.delete(f'/order/{uuid}',
headers={'X-Auth-Token': auth_token})
assert delete_rv.status_code == HTTPStatus.OK
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status == OrderStatus.cancelled.value
assert db_order.cancelled_at is not None
assert not os.path.exists(message_path)
# Try to cancel the order again
delete_rv = client.delete(f'/order/{uuid}',
headers={'X-Auth-Token': auth_token})
assert delete_rv.status_code == HTTPStatus.BAD_REQUEST
assert_error(delete_rv.get_json(), 'ORDER_CANCELLATION_ERROR')
def test_cancel_non_existing_order(client):
delete_rv = client.delete('/order/13245',
headers={'X-Auth-Token': 'token'})
assert delete_rv.status_code == HTTPStatus.NOT_FOUND
assert_error(delete_rv.get_json(), 'ORDER_NOT_FOUND')
def test_get_sent_message_for_nonexisting_uuid(client):
# Try to get message for a non existing uuid
rv = client.get('/order/some-uuid/sent_message')
assert rv.status_code == HTTPStatus.NOT_FOUND
assert_error(rv.get_json(), 'ORDER_NOT_FOUND')
@patch('orders.new_invoice')
def test_get_sent_message_for_pending_order(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client)['uuid']
# The test order has pending status. Hence, fetching via the
# /order/{uuid}/sent_message endpoint should fail. Only "sent" and
# "transmitting" orders can be requested.
rv = client.get(f'/order/{uuid}/sent_message')
assert rv.status_code == HTTPStatus.NOT_FOUND
assert_error(rv.get_json(), 'ORDER_NOT_FOUND')
@patch('orders.new_invoice')
@pytest.mark.parametrize("status",
[OrderStatus.sent, OrderStatus.transmitting])
def test_get_sent_message_from_uuid(mock_new_invoice, client, status):
uuid = generate_test_order(mock_new_invoice, client,
order_status=status)['uuid']
rv = client.get(f'/order/{uuid}/sent_message')
assert rv.status_code == HTTPStatus.OK
received_message = rv.data
check_received_message(uuid, received_message)
def test_get_sent_message_for_nonexisting_seq_number(client):
# Try to get message for a non existing seq number
rv = client.get('/message/1')
assert rv.status_code == HTTPStatus.NOT_FOUND
assert_error(rv.get_json(), 'SEQUENCE_NUMBER_NOT_FOUND')
@patch('orders.new_invoice')
def test_get_sent_message_by_seq_number_for_paid_order(mock_new_invoice,
client):
uuid = generate_test_order(mock_new_invoice, client)['uuid']
db_order = Order.query.filter_by(uuid=uuid).first()
pay_invoice(db_order.invoices[0])
db_order.tx_seq_num = 1
db.session.commit()
# Try to get sent_message for a paid order by sequence number. sent_message
# can only be retrieved for transmitting, sent, or received messages.
rv = client.get('/message/1')
assert rv.status_code == HTTPStatus.NOT_FOUND
assert_error(rv.get_json(), 'SEQUENCE_NUMBER_NOT_FOUND')
@patch('orders.new_invoice')
@pytest.mark.parametrize(
"status",
[OrderStatus.sent, OrderStatus.received, OrderStatus.transmitting])
def test_get_sent_message_by_seq_number(mock_new_invoice, client, status):
uuid = generate_test_order(mock_new_invoice,
client,
order_status=status,
tx_seq_num=1)['uuid']
# Get order's sent message by seq number
rv = client.get('/message/1')
assert rv.status_code == HTTPStatus.OK
received_message = rv.data
check_received_message(uuid, received_message)
@patch('orders.new_invoice')
def test_confirm_tx_missing_or_invalid_param(mock_new_invoice, client):
post_rv = client.post('/order/tx/1')
assert post_rv.status_code == HTTPStatus.BAD_REQUEST
post_rv = client.post('/order/tx/1', data={'regions': 'a'})
assert post_rv.status_code == HTTPStatus.BAD_REQUEST
post_rv = client.post('/order/tx/1', data={'regions': 1})
assert post_rv.status_code == HTTPStatus.BAD_REQUEST
# Confirm tx of a non existing sequence number
post_rv = client.post('/order/tx/2', data={"regions": [[1]]})
assert post_rv.status_code == HTTPStatus.NOT_FOUND
assert_error(post_rv.get_json(), 'SEQUENCE_NUMBER_NOT_FOUND')
# Create a test order but confirm Tx for an invalid region
generate_test_order(mock_new_invoice, client, tx_seq_num=1)
post_rv = client.post('/order/tx/1', data={'regions': [[20, 1]]})
assert post_rv.status_code == HTTPStatus.NOT_FOUND
assert_error(post_rv.get_json(), 'REGION_NOT_FOUND')
@patch('orders.new_invoice')
def test_confirm_tx(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=1)['uuid']
db_order = Order.query.filter_by(uuid=uuid).first()
# Confirm tx for a single region
post_rv = client.post(
'/order/tx/1', data={'regions': [[constants.Regions.t11n_afr.value]]})
assert post_rv.status_code == HTTPStatus.OK
db_tx_confirmation = TxConfirmation.query.filter_by(
order_id=db_order.id).all()
assert len(db_tx_confirmation) == 1
assert db_tx_confirmation[0].region_id == constants.SATELLITE_REGIONS[
constants.Regions.t11n_afr]['id']
# Confirm tx for multiple regions
post_rv = client.post('/order/tx/1',
data={
'regions': [[
constants.Regions.g18.value,
constants.Regions.e113.value,
constants.Regions.t11n_afr.value
]]
})
assert post_rv.status_code == HTTPStatus.OK
db_tx_confirmation = TxConfirmation.query.filter_by(
order_id=db_order.id).order_by(TxConfirmation.region_id).all()
assert len(db_tx_confirmation) == 3
assert db_tx_confirmation[0].region_id == constants.SATELLITE_REGIONS[
constants.Regions.g18]['id']
assert db_tx_confirmation[1].region_id == constants.SATELLITE_REGIONS[
constants.Regions.e113]['id']
assert db_tx_confirmation[2].region_id == constants.SATELLITE_REGIONS[
constants.Regions.t11n_afr]['id']
@patch('orders.new_invoice')
def test_confirm_rx_missing_or_invalid_param(mock_new_invoice, client):
post_rv = client.post('/order/rx/1')
assert post_rv.status_code == HTTPStatus.BAD_REQUEST
post_rv = client.post('/order/rx/1', data={'region': 'a'})
assert post_rv.status_code == HTTPStatus.BAD_REQUEST
post_rv = client.post('/order/rx/1', data={'regions': [[1, 2]]})
assert post_rv.status_code == HTTPStatus.BAD_REQUEST
# Confirm rx of a non existing sequence number
post_rv = client.post('/order/rx/2', data={"region": 1})
assert post_rv.status_code == HTTPStatus.NOT_FOUND
assert_error(post_rv.get_json(), 'SEQUENCE_NUMBER_NOT_FOUND')
# Create a test order but confirm Rx for an invalid region
generate_test_order(mock_new_invoice, client, tx_seq_num=1)
post_rv = client.post('/order/rx/1', data={'region': 20})
assert post_rv.status_code == HTTPStatus.NOT_FOUND
assert_error(post_rv.get_json(), 'REGION_NOT_FOUND')
@patch('orders.new_invoice')
def test_confirm_rx(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=1)['uuid']
db_order = Order.query.filter_by(uuid=uuid).first()
post_rv = client.post('/order/rx/1',
data={'region': constants.Regions.g18.value})
assert post_rv.status_code == HTTPStatus.OK
db_rx_confirmation = RxConfirmation.query.filter_by(
order_id=db_order.id).all()
assert len(db_rx_confirmation) == 1
assert db_rx_confirmation[0].region_id == constants.SATELLITE_REGIONS[
constants.Regions.g18]['id']
@patch('orders.new_invoice')
@pytest.mark.parametrize(
"tx_regions",
[[Regions.g18.value], [Regions.g18.value, Regions.e113.value],
[
Regions.g18.value, Regions.e113.value, Regions.t11n_afr.value,
Regions.t11n_eu.value, Regions.t18v_c.value
],
[
Regions.g18.value, Regions.e113.value, Regions.t11n_afr.value,
Regions.t11n_eu.value, Regions.t18v_c.value, Regions.t18v_c.value
]])
@pytest.mark.parametrize(
"rx_regions",
[[Regions.g18.value], [Regions.g18.value, Regions.e113.value],
[Regions.g18.value, Regions.e113.value, Regions.t18v_c.value],
[
Regions.g18.value, Regions.e113.value, Regions.t18v_c.value,
Regions.t18v_c.value
]])
def test_received_criteria_met_inadequate_regions(mock_new_invoice, client,
tx_regions, rx_regions):
uuid = generate_test_order(mock_new_invoice,
client,
order_status=OrderStatus.sent,
tx_seq_num=1)['uuid']
# Confirm tx
post_rv = client.post('/order/tx/1', data={'regions': [tx_regions]})
assert post_rv.status_code == HTTPStatus.OK
# Confirm rx
for region in rx_regions:
post_rv = client.post('/order/rx/1', data={'region': region})
assert post_rv.status_code == HTTPStatus.OK
# Order status should not change to sent because not enough regions have
# confirmed tx/rx
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status == OrderStatus.sent.value
@patch('orders.new_invoice')
def test_received_criteria_met_for_unsent_order(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=1)['uuid']
# Confirm tx for all 6 regions
post_rv = client.post('/order/tx/1',
data={'regions': [[e.value for e in Regions]]})
assert post_rv.status_code == HTTPStatus.OK
# Confirm rx for all regions except africa and europe
for region in [
Regions.g18.value, Regions.e113.value, Regions.t18v_c.value,
Regions.t18v_ku.value
]:
post_rv = client.post('/order/rx/1', data={'region': region})
assert post_rv.status_code == HTTPStatus.OK
# Although all the required Tx/Rx confirmations are available, the order
# still cannot change to "received" state, as that requires the order to be
# in "sent" state before. The test order is still in "pending" state.
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status != OrderStatus.received.value
assert db_order.status == OrderStatus.pending.value
@patch('orders.new_invoice')
def test_received_criteria_met_successfully(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice,
client,
order_status=OrderStatus.sent,
tx_seq_num=1)['uuid']
# Confirm tx for all 6 regions
post_rv = client.post('/order/tx/1',
data={'regions': [[e.value for e in Regions]]})
assert post_rv.status_code == HTTPStatus.OK
# Order's status should still be sent
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status == OrderStatus.sent.value
# Confirm rx for all regions except africa and europe
for region in [
Regions.g18.value, Regions.e113.value, Regions.t18v_c.value,
Regions.t18v_ku.value
]:
post_rv = client.post('/order/rx/1', data={'region': region})
assert post_rv.status_code == HTTPStatus.OK
# Order's status should change to received
db_order = Order.query.filter_by(uuid=uuid).first()
assert db_order.status == OrderStatus.received.value
# Synthesized rx_confirmations for africa and europe should be created
for region in [Regions.t11n_afr, Regions.t11n_eu]:
db_rx_confirmation = RxConfirmation.query.filter_by(
order_id=db_order.id).filter_by(
region_id=constants.SATELLITE_REGIONS[region]['id']).all()
assert len(db_rx_confirmation) == 1
assert db_rx_confirmation[0].presumed
@patch('orders.new_invoice')
def test_confirm_tx_repeated_regions(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=1)['uuid']
db_order1 = Order.query.filter_by(uuid=uuid).first()
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=2)['uuid']
db_order2 = Order.query.filter_by(uuid=uuid).first()
# Confirm tx for a single region
post_rv = client.post(
'/order/tx/1', data={'regions': [[constants.Regions.t11n_afr.value]]})
assert post_rv.status_code == HTTPStatus.OK
db_tx_confirmation = TxConfirmation.query.filter_by(
order_id=db_order1.id).all()
assert len(db_tx_confirmation) == 1
# Re-Confirm tx for the same region
post_rv = client.post(
'/order/tx/1', data={'regions': [[constants.Regions.t11n_afr.value]]})
assert post_rv.status_code == HTTPStatus.OK
db_tx_confirmation = TxConfirmation.query.filter_by(
order_id=db_order1.id).all()
assert len(db_tx_confirmation) == 1
# Confirm tx for multiple regions, including t11n_afr again
post_rv = client.post('/order/tx/1',
data={
'regions': [[
constants.Regions.g18.value,
constants.Regions.t18v_c.value,
constants.Regions.t11n_afr.value
]]
})
assert post_rv.status_code == HTTPStatus.OK
db_tx_confirmation = TxConfirmation.query.filter_by(
order_id=db_order1.id).all()
assert len(db_tx_confirmation) == 3
# Confirm tx for multiple regions, different order_id
post_rv = client.post('/order/tx/2',
data={
'regions': [[
constants.Regions.t11n_eu.value,
constants.Regions.t18v_ku.value,
constants.Regions.t18v_ku.value
]]
})
assert post_rv.status_code == HTTPStatus.OK
db_tx_confirmation = TxConfirmation.query.filter_by(
order_id=db_order2.id).all()
assert len(db_tx_confirmation) == 2
@patch('orders.new_invoice')
def test_confirm_rx_repeated_regions(mock_new_invoice, client):
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=1)['uuid']
db_order1 = Order.query.filter_by(uuid=uuid).first()
uuid = generate_test_order(mock_new_invoice, client, tx_seq_num=2)['uuid']
db_order2 = Order.query.filter_by(uuid=uuid).first()
# Confirm rx for a region
post_rv = client.post('/order/rx/1',
data={'region': constants.Regions.g18.value})
assert post_rv.status_code == HTTPStatus.OK
db_rx_confirmation = RxConfirmation.query.filter_by(
order_id=db_order1.id).all()
assert len(db_rx_confirmation) == 1
# Re-Confirm rx for the same region
post_rv = client.post('/order/rx/1',
data={'region': constants.Regions.g18.value})
assert post_rv.status_code == HTTPStatus.OK
db_rx_confirmation = RxConfirmation.query.filter_by(
order_id=db_order1.id).all()
assert len(db_rx_confirmation) == 1
# Confirm rx for the same region, different order_id
post_rv = client.post('/order/rx/2',
data={'region': constants.Regions.g18.value})
assert post_rv.status_code == HTTPStatus.OK
db_rx_confirmation = RxConfirmation.query.filter_by(
order_id=db_order2.id).all()
assert len(db_rx_confirmation) == 1
@patch('orders.new_invoice')
@pytest.mark.parametrize("status", [
OrderStatus.transmitting, OrderStatus.sent, OrderStatus.received,
OrderStatus.cancelled, OrderStatus.expired
])
def test_try_to_pay_a_non_pending_order(mock_new_invoice, client, status):
n_bytes = 500
invoice = new_invoice(1, InvoiceStatus.pending,
bidding.get_min_bid(n_bytes))
mock_new_invoice.return_value = (True, invoice)
post_rv = place_order(client, n_bytes)
assert post_rv.status_code == HTTPStatus.OK
uuid_order = post_rv.get_json()['uuid']
db_order = Order.query.filter_by(uuid=uuid_order).first()
db_order.status = status.value
db.session.commit()
charged_auth_token = hmac_sha256_digest(constants.LIGHTNING_WEBHOOK_KEY,
invoice.lid)
rv = client.post(f'/callback/{invoice.lid}/{charged_auth_token}')
assert rv.status_code == HTTPStatus.OK
# refetch the order and the invoice from the database
# expecation is that invoice changes its status to paid becasue
# it had the pending status, but order keeps its current status
db_invoice = Invoice.query.filter_by(lid=invoice.lid).first()
db_order = Order.query.filter_by(uuid=uuid_order).first()
assert db_invoice.status == InvoiceStatus.paid.value
assert db_order.status == status.value
assert db_invoice.paid_at is not None
@patch('orders.new_invoice')
def test_bump_non_existing_order(mock_new_invoice, client):
bid_increase = 2500
mock_new_invoice.return_value = (True,
new_invoice(1, InvoiceStatus.pending,
bid_increase))
bump_rv = client.post('/order/12345/bump',
data={
'bid_increase': bid_increase,
},
headers={'X-Auth-Token': "non-existing-token"})
assert bump_rv.status_code == HTTPStatus.NOT_FOUND
assert_error(bump_rv.get_json(), 'ORDER_NOT_FOUND')