Adaps unit tests. Speeds up tests by removing unnecesary sleeps

This commit is contained in:
Sergi Delgado Segura
2020-04-16 19:05:07 +02:00
parent 8fad4d79cc
commit eb8ffb4916
12 changed files with 303 additions and 443 deletions

View File

@@ -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)