Skip to content

Commit

Permalink
Merge #13517: qa: Remove need to handle the network thread in tests
Browse files Browse the repository at this point in the history
fa87da2 qa: Avoid start/stop of the network thread mid-test (MarcoFalke)

Pull request description:

  This simplifies test writing by removing the need to handle the network thread in tests. E.g. start thread, join thread, restart thread mid-test, adding p2p connections at the "right" time, ...

Tree-SHA512: 533642f12fef5496f1933855edcdab1a7ed901d088d34911749cd0f9e044c8a6cb1f89985ac3a7f41a512943663e4e270a61978f6f072143ae050cd102d4eab8
  • Loading branch information
laanwj committed Jun 29, 2018
2 parents f3c9c40 + fa87da2 commit a6ed99a
Show file tree
Hide file tree
Showing 26 changed files with 98 additions and 223 deletions.
6 changes: 1 addition & 5 deletions test/functional/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,14 @@ over the network (`CBlock`, `CTransaction`, etc, along with the network-level
wrappers for them, `msg_block`, `msg_tx`, etc).

- P2P tests have two threads. One thread handles all network communication
with the bitcoind(s) being tested (using python's asyncore package); the other
with the bitcoind(s) being tested in a callback-based event loop; the other
implements the test logic.

- `P2PConnection` is the class used to connect to a bitcoind. `P2PInterface`
contains the higher level logic for processing P2P payloads and connecting to
the Bitcoin Core node application logic. For custom behaviour, subclass the
P2PInterface object and override the callback methods.

- Call `network_thread_start()` after all `P2PInterface` objects are created to
start the networking thread. (Continue with the test logic in your existing
thread.)

- Can be used to write tests where specific P2P protocol behavior is tested.
Examples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`.

Expand Down
10 changes: 0 additions & 10 deletions test/functional/example_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
mininode_lock,
msg_block,
msg_getdata,
network_thread_join,
network_thread_start,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
Expand Down Expand Up @@ -135,9 +133,6 @@ def run_test(self):
# Create P2P connections to two of the nodes
self.nodes[0].add_p2p_connection(BaseNode())

# Start up network handling in another thread. This needs to be called
# after the P2P connections have been created.
network_thread_start()
# wait_for_verack ensures that the P2P connection is fully up.
self.nodes[0].p2p.wait_for_verack()

Expand Down Expand Up @@ -189,14 +184,9 @@ def run_test(self):
connect_nodes(self.nodes[1], 2)

self.log.info("Add P2P connection to node2")
# We can't add additional P2P connections once the network thread has started. Disconnect the connection
# to node0, wait for the network thread to terminate, then connect to node2. This is specific to
# the current implementation of the network thread and may be improved in future.
self.nodes[0].disconnect_p2ps()
network_thread_join()

self.nodes[2].add_p2p_connection(BaseNode())
network_thread_start()
self.nodes[2].p2p.wait_for_verack()

self.log.info("Wait for node2 reach current tip. Test that it has propagated all the blocks to us")
Expand Down
26 changes: 10 additions & 16 deletions test/functional/feature_assumevalid.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@

from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.key import CECKey
from test_framework.mininode import (CBlockHeader,
COutPoint,
CTransaction,
CTxIn,
CTxOut,
network_thread_join,
network_thread_start,
P2PInterface,
msg_block,
msg_headers)
from test_framework.messages import (
CBlockHeader,
COutPoint,
CTransaction,
CTxIn,
CTxOut,
msg_block,
msg_headers
)
from test_framework.mininode import P2PInterface
from test_framework.script import (CScript, OP_TRUE)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
Expand Down Expand Up @@ -98,8 +98,6 @@ def run_test(self):

# Connect to node0
p2p0 = self.nodes[0].add_p2p_connection(BaseNode())

network_thread_start()
self.nodes[0].p2p.wait_for_verack()

# Build the blockchain
Expand Down Expand Up @@ -160,9 +158,7 @@ def run_test(self):
self.block_time += 1
height += 1

# We're adding new connections so terminate the network thread
self.nodes[0].disconnect_p2ps()
network_thread_join()

# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
Expand All @@ -172,8 +168,6 @@ def run_test(self):
p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
p2p2 = self.nodes[2].add_p2p_connection(BaseNode())

network_thread_start()

p2p0.wait_for_verack()
p2p1.wait_for_verack()
p2p2.wait_for_verack()
Expand Down
4 changes: 1 addition & 3 deletions test/functional/feature_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
uint256_from_compact,
uint256_from_str,
)
from test_framework.mininode import P2PDataStore, network_thread_start, network_thread_join
from test_framework.mininode import P2PDataStore
from test_framework.script import (
CScript,
MAX_SCRIPT_ELEMENT_SIZE,
Expand Down Expand Up @@ -1299,7 +1299,6 @@ def bootstrap_p2p(self):
Helper to connect and wait for version handshake."""
self.nodes[0].add_p2p_connection(P2PDataStore())
network_thread_start()
# We need to wait for the initial getheaders from the peer before we
# start populating our blockstore. If we don't, then we may run ahead
# to the next subtest before we receive the getheaders. We'd then send
Expand All @@ -1314,7 +1313,6 @@ def reconnect_p2p(self):
The node gets disconnected several times in this test. This helper
method reconnects the p2p and restarts the network thread."""
self.nodes[0].disconnect_p2ps()
network_thread_join()
self.bootstrap_p2p()

def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True, reconnect=False, timeout=60):
Expand Down
4 changes: 0 additions & 4 deletions test/functional/feature_cltv.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ def set_test_params(self):

def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())

network_thread_start()

# wait_for_verack ensures that the P2P connection is fully up.
self.nodes[0].p2p.wait_for_verack()

self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
Expand Down
3 changes: 1 addition & 2 deletions test/functional/feature_csv_activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

from test_framework.blocktools import create_coinbase, create_block
from test_framework.messages import ToHex, CTransaction
from test_framework.mininode import network_thread_start, P2PDataStore
from test_framework.mininode import P2PDataStore
from test_framework.script import (
CScript,
OP_CHECKSEQUENCEVERIFY,
Expand Down Expand Up @@ -183,7 +183,6 @@ def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None

def run_test(self):
self.nodes[0].add_p2p_connection(P2PDataStore())
network_thread_start()
self.nodes[0].p2p.wait_for_verack()

self.log.info("Generate blocks in the past for coinbase outputs.")
Expand Down
2 changes: 0 additions & 2 deletions test/functional/feature_dersig.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ def set_test_params(self):
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())

network_thread_start()

# wait_for_verack ensures that the P2P connection is fully up.
self.nodes[0].p2p.wait_for_verack()

Expand Down
3 changes: 0 additions & 3 deletions test/functional/feature_maxuploadtarget.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def run_test(self):
for _ in range(3):
p2p_conns.append(self.nodes[0].add_p2p_connection(TestP2PConn()))

network_thread_start()
for p2pc in p2p_conns:
p2pc.wait_for_verack()

Expand Down Expand Up @@ -148,8 +147,6 @@ def run_test(self):

# Reconnect to self.nodes[0]
self.nodes[0].add_p2p_connection(TestP2PConn())

network_thread_start()
self.nodes[0].p2p.wait_for_verack()

#retrieve 20 blocks which should be enough to break the 1MB limit
Expand Down
3 changes: 1 addition & 2 deletions test/functional/feature_nulldummy.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.mininode import CTransaction, network_thread_start
from test_framework.messages import CTransaction
from test_framework.blocktools import create_coinbase, create_block, add_witness_commitment
from test_framework.script import CScript
from io import BytesIO
Expand Down Expand Up @@ -50,7 +50,6 @@ def run_test(self):
self.wit_address = self.nodes[0].addwitnessaddress(self.address)
self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address']

network_thread_start()
self.coinbase_blocks = self.nodes[0].generate(2) # Block 2
coinbase_txid = []
for i in self.coinbase_blocks:
Expand Down
3 changes: 1 addition & 2 deletions test/functional/feature_versionbits_warning.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from test_framework.blocktools import create_block, create_coinbase
from test_framework.messages import msg_block
from test_framework.mininode import P2PInterface, network_thread_start, mininode_lock
from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import wait_until

Expand Down Expand Up @@ -65,7 +65,6 @@ def run_test(self):
# Handy alias
node = self.nodes[0]
node.add_p2p_connection(P2PInterface())
network_thread_start()
node.p2p.wait_for_verack()

# Mine one period worth of blocks
Expand Down
4 changes: 1 addition & 3 deletions test/functional/p2p_compactblocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,13 +788,11 @@ def announce_cmpct_block(node, peer):
assert_equal(int(node.getbestblockhash(), 16), block.sha256)

def run_test(self):
# Setup the p2p connections and start up the network thread.
# Setup the p2p connections
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
self.segwit_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
self.old_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)

network_thread_start()

self.test_node.wait_for_verack()

# We will need UTXOs to construct transactions in later tests.
Expand Down
3 changes: 1 addition & 2 deletions test/functional/p2p_feefilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ def run_test(self):
node1.generate(1)
sync_blocks(self.nodes)

# Setup the p2p connections and start up the network thread.
# Setup the p2p connections
self.nodes[0].add_p2p_connection(TestP2PConn())
network_thread_start()
self.nodes[0].p2p.wait_for_verack()

# Test that invs are received for all txs at feerate of 20 sat/byte
Expand Down
3 changes: 0 additions & 3 deletions test/functional/p2p_fingerprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
msg_block,
msg_getdata,
msg_getheaders,
network_thread_start,
wait_until,
)
from test_framework.test_framework import BitcoinTestFramework
Expand Down Expand Up @@ -76,8 +75,6 @@ def last_header_equals(self, expected_hash, node):
# last month but that have over a month's worth of work are also withheld.
def run_test(self):
node0 = self.nodes[0].add_p2p_connection(P2PInterface())

network_thread_start()
node0.wait_for_verack()

# Set node time to 60 days ago
Expand Down
4 changes: 1 addition & 3 deletions test/functional/p2p_invalid_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from test_framework.blocktools import create_block, create_coinbase, create_transaction
from test_framework.messages import COIN
from test_framework.mininode import network_thread_start, P2PDataStore
from test_framework.mininode import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal

Expand All @@ -28,8 +28,6 @@ def run_test(self):
# Add p2p connection to node0
node = self.nodes[0] # convenience reference to the node
node.add_p2p_connection(P2PDataStore())

network_thread_start()
node.p2p.wait_for_verack()

best_block = node.getblock(node.getbestblockhash())
Expand Down
4 changes: 1 addition & 3 deletions test/functional/p2p_invalid_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
CTxIn,
CTxOut,
)
from test_framework.mininode import network_thread_start, P2PDataStore, network_thread_join
from test_framework.mininode import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
Expand All @@ -32,7 +32,6 @@ def bootstrap_p2p(self, *, num_connections=1):
Helper to connect and wait for version handshake."""
for _ in range(num_connections):
self.nodes[0].add_p2p_connection(P2PDataStore())
network_thread_start()
self.nodes[0].p2p.wait_for_verack()

def reconnect_p2p(self, **kwargs):
Expand All @@ -41,7 +40,6 @@ def reconnect_p2p(self, **kwargs):
The node gets disconnected several times in this test. This helper
method reconnects the p2p and restarts the network thread."""
self.nodes[0].disconnect_p2ps()
network_thread_join()
self.bootstrap_p2p(**kwargs)

def run_test(self):
Expand Down
9 changes: 2 additions & 7 deletions test/functional/p2p_leak.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ def run_test(self):
unsupported_service_bit5_node = self.nodes[0].add_p2p_connection(CLazyNode(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)
unsupported_service_bit7_node = self.nodes[0].add_p2p_connection(CLazyNode(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)

network_thread_start()

wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)
wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)
wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
Expand All @@ -126,9 +124,8 @@ def run_test(self):

self.nodes[0].disconnect_p2ps()

# Wait until all connections are closed and the network thread has terminated
# Wait until all connections are closed
wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0)
network_thread_join()

# Make sure no unexpected messages came in
assert(no_version_bannode.unexpected_msg == False)
Expand All @@ -143,11 +140,9 @@ def run_test(self):
allowed_service_bit5_node = self.nodes[0].add_p2p_connection(P2PInterface(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)
allowed_service_bit7_node = self.nodes[0].add_p2p_connection(P2PInterface(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)

# Network thread stopped when all previous P2PInterfaces disconnected. Restart it
network_thread_start()

wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock)
wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock)


if __name__ == '__main__':
P2PLeakTest().main()
1 change: 0 additions & 1 deletion test/functional/p2p_mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ def set_test_params(self):
def run_test(self):
# Add a p2p connection
self.nodes[0].add_p2p_connection(P2PInterface())
network_thread_start()
self.nodes[0].p2p.wait_for_verack()

#request mempool
Expand Down
5 changes: 1 addition & 4 deletions test/functional/p2p_node_network_limited.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- send a block within 288 + 2 of the tip
- disconnect peers who request blocks older than that."""
from test_framework.messages import CInv, msg_getdata, msg_verack
from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS, P2PInterface, wait_until, mininode_lock, network_thread_start, network_thread_join
from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS, P2PInterface, wait_until, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks

Expand Down Expand Up @@ -48,7 +48,6 @@ def setup_network(self):

def run_test(self):
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
network_thread_start()
node.wait_for_verack()

expected_services = NODE_BLOOM | NODE_WITNESS | NODE_NETWORK_LIMITED
Expand All @@ -74,9 +73,7 @@ def run_test(self):

self.log.info("Check local address relay, do a fresh connection.")
self.nodes[0].disconnect_p2ps()
network_thread_join()
node1 = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
network_thread_start()
node1.wait_for_verack()
node1.send_message(msg_verack())

Expand Down
5 changes: 1 addition & 4 deletions test/functional/p2p_segwit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1964,18 +1964,15 @@ def test_non_standard_witness(self):

self.utxo.pop(0)


def run_test(self):
# Setup the p2p connections and start up the network thread.
# Setup the p2p connections
# self.test_node sets NODE_WITNESS|NODE_NETWORK
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
# self.old_node sets only NODE_NETWORK
self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
# self.std_node is for testing node1 (fRequireStandard=true)
self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)

network_thread_start()

# Keep a place to store utxo's that can be used in later tests
self.utxo = []

Expand Down
Loading

0 comments on commit a6ed99a

Please sign in to comment.