2021-07-20 11:00:49 -03:00
|
|
|
import pytest
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
from common import generate_test_order
|
|
|
|
from constants import InvoiceStatus, OrderStatus
|
2021-12-21 16:31:41 -03:00
|
|
|
import transmitter
|
2021-07-20 11:00:49 -03:00
|
|
|
from database import db
|
|
|
|
from schemas import order_schema
|
|
|
|
from models import Order
|
|
|
|
from invoice_helpers import pay_invoice
|
2021-12-21 16:31:41 -03:00
|
|
|
import constants
|
2021-07-20 11:00:49 -03:00
|
|
|
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):
|
2021-12-21 16:32:10 -03:00
|
|
|
msg = order_schema.dumps(order)
|
|
|
|
mockredis.publish.assert_called_with(channel='transmissions', message=msg)
|
2021-07-20 11:00:49 -03:00
|
|
|
|
|
|
|
|
|
|
|
@patch('orders.new_invoice')
|
2021-12-21 16:31:41 -03:00
|
|
|
def test_tx_resume(mock_new_invoice, client, mockredis):
|
2021-07-20 11:00:49 -03:00
|
|
|
# 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']
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
transmitter.tx_resume()
|
2021-07-20 11:00:49 -03:00
|
|
|
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')
|
2021-12-21 16:31:41 -03:00
|
|
|
def test_tx_start(mock_new_invoice, client, mockredis):
|
2021-07-20 11:00:49 -03:00
|
|
|
# Create two orders and pay only for the first.
|
|
|
|
first_order_uuid = generate_test_order(mock_new_invoice, client)['uuid']
|
2021-12-21 16:31:41 -03:00
|
|
|
second_order_uuid = generate_test_order(mock_new_invoice,
|
|
|
|
client,
|
|
|
|
order_id=2)['uuid']
|
2021-07-20 11:00:49 -03:00
|
|
|
|
|
|
|
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
pay_invoice(first_db_order.invoices[0])
|
2021-07-20 11:00:49 -03:00
|
|
|
assert_redis_call(mockredis, first_db_order)
|
2021-12-21 16:31:41 -03:00
|
|
|
db.session.commit()
|
2021-07-20 11:00:49 -03:00
|
|
|
|
|
|
|
# The expectation is that the first order gets transmitted and the second
|
2021-12-21 16:31:41 -03:00
|
|
|
# stays untouched. The invoice callback handler should call tx_start.
|
2021-07-20 11:00:49 -03:00
|
|
|
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
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
# 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
|
|
|
|
|
2021-07-20 11:00:49 -03:00
|
|
|
|
|
|
|
@patch('orders.new_invoice')
|
2021-12-21 16:31:41 -03:00
|
|
|
def test_assign_tx_seq_num(mock_new_invoice, client):
|
2021-07-20 11:00:49 -03:00
|
|
|
# make some orders
|
2021-12-21 16:31:41 -03:00
|
|
|
first_order_uuid = generate_test_order(mock_new_invoice, client)['uuid']
|
2021-07-20 11:00:49 -03:00
|
|
|
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
|
|
|
|
assert first_db_order.tx_seq_num is None
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
second_order_uuid = generate_test_order(mock_new_invoice,
|
|
|
|
client,
|
|
|
|
order_id=2)['uuid']
|
2021-07-20 11:00:49 -03:00
|
|
|
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
|
|
|
|
assert second_db_order.tx_seq_num is None
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
third_order_uuid = generate_test_order(mock_new_invoice,
|
|
|
|
client,
|
|
|
|
order_id=3)['uuid']
|
2021-07-20 11:00:49 -03:00
|
|
|
third_db_order = Order.query.filter_by(uuid=third_order_uuid).first()
|
|
|
|
assert third_db_order.tx_seq_num is None
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
transmitter.assign_tx_seq_num(first_db_order)
|
2021-07-20 11:00:49 -03:00
|
|
|
db.session.commit()
|
|
|
|
first_db_order = Order.query.filter_by(uuid=first_order_uuid).first()
|
|
|
|
assert first_db_order.tx_seq_num == 1
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
transmitter.assign_tx_seq_num(second_db_order)
|
2021-07-20 11:00:49 -03:00
|
|
|
db.session.commit()
|
|
|
|
second_db_order = Order.query.filter_by(uuid=second_order_uuid).first()
|
|
|
|
assert second_db_order.tx_seq_num == 2
|
|
|
|
|
2021-12-21 16:31:41 -03:00
|
|
|
transmitter.assign_tx_seq_num(third_db_order)
|
2021-07-20 11:00:49 -03:00
|
|
|
db.session.commit()
|
|
|
|
third_db_order = Order.query.filter_by(uuid=third_order_uuid).first()
|
|
|
|
assert third_db_order.tx_seq_num == 3
|
2021-12-21 16:31:41 -03:00
|
|
|
|
|
|
|
|
|
|
|
@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
|