mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-17 22:24:23 +01:00
Adaps unit tests. Speeds up tests by removing unnecesary sleeps
This commit is contained in:
@@ -9,23 +9,31 @@ from threading import Thread
|
||||
from teos.carrier import Carrier
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
from teos.block_processor import BlockProcessor
|
||||
from teos.gatekeeper import Gatekeeper, UserInfo
|
||||
from teos.appointments_dbm import AppointmentsDBM
|
||||
from teos.responder import Responder, TransactionTracker
|
||||
from teos.responder import Responder, TransactionTracker, CONFIRMATIONS_BEFORE_RETRY
|
||||
|
||||
from common.constants import LOCATOR_LEN_HEX
|
||||
from bitcoind_mock.transaction import create_dummy_transaction, create_tx_from_hex
|
||||
from test.teos.unit.conftest import (
|
||||
generate_block,
|
||||
generate_blocks,
|
||||
generate_block_w_delay,
|
||||
generate_blocks_w_delay,
|
||||
get_random_value_hex,
|
||||
bitcoind_connect_params,
|
||||
bitcoind_feed_params,
|
||||
get_config,
|
||||
)
|
||||
|
||||
|
||||
config = get_config()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def responder(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
def responder(db_manager, gatekeeper, carrier, block_processor):
|
||||
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
@@ -66,28 +74,26 @@ def create_dummy_tracker_data(random_txid=False, penalty_rawtx=None):
|
||||
if random_txid is True:
|
||||
penalty_txid = get_random_value_hex(32)
|
||||
|
||||
appointment_end = bitcoin_cli(bitcoind_connect_params).getblockcount() + 2
|
||||
locator = dispute_txid[:LOCATOR_LEN_HEX]
|
||||
user_id = get_random_value_hex(16)
|
||||
|
||||
return locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end
|
||||
return locator, dispute_txid, penalty_txid, penalty_rawtx, user_id
|
||||
|
||||
|
||||
def create_dummy_tracker(random_txid=False, penalty_rawtx=None):
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
||||
random_txid, penalty_rawtx
|
||||
)
|
||||
return TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end)
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, expiry = create_dummy_tracker_data(random_txid, penalty_rawtx)
|
||||
return TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, expiry)
|
||||
|
||||
|
||||
def test_tracker_init(run_bitcoind):
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data()
|
||||
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end)
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data()
|
||||
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, user_id)
|
||||
|
||||
assert (
|
||||
tracker.dispute_txid == dispute_txid
|
||||
and tracker.penalty_txid == penalty_txid
|
||||
and tracker.penalty_rawtx == penalty_rawtx
|
||||
and tracker.appointment_end == appointment_end
|
||||
and tracker.user_id == user_id
|
||||
)
|
||||
|
||||
|
||||
@@ -115,7 +121,7 @@ def test_tracker_to_dict():
|
||||
assert (
|
||||
tracker.locator == tracker_dict["locator"]
|
||||
and tracker.penalty_rawtx == tracker_dict["penalty_rawtx"]
|
||||
and tracker.appointment_end == tracker_dict["appointment_end"]
|
||||
and tracker.user_id == tracker_dict["user_id"]
|
||||
)
|
||||
|
||||
|
||||
@@ -129,7 +135,7 @@ def test_tracker_from_dict():
|
||||
def test_tracker_from_dict_invalid_data():
|
||||
tracker_dict = create_dummy_tracker().to_dict()
|
||||
|
||||
for value in ["dispute_txid", "penalty_txid", "penalty_rawtx", "appointment_end"]:
|
||||
for value in ["dispute_txid", "penalty_txid", "penalty_rawtx", "user_id"]:
|
||||
tracker_dict_copy = deepcopy(tracker_dict)
|
||||
tracker_dict_copy[value] = None
|
||||
|
||||
@@ -141,17 +147,22 @@ def test_tracker_from_dict_invalid_data():
|
||||
assert True
|
||||
|
||||
|
||||
def test_init_responder(temp_db_manager, carrier, block_processor):
|
||||
responder = Responder(temp_db_manager, carrier, block_processor)
|
||||
def test_init_responder(temp_db_manager, gatekeeper, carrier, block_processor):
|
||||
responder = Responder(temp_db_manager, gatekeeper, carrier, block_processor)
|
||||
assert isinstance(responder.trackers, dict) and len(responder.trackers) == 0
|
||||
assert isinstance(responder.tx_tracker_map, dict) and len(responder.tx_tracker_map) == 0
|
||||
assert isinstance(responder.unconfirmed_txs, list) and len(responder.unconfirmed_txs) == 0
|
||||
assert isinstance(responder.missed_confirmations, dict) and len(responder.missed_confirmations) == 0
|
||||
assert responder.block_queue.empty()
|
||||
assert isinstance(responder.block_queue, Queue) and responder.block_queue.empty()
|
||||
assert isinstance(responder.db_manager, AppointmentsDBM)
|
||||
assert isinstance(responder.gatekeeper, Gatekeeper)
|
||||
assert isinstance(responder.carrier, Carrier)
|
||||
assert isinstance(responder.block_processor, BlockProcessor)
|
||||
assert responder.last_known_block is None or isinstance(responder.last_known_block, str)
|
||||
|
||||
|
||||
def test_handle_breach(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
def test_handle_breach(db_manager, gatekeeper, carrier, block_processor):
|
||||
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||
|
||||
uuid = uuid4().hex
|
||||
tracker = create_dummy_tracker()
|
||||
@@ -163,17 +174,17 @@ def test_handle_breach(db_manager, carrier, block_processor):
|
||||
tracker.dispute_txid,
|
||||
tracker.penalty_txid,
|
||||
tracker.penalty_rawtx,
|
||||
tracker.appointment_end,
|
||||
tracker.user_id,
|
||||
block_hash=get_random_value_hex(32),
|
||||
)
|
||||
|
||||
assert receipt.delivered is True
|
||||
|
||||
|
||||
def test_handle_breach_bad_response(db_manager, block_processor):
|
||||
def test_handle_breach_bad_response(db_manager, gatekeeper, block_processor):
|
||||
# We need a new carrier here, otherwise the transaction will be flagged as previously sent and receipt.delivered
|
||||
# will be True
|
||||
responder = Responder(db_manager, Carrier(bitcoind_connect_params), block_processor)
|
||||
responder = Responder(db_manager, gatekeeper, Carrier(bitcoind_connect_params), block_processor)
|
||||
|
||||
uuid = uuid4().hex
|
||||
tracker = create_dummy_tracker()
|
||||
@@ -188,7 +199,7 @@ def test_handle_breach_bad_response(db_manager, block_processor):
|
||||
tracker.dispute_txid,
|
||||
tracker.penalty_txid,
|
||||
tracker.penalty_rawtx,
|
||||
tracker.appointment_end,
|
||||
tracker.user_id,
|
||||
block_hash=get_random_value_hex(32),
|
||||
)
|
||||
|
||||
@@ -199,9 +210,7 @@ def test_add_tracker(responder):
|
||||
for _ in range(20):
|
||||
uuid = uuid4().hex
|
||||
confirmations = 0
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
||||
random_txid=True
|
||||
)
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(random_txid=True)
|
||||
|
||||
# Check the tracker is not within the responder trackers before adding it
|
||||
assert uuid not in responder.trackers
|
||||
@@ -209,7 +218,7 @@ def test_add_tracker(responder):
|
||||
assert penalty_txid not in responder.unconfirmed_txs
|
||||
|
||||
# And that it is afterwards
|
||||
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
||||
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||
assert uuid in responder.trackers
|
||||
assert penalty_txid in responder.tx_tracker_map
|
||||
assert penalty_txid in responder.unconfirmed_txs
|
||||
@@ -219,18 +228,18 @@ def test_add_tracker(responder):
|
||||
assert (
|
||||
tracker.get("penalty_txid") == penalty_txid
|
||||
and tracker.get("locator") == locator
|
||||
and tracker.get("appointment_end") == appointment_end
|
||||
and tracker.get("user_id") == user_id
|
||||
)
|
||||
|
||||
|
||||
def test_add_tracker_same_penalty_txid(responder):
|
||||
confirmations = 0
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(random_txid=True)
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(random_txid=True)
|
||||
uuid_1 = uuid4().hex
|
||||
uuid_2 = uuid4().hex
|
||||
|
||||
responder.add_tracker(uuid_1, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
||||
responder.add_tracker(uuid_2, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
||||
responder.add_tracker(uuid_1, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||
responder.add_tracker(uuid_2, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||
|
||||
# Check that both trackers have been added
|
||||
assert uuid_1 in responder.trackers and uuid_2 in responder.trackers
|
||||
@@ -243,7 +252,7 @@ def test_add_tracker_same_penalty_txid(responder):
|
||||
assert (
|
||||
tracker.get("penalty_txid") == penalty_txid
|
||||
and tracker.get("locator") == locator
|
||||
and tracker.get("appointment_end") == appointment_end
|
||||
and tracker.get("user_id") == user_id
|
||||
)
|
||||
|
||||
|
||||
@@ -251,35 +260,42 @@ def test_add_tracker_already_confirmed(responder):
|
||||
for i in range(20):
|
||||
uuid = uuid4().hex
|
||||
confirmations = i + 1
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(
|
||||
penalty_rawtx=create_dummy_transaction().hex()
|
||||
)
|
||||
|
||||
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
||||
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||
|
||||
assert penalty_txid not in responder.unconfirmed_txs
|
||||
|
||||
|
||||
def test_do_watch(temp_db_manager, carrier, block_processor):
|
||||
def test_do_watch(temp_db_manager, gatekeeper, carrier, block_processor):
|
||||
# Create a fresh responder to simplify the test
|
||||
responder = Responder(temp_db_manager, carrier, block_processor)
|
||||
responder = Responder(temp_db_manager, gatekeeper, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
trackers = [create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(20)]
|
||||
subscription_expiry = responder.block_processor.get_block_count() + 110
|
||||
|
||||
# Let's set up the trackers first
|
||||
for tracker in trackers:
|
||||
uuid = uuid4().hex
|
||||
|
||||
# Simulate user registration
|
||||
responder.gatekeeper.registered_users[tracker.user_id] = UserInfo(
|
||||
available_slots=10, subscription_expiry=subscription_expiry
|
||||
)
|
||||
|
||||
responder.trackers[uuid] = {
|
||||
"locator": tracker.locator,
|
||||
"penalty_txid": tracker.penalty_txid,
|
||||
"appointment_end": tracker.appointment_end,
|
||||
"user_id": tracker.user_id,
|
||||
}
|
||||
responder.tx_tracker_map[tracker.penalty_txid] = [uuid]
|
||||
responder.missed_confirmations[tracker.penalty_txid] = 0
|
||||
responder.unconfirmed_txs.append(tracker.penalty_txid)
|
||||
responder.gatekeeper.registered_users[tracker.user_id].appointments.append(uuid)
|
||||
|
||||
# We also need to store the info in the db
|
||||
responder.db_manager.create_triggered_appointment_flag(uuid)
|
||||
@@ -295,32 +311,29 @@ def test_do_watch(temp_db_manager, carrier, block_processor):
|
||||
broadcast_txs.append(tracker.penalty_txid)
|
||||
|
||||
# Mine a block
|
||||
generate_block()
|
||||
generate_block_w_delay()
|
||||
|
||||
# The transactions we sent shouldn't be in the unconfirmed transaction list anymore
|
||||
assert not set(broadcast_txs).issubset(responder.unconfirmed_txs)
|
||||
|
||||
# TODO: test that reorgs can be detected once data persistence is merged (new version of the simulator)
|
||||
# CONFIRMATIONS_BEFORE_RETRY+1 blocks after, the responder should rebroadcast the unconfirmed txs (15 remaining)
|
||||
generate_blocks_w_delay(CONFIRMATIONS_BEFORE_RETRY + 1)
|
||||
assert len(responder.unconfirmed_txs) == 0
|
||||
assert len(responder.trackers) == 20
|
||||
|
||||
# Generating 5 additional blocks should complete the 5 trackers
|
||||
generate_blocks(5)
|
||||
# Generating 100 - CONFIRMATIONS_BEFORE_RETRY -2 additional blocks should complete the first 5 trackers
|
||||
generate_blocks_w_delay(100 - CONFIRMATIONS_BEFORE_RETRY - 2)
|
||||
assert len(responder.unconfirmed_txs) == 0
|
||||
assert len(responder.trackers) == 15
|
||||
|
||||
assert not set(broadcast_txs).issubset(responder.tx_tracker_map)
|
||||
|
||||
# Do the rest
|
||||
broadcast_txs = []
|
||||
for tracker in trackers[5:]:
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||
broadcast_txs.append(tracker.penalty_txid)
|
||||
|
||||
# Mine a block
|
||||
generate_blocks(6)
|
||||
|
||||
assert len(responder.tx_tracker_map) == 0
|
||||
# CONFIRMATIONS_BEFORE_RETRY additional blocks should complete the rest
|
||||
generate_blocks_w_delay(CONFIRMATIONS_BEFORE_RETRY)
|
||||
assert len(responder.unconfirmed_txs) == 0
|
||||
assert len(responder.trackers) == 0
|
||||
|
||||
|
||||
def test_check_confirmations(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
def test_check_confirmations(db_manager, gatekeeper, carrier, block_processor):
|
||||
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
@@ -376,68 +389,69 @@ def test_get_txs_to_rebroadcast(responder):
|
||||
assert txs_to_rebroadcast == list(txs_missing_too_many_conf.keys())
|
||||
|
||||
|
||||
def test_get_completed_trackers(db_manager, carrier, block_processor):
|
||||
def test_get_completed_trackers(db_manager, gatekeeper, carrier, block_processor):
|
||||
initial_height = bitcoin_cli(bitcoind_connect_params).getblockcount()
|
||||
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
# A complete tracker is a tracker that has reached the appointment end with enough confs (> MIN_CONFIRMATIONS)
|
||||
# We'll create three type of transactions: end reached + enough conf, end reached + no enough conf, end not reached
|
||||
trackers_end_conf = {
|
||||
# A complete tracker is a tracker which penalty transaction has been irrevocably resolved (i.e. has reached 100
|
||||
# confirmations)
|
||||
# We'll create 3 type of txs: irrevocably resolved, confirmed but not irrevocably resolved, and unconfirmed
|
||||
trackers_ir_resolved = {
|
||||
uuid4().hex: create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(10)
|
||||
}
|
||||
|
||||
trackers_end_no_conf = {}
|
||||
trackers_confirmed = {
|
||||
uuid4().hex: create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(10)
|
||||
}
|
||||
|
||||
trackers_unconfirmed = {}
|
||||
for _ in range(10):
|
||||
tracker = create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex())
|
||||
responder.unconfirmed_txs.append(tracker.penalty_txid)
|
||||
trackers_end_no_conf[uuid4().hex] = tracker
|
||||
|
||||
trackers_no_end = {}
|
||||
for _ in range(10):
|
||||
tracker = create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex())
|
||||
tracker.appointment_end += 10
|
||||
trackers_no_end[uuid4().hex] = tracker
|
||||
trackers_unconfirmed[uuid4().hex] = tracker
|
||||
|
||||
all_trackers = {}
|
||||
all_trackers.update(trackers_end_conf)
|
||||
all_trackers.update(trackers_end_no_conf)
|
||||
all_trackers.update(trackers_no_end)
|
||||
all_trackers.update(trackers_ir_resolved)
|
||||
all_trackers.update(trackers_confirmed)
|
||||
all_trackers.update(trackers_unconfirmed)
|
||||
|
||||
# Let's add all to the responder
|
||||
for uuid, tracker in all_trackers.items():
|
||||
responder.trackers[uuid] = {
|
||||
"locator": tracker.locator,
|
||||
"penalty_txid": tracker.penalty_txid,
|
||||
"appointment_end": tracker.appointment_end,
|
||||
"user_id": tracker.user_id,
|
||||
}
|
||||
|
||||
for uuid, tracker in all_trackers.items():
|
||||
for uuid, tracker in trackers_ir_resolved.items():
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||
|
||||
# The dummy appointments have a end_appointment time of current + 2, but trackers need at least 6 confs by default
|
||||
generate_blocks(6)
|
||||
generate_block_w_delay()
|
||||
|
||||
# And now let's check
|
||||
completed_trackers = responder.get_completed_trackers(initial_height + 6)
|
||||
completed_trackers_ids = [tracker_id for tracker_id, confirmations in completed_trackers.items()]
|
||||
ended_trackers_keys = list(trackers_end_conf.keys())
|
||||
assert set(completed_trackers_ids) == set(ended_trackers_keys)
|
||||
for uuid, tracker in trackers_confirmed.items():
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||
|
||||
# Generating 6 additional blocks should also confirm trackers_no_end
|
||||
generate_blocks(6)
|
||||
# ir_resolved have 100 confs and confirmed have 99
|
||||
generate_blocks_w_delay(99)
|
||||
|
||||
completed_trackers = responder.get_completed_trackers(initial_height + 12)
|
||||
completed_trackers_ids = [tracker_id for tracker_id, confirmations in completed_trackers.items()]
|
||||
ended_trackers_keys.extend(list(trackers_no_end.keys()))
|
||||
# Let's check
|
||||
completed_trackers = responder.get_completed_trackers()
|
||||
ended_trackers_keys = list(trackers_ir_resolved.keys())
|
||||
assert set(completed_trackers) == set(ended_trackers_keys)
|
||||
|
||||
assert set(completed_trackers_ids) == set(ended_trackers_keys)
|
||||
# Generating 1 additional block should also include confirmed
|
||||
generate_block_w_delay()
|
||||
|
||||
completed_trackers = responder.get_completed_trackers()
|
||||
ended_trackers_keys.extend(list(trackers_confirmed.keys()))
|
||||
assert set(completed_trackers) == set(ended_trackers_keys)
|
||||
|
||||
|
||||
def test_rebroadcast(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
def test_rebroadcast(db_manager, gatekeeper, carrier, block_processor):
|
||||
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
@@ -446,17 +460,13 @@ def test_rebroadcast(db_manager, carrier, block_processor):
|
||||
# Rebroadcast calls add_response with retry=True. The tracker data is already in trackers.
|
||||
for i in range(20):
|
||||
uuid = uuid4().hex
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
||||
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(
|
||||
penalty_rawtx=create_dummy_transaction().hex()
|
||||
)
|
||||
|
||||
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end)
|
||||
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, user_id)
|
||||
|
||||
responder.trackers[uuid] = {
|
||||
"locator": locator,
|
||||
"penalty_txid": penalty_txid,
|
||||
"appointment_end": appointment_end,
|
||||
}
|
||||
responder.trackers[uuid] = {"locator": locator, "penalty_txid": penalty_txid, "user_id": user_id}
|
||||
|
||||
# We need to add it to the db too
|
||||
responder.db_manager.create_triggered_appointment_flag(uuid)
|
||||
|
||||
Reference in New Issue
Block a user