From fa3f9a05660687bf4146e089050e944a1d6cbe3c Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 4 May 2020 20:06:38 -0400 Subject: test: Fix intermittent sync_blocks failures --- test/functional/feature_loadblock.py | 8 +++----- test/functional/feature_reindex.py | 6 +++--- test/functional/mempool_persist.py | 10 +++++----- test/functional/test_framework/test_node.py | 28 ++++++++++++++++++++++++++-- test/functional/wallet_abandonconflict.py | 7 +++---- test/functional/wallet_basic.py | 9 ++------- 6 files changed, 42 insertions(+), 26 deletions(-) (limited to 'test/functional') diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py index 1138b0f0ea..82f1331685 100755 --- a/test/functional/feature_loadblock.py +++ b/test/functional/feature_loadblock.py @@ -16,10 +16,8 @@ import sys import tempfile import urllib -from test_framework.test_framework import ( - BitcoinTestFramework, -) -from test_framework.util import assert_equal, wait_until +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal class LoadblockTest(BitcoinTestFramework): @@ -75,7 +73,7 @@ class LoadblockTest(BitcoinTestFramework): self.log.info("Restart second, unsynced node with bootstrap file") self.stop_node(1) self.start_node(1, ["-loadblock=" + bootstrap_file]) - wait_until(lambda: self.nodes[1].getblockcount() == 100) + assert_equal(self.nodes[1].getblockcount(), 100) # start_node is blocking on all block files being imported assert_equal(self.nodes[1].getblockchaininfo()['blocks'], 100) assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py index 940b403f9c..31cea8d1b7 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -10,10 +10,10 @@ """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import wait_until +from test_framework.util import assert_equal -class ReindexTest(BitcoinTestFramework): +class ReindexTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -24,7 +24,7 @@ class ReindexTest(BitcoinTestFramework): self.stop_nodes() extra_args = [["-reindex-chainstate" if justchainstate else "-reindex"]] self.start_nodes(extra_args) - wait_until(lambda: self.nodes[0].getblockcount() == blockcount) + assert_equal(self.nodes[0].getblockcount(), blockcount) # start_node is blocking on reindex self.log.info("Success") def run_test(self): diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 99003d2d1f..3969da2eb0 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -95,8 +95,8 @@ class MempoolPersistTest(BitcoinTestFramework): self.start_node(1, extra_args=["-persistmempool=0"]) self.start_node(0) self.start_node(2) - wait_until(lambda: self.nodes[0].getmempoolinfo()["loaded"], timeout=1) - wait_until(lambda: self.nodes[2].getmempoolinfo()["loaded"], timeout=1) + assert self.nodes[0].getmempoolinfo()["loaded"] # start_node is blocking on the mempool being loaded + assert self.nodes[2].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[0].getrawmempool()), 6) assert_equal(len(self.nodes[2].getrawmempool()), 5) # The others have loaded their mempool. If node_1 loaded anything, we'd probably notice by now: @@ -117,13 +117,13 @@ class MempoolPersistTest(BitcoinTestFramework): self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") self.stop_nodes() self.start_node(0, extra_args=["-persistmempool=0", "-disablewallet"]) - wait_until(lambda: self.nodes[0].getmempoolinfo()["loaded"]) + assert self.nodes[0].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[0].getrawmempool()), 0) self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.") self.stop_nodes() self.start_node(0) - wait_until(lambda: self.nodes[0].getmempoolinfo()["loaded"]) + assert self.nodes[0].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[0].getrawmempool()), 6) mempooldat0 = os.path.join(self.nodes[0].datadir, self.chain, 'mempool.dat') @@ -137,7 +137,7 @@ class MempoolPersistTest(BitcoinTestFramework): os.rename(mempooldat0, mempooldat1) self.stop_nodes() self.start_node(1, extra_args=[]) - wait_until(lambda: self.nodes[1].getmempoolinfo()["loaded"]) + assert self.nodes[1].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[1].getrawmempool()), 6) self.log.debug("Prevent bitcoind from writing mempool.dat to disk. Verify that `savemempool` fails") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index e6ec3c1b2d..404c1b207b 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -110,7 +110,7 @@ class TestNode(): "--gen-suppressions=all", "--exit-on-first-error=yes", "--error-exitcode=1", "--quiet"] + self.args - if self.version is None or self.version >= 190000: + if self.version_is_at_least(190000): self.args.append("-logthreadnames") self.cli = TestNodeCLI(bitcoin_cli, self.datadir) @@ -222,6 +222,27 @@ class TestNode(): rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.chain, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir) rpc.getblockcount() # If the call to getblockcount() succeeds then the RPC connection is up + if self.version_is_at_least(190000): + # getmempoolinfo.loaded is available since commit + # bb8ae2c (version 0.19.0) + wait_until(lambda: rpc.getmempoolinfo()['loaded']) + # Wait for the node to finish reindex, block import, and + # loading the mempool. Usually importing happens fast or + # even "immediate" when the node is started. However, there + # is no guarantee and sometimes ThreadImport might finish + # later. This is going to cause intermittent test failures, + # because generally the tests assume the node is fully + # ready after being started. + # + # For example, the node will reject block messages from p2p + # when it is still importing with the error "Unexpected + # block message received" + # + # The wait is done here to make tests as robust as possible + # and prevent racy tests and intermittent failures as much + # as possible. Some tests might not need this, but the + # overhead is trivial, and the added gurantees are worth + # the minimal performance cost. self.log.debug("RPC successfully started") if self.use_cli: return @@ -274,6 +295,9 @@ class TestNode(): wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name)) return RPCOverloadWrapper(self.rpc / wallet_path, descriptors=self.descriptors) + def version_is_at_least(self, ver): + return self.version is None or self.version >= ver + def stop_node(self, expected_stderr='', wait=0): """Stop the node.""" if not self.running: @@ -281,7 +305,7 @@ class TestNode(): self.log.debug("Stopping node") try: # Do not use wait argument when testing older nodes, e.g. in feature_backwards_compatibility.py - if self.version is None or self.version >= 180000: + if self.version_is_at_least(180000): self.stop(wait=wait) else: self.stop() diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index c7b19081c8..90d17a806c 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -18,7 +18,6 @@ from test_framework.util import ( assert_raises_rpc_error, connect_nodes, disconnect_nodes, - wait_until, ) @@ -98,7 +97,7 @@ class AbandonConflictTest(BitcoinTestFramework): # TODO: redo with eviction self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=0.0001"]) - wait_until(lambda: self.nodes[0].getmempoolinfo()['loaded']) + assert self.nodes[0].getmempoolinfo()['loaded'] # Verify txs no longer in either node's mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) @@ -126,7 +125,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=0.00001"]) - wait_until(lambda: self.nodes[0].getmempoolinfo()['loaded']) + assert self.nodes[0].getmempoolinfo()['loaded'] assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) @@ -148,7 +147,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Remove using high relay fee again self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=0.0001"]) - wait_until(lambda: self.nodes[0].getmempoolinfo()['loaded']) + assert self.nodes[0].getmempoolinfo()['loaded'] assert_equal(len(self.nodes[0].getrawmempool()), 0) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("24.9996")) diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 2dddbf2cf3..9e295af330 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the wallet.""" from decimal import Decimal -import time from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -466,12 +465,8 @@ class WalletTest(BitcoinTestFramework): extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)] self.start_node(0, extra_args=extra_args) - # wait for loadmempool - timeout = 10 - while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit * 2): - time.sleep(0.5) - timeout -= 0.5 - assert_equal(len(self.nodes[0].getrawmempool()), chainlimit * 2) + # wait until the wallet has submitted all transactions to the mempool + wait_until(lambda: len(self.nodes[0].getrawmempool()) == chainlimit * 2) node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. -- cgit v1.2.3