Merge #11068: qa: Move wait_until to util

08ce33f8e qa: Move wait_until to util (MarcoFalke)

Pull request description:

  This moves `wait_until` to `util.py` to make it generally available to python tests.
  Also, `wait_until` now takes an optional lock that is acquired while testing the predicate.
  Previously the lock was always acquired, even when it was not necessary, cf. `disconnect_ban.py`.

Tree-SHA512: 18e452a017a6566fa8ad09bde058e1b841e167039dc63299e70cfa7a6dcbc779581e60ca3e8eb2f1b610767d5208b9376c203eb11015b250fd0542b5eb4215a8
This commit is contained in:
MarcoFalke 2017-08-23 17:11:33 -04:00 committed by Alexander Block
parent d09f88d985
commit 956e6bc016
11 changed files with 75 additions and 86 deletions

View File

@ -109,7 +109,7 @@ class BIP65Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block)) node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
assert wait_until(lambda: "reject" in node0.last_message.keys()) wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock: with mininode_lock:
assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)') assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)')
@ -136,7 +136,7 @@ class BIP65Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block)) node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
assert wait_until (lambda: "reject" in node0.last_message.keys()) wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock: with mininode_lock:
assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD] assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
assert_equal(node0.last_message["reject"].data, block.sha256) assert_equal(node0.last_message["reject"].data, block.sha256)

View File

@ -99,7 +99,7 @@ class BIP66Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block)) node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
assert wait_until(lambda: "reject" in node0.last_message.keys()) wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock: with mininode_lock:
assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)') assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)')
@ -127,7 +127,7 @@ class BIP66Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block)) node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
assert wait_until (lambda: "reject" in node0.last_message.keys()) wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock: with mininode_lock:
# We can receive different reject messages depending on whether # We can receive different reject messages depending on whether
# bitcoind is running with multiple script check threads. If script # bitcoind is running with multiple script check threads. If script

View File

