blockstream-satellite-api/server/tests/test_transmitter.py

189 lines
7.5 KiB
Python
Raw Normal View History

import pytest
from unittest.mock import patch
from common import generate_test_order
from constants import InvoiceStatus, OrderStatus
import transmitter
from database import db
from schemas import order_schema
from models import Order
from invoice_helpers import pay_invoice
import constants
import server
@pytest.fixture
def app(mockredis):
app = server.create_app(from_test=True)
app.app_context().push()
yield app
server.teardown_app(app)
@pytest.fixture
def client(app):
with app.test_client() as client:
yield client
def assert_redis_call(mockredis, order):
msg = order_schema.dumps(order)
mockredis.publish.assert_called_with(channel='transmissions', message=msg)
@patch('orders.new_invoice')
def test_tx_resume(mock_new_invoice, client, mockredis):
# Create two orders: one in transmitting state, the other in pending state.
first_order_uuid = generate_test_order(
mock_new_invoice, client,
order_status=OrderStatus.transmitting)['uuid']
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
second_order_uuid = generate_test_order(mock_new_invoice,
client,
order_id=2)['uuid']
transmitter.tx_resume()
assert_redis_call(mockredis, first_db_order)
# The expectation is that the transmitting order changes to sent. The other
# order should remain untouched.
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
assert first_db_order.status == OrderStatus.sent.value
assert first_db_order.ended_transmission_at is not None
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
assert second_db_order.status == OrderStatus.pending.value
assert second_db_order.ended_transmission_at is None
@patch('orders.new_invoice')
def test_tx_start(mock_new_invoice, client, mockredis):
# Create two orders and pay only for the first.
first_order_uuid = generate_test_order(mock_new_invoice, client)['uuid']
second_order_uuid = generate_test_order(mock_new_invoice,
client,
order_id=2)['uuid']
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
pay_invoice(first_db_order.invoices[0])
assert_redis_call(mockredis, first_db_order)
db.session.commit()
# The expectation is that the first order gets transmitted and the second
# stays untouched. The invoice callback handler should call tx_start.
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
assert first_db_order.status == OrderStatus.transmitting.value
assert first_db_order.tx_seq_num is not None
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
assert second_db_order.status == OrderStatus.pending.value
assert second_db_order.tx_seq_num is None
# Calling tx_start explicitly won't change anything since the second order
# is still unpaid
transmitter.tx_start()
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
assert second_db_order.status == OrderStatus.pending.value
assert second_db_order.tx_seq_num is None
@patch('orders.new_invoice')
def test_assign_tx_seq_num(mock_new_invoice, client):
# make some orders
first_order_uuid = generate_test_order(mock_new_invoice, client)['uuid']
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
assert first_db_order.tx_seq_num is None
second_order_uuid = generate_test_order(mock_new_invoice,
client,
order_id=2)['uuid']
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
assert second_db_order.tx_seq_num is None
third_order_uuid = generate_test_order(mock_new_invoice,
client,
order_id=3)['uuid']
third_db_order = Order.query.filter_by(uuid=third_order_uuid).first()
assert third_db_order.tx_seq_num is None
transmitter.assign_tx_seq_num(first_db_order)
db.session.commit()
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
assert first_db_order.tx_seq_num == 1
transmitter.assign_tx_seq_num(second_db_order)
db.session.commit()
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
assert second_db_order.tx_seq_num == 2
transmitter.assign_tx_seq_num(third_db_order)
db.session.commit()
third_db_order = Order.query.filter_by(uuid=third_order_uuid).first()
assert third_db_order.tx_seq_num == 3
@patch('orders.new_invoice')
def test_start(mock_new_invoice, client, mockredis):
# prepare test env
# create an old transmitted order
completed_order_uuid = generate_test_order(
mock_new_invoice,
client,
invoice_status=InvoiceStatus.paid,
order_status=OrderStatus.transmitting)['uuid']
# create two sendable orders
first_sendable_order_uuid = generate_test_order(mock_new_invoice,
client,
order_id=5,
bid=1000)['uuid']
first_sendable_db_order = \
Order.query.filter_by(uuid=first_sendable_order_uuid).first()
pay_invoice(first_sendable_db_order.invoices[0])
db.session.commit()
second_sendable_order_uuid = generate_test_order(mock_new_invoice,
client,
order_id=6,
bid=2000)['uuid']
second_sendable_db_order = \
Order.query.filter_by(uuid=second_sendable_order_uuid).first()
pay_invoice(second_sendable_db_order.invoices[0])
db.session.commit()
# tx_resume() will finalize the completed order and call
# tx_start() which leads to one of the paid orders being sent,
# The tx_start() function method tries to send the other order
# but it can't because the first sent order has not ended yet.
# The direct call to tx_end() below will force ending the first
# transmission and trigger the second transmission
transmitter.tx_resume()
transmitter.tx_start()
first_sendable_db_order = \
Order.query.filter_by(uuid=first_sendable_order_uuid).first()
second_sendable_db_order = \
Order.query.filter_by(uuid=second_sendable_order_uuid).first()
assert first_sendable_db_order.status == OrderStatus.paid.value
assert second_sendable_db_order.status == OrderStatus.transmitting.value
transmitter.tx_end(second_sendable_db_order)
completed_db_order = \
Order.query.filter_by(uuid=completed_order_uuid).first()
assert completed_db_order.status == OrderStatus.sent.value
assert completed_db_order.ended_transmission_at is not None
first_sendable_db_order = \
Order.query.filter_by(uuid=first_sendable_order_uuid).first()
second_sendable_db_order = \
Order.query.filter_by(uuid=second_sendable_order_uuid).first()
assert first_sendable_db_order.status ==\
constants.OrderStatus.transmitting.value
assert second_sendable_db_order.status ==\
constants.OrderStatus.sent.value
# The second order has a higher bid_per_byte, so it should be sent first
assert first_sendable_db_order.tx_seq_num == 2
assert second_sendable_db_order.tx_seq_num == 1