@ -4,13 +4,14 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node disconnect and ban behavior""" """Test node disconnect and ban behavior"""
from test_framework.mininode import wait_until
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (assert_equal, from test_framework.util import (
assert_equal,
assert_raises_jsonrpc, assert_raises_jsonrpc,
connect_nodes_bi, connect_nodes_bi,
wait_until,
set_node_times, set_node_times,
) )
class DisconnectBanTest(BitcoinTestFramework): class DisconnectBanTest(BitcoinTestFramework):
@ -25,7 +26,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("setban: successfully ban single IP address") self.log.info("setban: successfully ban single IP address")
assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point
self.nodes[1].setban("127.0.0.1", "add") self.nodes[1].setban("127.0.0.1", "add")
assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)
assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point
assert_equal(len(self.nodes[1].listbanned()), 1) assert_equal(len(self.nodes[1].listbanned()), 1)
@ -88,7 +89,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: successfully disconnect node by address") self.log.info("disconnectnode: successfully disconnect node by address")
address1 = self.nodes[0].getpeerinfo()[0]['addr'] address1 = self.nodes[0].getpeerinfo()[0]['addr']
self.nodes[0].disconnectnode(address=address1) self.nodes[0].disconnectnode(address=address1)
assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
self.log.info("disconnectnode: successfully reconnect node") self.log.info("disconnectnode: successfully reconnect node")
@ -99,7 +100,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: successfully disconnect node by node id") self.log.info("disconnectnode: successfully disconnect node by node id")
id1 = self.nodes[0].getpeerinfo()[0]['id'] id1 = self.nodes[0].getpeerinfo()[0]['id']
self.nodes[0].disconnectnode(nodeid=id1) self.nodes[0].disconnectnode(nodeid=id1)
assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1] assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -23,13 +23,13 @@ from test_framework.mininode import (
mininode_lock, mininode_lock,
msg_block, msg_block,
msg_getdata, msg_getdata,
wait_until,
) )
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import ( from test_framework.util import (
assert_equal, assert_equal,
connect_nodes, connect_nodes,
p2p_port, p2p_port,
wait_until,
) )
# NodeConnCB is a class containing callbacks to be executed when a P2P # NodeConnCB is a class containing callbacks to be executed when a P2P
@ -209,7 +209,7 @@ class ExampleTest(BitcoinTestFramework):
# wait_until() will loop until a predicate condition is met. Use it to test properties of the # wait_until() will loop until a predicate condition is met. Use it to test properties of the
# NodeConnCB objects. # NodeConnCB objects.
assert wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5) wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5, lock=mininode_lock)
self.log.info("Check that each block was received only once") self.log.info("Check that each block was received only once")
# The network thread uses a global lock on data access to the NodeConn objects when sending and receiving # The network thread uses a global lock on data access to the NodeConn objects when sending and receiving

View File

@ -32,7 +32,6 @@ Test is as follows:
""" """
import time import time
from test_framework.mininode import wait_until
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import * from test_framework.util import *
@ -69,7 +68,7 @@ class MempoolPersistTest(BitcoinTestFramework):
self.nodes.append(self.start_node(1, self.options.tmpdir)) self.nodes.append(self.start_node(1, self.options.tmpdir))
# Give dashd a second to reload the mempool # Give dashd a second to reload the mempool
time.sleep(1) time.sleep(1)
assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
assert_equal(len(self.nodes[1].getrawmempool()), 0) assert_equal(len(self.nodes[1].getrawmempool()), 0)
self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
@ -84,7 +83,7 @@ class MempoolPersistTest(BitcoinTestFramework):
self.stop_nodes() self.stop_nodes()
self.nodes = [] self.nodes = []
self.nodes.append(self.start_node(0, self.options.tmpdir)) self.nodes.append(self.start_node(0, self.options.tmpdir))
assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
if __name__ == '__main__': if __name__ == '__main__':
MempoolPersistTest().main() MempoolPersistTest().main()

View File

@ -67,7 +67,7 @@ class TestNode(NodeConnCB):
def request_headers_and_sync(self, locator, hashstop=0): def request_headers_and_sync(self, locator, hashstop=0):
self.clear_block_announcement() self.clear_block_announcement()
self.get_headers(locator, hashstop) self.get_headers(locator, hashstop)
assert wait_until(self.received_block_announcement, timeout=30) wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock)
self.clear_block_announcement() self.clear_block_announcement()
# Block until a block announcement for a particular block hash is # Block until a block announcement for a particular block hash is
@ -75,7 +75,7 @@ class TestNode(NodeConnCB):
def wait_for_block_announcement(self, block_hash, timeout=30): def wait_for_block_announcement(self, block_hash, timeout=30):
def received_hash(): def received_hash():
return (block_hash in self.announced_blockhashes) return (block_hash in self.announced_blockhashes)
return wait_until(received_hash, timeout=timeout) wait_until(received_hash, timeout=timeout, lock=mininode_lock)
def send_await_disconnect(self, message, timeout=30): def send_await_disconnect(self, message, timeout=30):
"""Sends a message to the node and wait for disconnect. """Sends a message to the node and wait for disconnect.
@ -83,11 +83,7 @@ class TestNode(NodeConnCB):
This is used when we want to send a message into the node that we expect This is used when we want to send a message into the node that we expect
will get us disconnected, eg an invalid block.""" will get us disconnected, eg an invalid block."""
self.send_message(message) self.send_message(message)
success = wait_until(lambda: not self.connected, timeout=timeout) wait_until(lambda: not self.connected, timeout=timeout, lock=mininode_lock)
if not success:
logger.error("send_await_disconnect failed!")
raise AssertionError("send_await_disconnect failed!")
return success
class CompactBlocksTest(BitcoinTestFramework): class CompactBlocksTest(BitcoinTestFramework):
def __init__(self): def __init__(self):
@ -143,9 +139,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Make sure we get a SENDCMPCT message from our peer # Make sure we get a SENDCMPCT message from our peer
def received_sendcmpct(): def received_sendcmpct():
return (len(test_node.last_sendcmpct) > 0) return (len(test_node.last_sendcmpct) > 0)
got_message = wait_until(received_sendcmpct, timeout=30) wait_until(received_sendcmpct, timeout=30, lock=mininode_lock)
assert(received_sendcmpct())
assert(got_message)
with mininode_lock: with mininode_lock:
# Check that the first version received is the preferred one # Check that the first version received is the preferred one
assert_equal(test_node.last_sendcmpct[0].version, preferred_version) assert_equal(test_node.last_sendcmpct[0].version, preferred_version)
@ -158,7 +152,6 @@ class CompactBlocksTest(BitcoinTestFramework):
block_hash = int(node.generate(1)[0], 16) block_hash = int(node.generate(1)[0], 16)
peer.wait_for_block_announcement(block_hash, timeout=30) peer.wait_for_block_announcement(block_hash, timeout=30)
assert(peer.block_announced) assert(peer.block_announced)
assert(got_message)
with mininode_lock: with mininode_lock:
assert predicate(peer), ( assert predicate(peer), (
@ -255,7 +248,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Wait until we've seen the block announcement for the resulting tip # Wait until we've seen the block announcement for the resulting tip
tip = int(node.getbestblockhash(), 16) tip = int(node.getbestblockhash(), 16)
assert(test_node.wait_for_block_announcement(tip)) test_node.wait_for_block_announcement(tip)
# Make sure we will receive a fast-announce compact block # Make sure we will receive a fast-announce compact block
self.request_cb_announcements(test_node, node, version) self.request_cb_announcements(test_node, node, version)
@ -270,8 +263,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block.rehash() block.rehash()
# Wait until the block was announced (via compact blocks) # Wait until the block was announced (via compact blocks)
wait_until(test_node.received_block_announcement, timeout=30) wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
assert(test_node.received_block_announcement())
# Now fetch and check the compact block # Now fetch and check the compact block
header_and_shortids = None header_and_shortids = None
@ -287,8 +279,7 @@ class CompactBlocksTest(BitcoinTestFramework):
inv = CInv(20, block_hash) # 20 == "CompactBlock" inv = CInv(20, block_hash) # 20 == "CompactBlock"
test_node.send_message(msg_getdata([inv])) test_node.send_message(msg_getdata([inv]))
wait_until(test_node.received_block_announcement, timeout=30) wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
assert(test_node.received_block_announcement())
# Now fetch and check the compact block # Now fetch and check the compact block
header_and_shortids = None header_and_shortids = None
@ -346,13 +337,11 @@ class CompactBlocksTest(BitcoinTestFramework):
if announce == "inv": if announce == "inv":
test_node.send_message(msg_inv([CInv(2, block.sha256)])) test_node.send_message(msg_inv([CInv(2, block.sha256)]))
success = wait_until(lambda: "getheaders" in test_node.last_message, timeout=30) wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock)
assert(success)
test_node.send_header_for_blocks([block]) test_node.send_header_for_blocks([block])
else: else:
test_node.send_header_for_blocks([block]) test_node.send_header_for_blocks([block])
success = wait_until(lambda: "getdata" in test_node.last_message, timeout=30) wait_until(lambda: "getdata" in test_node.last_message, timeout=30, lock=mininode_lock)
assert(success)
assert_equal(len(test_node.last_message["getdata"].inv), 1) assert_equal(len(test_node.last_message["getdata"].inv), 1)
assert_equal(test_node.last_message["getdata"].inv[0].type, 20) assert_equal(test_node.last_message["getdata"].inv[0].type, 20)
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
@ -520,8 +509,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
# We should receive a getdata request # We should receive a getdata request
success = wait_until(lambda: "getdata" in test_node.last_message, timeout=10) wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock)
assert(success)
assert_equal(len(test_node.last_message["getdata"].inv), 1) assert_equal(len(test_node.last_message["getdata"].inv), 1)
assert(test_node.last_message["getdata"].inv[0].type == 2) assert(test_node.last_message["getdata"].inv[0].type == 2)
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
@ -545,8 +533,7 @@ class CompactBlocksTest(BitcoinTestFramework):
num_to_request = random.randint(1, len(block.vtx)) num_to_request = random.randint(1, len(block.vtx))
msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request))) msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
test_node.send_message(msg) test_node.send_message(msg)
success = wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10, lock=mininode_lock)
assert(success)
[tx.calc_sha256() for tx in block.vtx] [tx.calc_sha256() for tx in block.vtx]
with mininode_lock: with mininode_lock:
@ -579,22 +566,20 @@ class CompactBlocksTest(BitcoinTestFramework):
for i in range(MAX_CMPCTBLOCK_DEPTH + 1): for i in range(MAX_CMPCTBLOCK_DEPTH + 1):
test_node.clear_block_announcement() test_node.clear_block_announcement()
new_blocks.append(node.generate(1)[0]) new_blocks.append(node.generate(1)[0])
wait_until(test_node.received_block_announcement, timeout=30) wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement() test_node.clear_block_announcement()
test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))])) test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))]))
success = wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock)
assert(success)
test_node.clear_block_announcement() test_node.clear_block_announcement()
node.generate(1) node.generate(1)
wait_until(test_node.received_block_announcement, timeout=30) wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement() test_node.clear_block_announcement()
with mininode_lock: with mininode_lock:
test_node.last_message.pop("block", None) test_node.last_message.pop("block", None)
test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))])) test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))]))
success = wait_until(lambda: "block" in test_node.last_message, timeout=30) wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock)
assert(success)
with mininode_lock: with mininode_lock:
test_node.last_message["block"].block.calc_sha256() test_node.last_message["block"].block.calc_sha256()
assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16)) assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16))
@ -639,7 +624,7 @@ class CompactBlocksTest(BitcoinTestFramework):
node.submitblock(ToHex(block)) node.submitblock(ToHex(block))
for l in listeners: for l in listeners:
wait_until(lambda: l.received_block_announcement(), timeout=30) wait_until(lambda: l.received_block_announcement(), timeout=30, lock=mininode_lock)
with mininode_lock: with mininode_lock:
for l in listeners: for l in listeners:
assert "cmpctblock" in l.last_message assert "cmpctblock" in l.last_message

View File

@ -108,9 +108,9 @@ class P2PLeakTest(BitcoinTestFramework):
NetworkThread().start() # Start up network handling in another thread NetworkThread().start() # Start up network handling in another thread
assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10) wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)
assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10) wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)
assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10) wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
# Mine a block and make sure that it's not sent to the connected nodes # Mine a block and make sure that it's not sent to the connected nodes
self.nodes[0].generate(1) self.nodes[0].generate(1)

View File

@ -139,7 +139,7 @@ class TestNode(NodeConnCB):
expect_headers = headers if headers != None else [] expect_headers = headers if headers != None else []
expect_inv = inv if inv != None else [] expect_inv = inv if inv != None else []
test_function = lambda: self.block_announced test_function = lambda: self.block_announced
assert(wait_until(test_function, timeout=60)) wait_until(test_function, timeout=60, lock=mininode_lock)
with mininode_lock: with mininode_lock:
self.block_announced = False self.block_announced = False
@ -166,12 +166,12 @@ class TestNode(NodeConnCB):
return return
test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list
assert(wait_until(test_function, timeout=timeout)) wait_until(test_function, timeout=timeout, lock=mininode_lock)
return return
def wait_for_block_announcement(self, block_hash, timeout=60): def wait_for_block_announcement(self, block_hash, timeout=60):
test_function = lambda: self.last_blockhash_announced == block_hash test_function = lambda: self.last_blockhash_announced == block_hash
assert(wait_until(test_function, timeout=timeout)) wait_until(test_function, timeout=timeout, lock=mininode_lock)
return return
def send_header_for_blocks(self, new_blocks): def send_header_for_blocks(self, new_blocks):

View File

@ -19,7 +19,7 @@ TestNode behaves as follows:
from .mininode import * from .mininode import *
from .blockstore import BlockStore, TxStore from .blockstore import BlockStore, TxStore
from .util import p2p_port from .util import p2p_port, wait_until
import logging import logging
@ -189,7 +189,7 @@ class TestManager(object):
def wait_for_disconnections(self): def wait_for_disconnections(self):
def disconnected(): def disconnected():
return all(node.closed for node in self.test_nodes) return all(node.closed for node in self.test_nodes)
return wait_until(disconnected, timeout=10) wait_until(disconnected, timeout=10, lock=mininode_lock)
def wait_for_verack(self): def wait_for_verack(self):
return all(node.wait_for_verack() for node in self.test_nodes) return all(node.wait_for_verack() for node in self.test_nodes)
@ -197,7 +197,7 @@ class TestManager(object):
def wait_for_pings(self, counter, timeout=float('inf')): def wait_for_pings(self, counter, timeout=float('inf')):
def received_pongs(): def received_pongs():
return all(node.received_ping_response(counter) for node in self.test_nodes) return all(node.received_ping_response(counter) for node in self.test_nodes)
return wait_until(received_pongs, timeout=timeout) wait_until(received_pongs, timeout=timeout, lock=mininode_lock)
# sync_blocks: Wait for all connections to request the blockhash given # sync_blocks: Wait for all connections to request the blockhash given
# then send get_headers to find out the tip of each node, and synchronize # then send get_headers to find out the tip of each node, and synchronize
@ -210,8 +210,7 @@ class TestManager(object):
) )
# --> error if not requested # --> error if not requested
if not wait_until(blocks_requested, attempts=20*num_blocks, sleep=0.1): wait_until(blocks_requested, attempts=20*num_blocks, sleep=0.1, lock=mininode_lock)
raise AssertionError("Not all nodes requested block")
# Send getheaders message # Send getheaders message
[ c.cb.send_getheaders() for c in self.connections ] [ c.cb.send_getheaders() for c in self.connections ]
@ -231,8 +230,7 @@ class TestManager(object):
) )
# --> error if not requested # --> error if not requested
if not wait_until(transaction_requested, attempts=20*num_events): wait_until(transaction_requested, attempts=20*num_events, lock=mininode_lock)
raise AssertionError("Not all nodes requested transaction")
# Get the mempool # Get the mempool
[ c.cb.send_mempool() for c in self.connections ] [ c.cb.send_mempool() for c in self.connections ]

View File

@ -37,7 +37,7 @@ import time
from threading import RLock, Thread from threading import RLock, Thread
from test_framework.siphash import siphash256 from test_framework.siphash import siphash256
from test_framework.util import hex_str_to_bytes, bytes_to_hex_str from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, wait_until
import dash_hash import dash_hash
@ -1299,22 +1299,6 @@ class msg_reject(object):
return "msg_reject: %s %d %s [%064x]" \ return "msg_reject: %s %d %s [%064x]" \
% (self.message, self.code, self.reason, self.data) % (self.message, self.code, self.reason, self.data)
# Helper function
def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), sleep=0.05):
if attempts == float('inf') and timeout == float('inf'):
timeout = 60
attempt = 0
elapsed = 0
while attempt < attempts and elapsed < timeout:
with mininode_lock:
if predicate():
return True
attempt += 1
elapsed += sleep
time.sleep(sleep)
return False
class msg_sendcmpct(object): class msg_sendcmpct(object):
command = b"sendcmpct" command = b"sendcmpct"
@ -1624,21 +1608,21 @@ class NodeConnCB(object):
def wait_for_disconnect(self, timeout=60): def wait_for_disconnect(self, timeout=60):
test_function = lambda: not self.connected test_function = lambda: not self.connected
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
# Message receiving helper methods # Message receiving helper methods
def wait_for_block(self, blockhash, timeout=60): def wait_for_block(self, blockhash, timeout=60):
test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_getdata(self, timeout=60): def wait_for_getdata(self, timeout=60):
test_function = lambda: self.last_message.get("getdata") test_function = lambda: self.last_message.get("getdata")
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_getheaders(self, timeout=60): def wait_for_getheaders(self, timeout=60):
test_function = lambda: self.last_message.get("getheaders") test_function = lambda: self.last_message.get("getheaders")
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_inv(self, expected_inv, timeout=60): def wait_for_inv(self, expected_inv, timeout=60):
"""Waits for an INV message and checks that the first inv object in the message was as expected.""" """Waits for an INV message and checks that the first inv object in the message was as expected."""
@ -1647,11 +1631,11 @@ class NodeConnCB(object):
test_function = lambda: self.last_message.get("inv") and \ test_function = lambda: self.last_message.get("inv") and \
self.last_message["inv"].inv[0].type == expected_inv[0].type and \ self.last_message["inv"].inv[0].type == expected_inv[0].type and \
self.last_message["inv"].inv[0].hash == expected_inv[0].hash self.last_message["inv"].inv[0].hash == expected_inv[0].hash
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_verack(self, timeout=60): def wait_for_verack(self, timeout=60):
test_function = lambda: self.message_count["verack"] test_function = lambda: self.message_count["verack"]
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
# Message sending helper functions # Message sending helper functions
@ -1669,7 +1653,7 @@ class NodeConnCB(object):
def sync_with_ping(self, timeout=60): def sync_with_ping(self, timeout=60):
self.send_message(msg_ping(nonce=self.ping_counter)) self.send_message(msg_ping(nonce=self.ping_counter))
test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
assert wait_until(test_function, timeout=timeout) wait_until(test_function, timeout=timeout, lock=mininode_lock)
self.ping_counter += 1 self.ping_counter += 1
return True return True

View File

@ -159,6 +159,28 @@ def str_to_b64str(string):
def satoshi_round(amount): def satoshi_round(amount):
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), sleep=0.05, lock=None):
if attempts == float('inf') and timeout == float('inf'):
timeout = 60
attempt = 0
timeout += time.time()
while attempt < attempts and time.time() < timeout:
if lock:
with lock:
if predicate():
return
else:
if predicate():
return
attempt += 1
time.sleep(sleep)
# Print the cause of the timeout
assert_greater_than(attempts, attempt)
assert_greater_than(timeout, time.time())
raise RuntimeError('Unreachable')
# RPC/P2P connection constants and functions # RPC/P2P connection constants and functions
############################################ ############################################