diff options
Diffstat (limited to 'test')
23 files changed, 401 insertions, 217 deletions
diff --git a/test/README.md b/test/README.md index b40052b898..4dd512638d 100644 --- a/test/README.md +++ b/test/README.md @@ -34,7 +34,7 @@ You can run any single test by calling test/functional/test_runner.py <testname> -Or you can run any combination of tests by calling +Or you can run any combination (incl. duplicates) of tests by calling test/functional/test_runner.py <testname1> <testname2> <testname3> ... diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py index 0439d168de..9748757641 100755 --- a/test/functional/abandonconflict.py +++ b/test/functional/abandonconflict.py @@ -10,10 +10,8 @@ which are not included in a block and are not currently in the mempool. It has no effect on transactions which are already conflicted or abandoned. """ - from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import urllib.parse class AbandonConflictTest(BitcoinTestFramework): def __init__(self): @@ -37,8 +35,8 @@ class AbandonConflictTest(BitcoinTestFramework): assert(balance - newbalance < Decimal("0.001")) #no more than fees lost balance = newbalance - url = urllib.parse.urlparse(self.nodes[1].url) - self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) + # Disconnect nodes so node0's transactions don't get into node1's mempool + disconnect_nodes(self.nodes[0], 1) # Identify the 10btc outputs nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10")) @@ -78,8 +76,9 @@ class AbandonConflictTest(BitcoinTestFramework): stop_node(self.nodes[0],0) self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) - # Verify txs no longer in mempool + # Verify txs no longer in either node's mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) + assert_equal(len(self.nodes[1].getrawmempool()), 0) # Not in mempool txs from self should only reduce balance # inputs are still spent, but change not received diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py index 1b2dff63d2..fff47fcca9 100755 --- a/test/functional/bip9-softforks.py +++ b/test/functional/bip9-softforks.py @@ -99,12 +99,43 @@ class BIP9SoftForksTest(ComparisonTestFramework): assert_equal(self.get_bip9_status(bipName)['status'], 'started') assert_equal(self.get_bip9_status(bipName)['since'], 144) + assert_equal(self.get_bip9_status(bipName)['statistics']['elapsed'], 0) + assert_equal(self.get_bip9_status(bipName)['statistics']['count'], 0) tmpl = self.nodes[0].getblocktemplate({}) assert(bipName not in tmpl['rules']) assert_equal(tmpl['vbavailable'][bipName], bitno) assert_equal(tmpl['vbrequired'], 0) assert(tmpl['version'] & activated_version) + # Test 1-A + # check stats after max number of "signalling not" blocks such that LOCKED_IN still possible this period + test_blocks = self.generate_blocks(36, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(10, activated_version) # 0x20000001 (signalling ready) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['statistics']['elapsed'], 46) + assert_equal(self.get_bip9_status(bipName)['statistics']['count'], 10) + assert_equal(self.get_bip9_status(bipName)['statistics']['possible'], True) + + # Test 1-B + # check stats after one additional "signalling not" block -- LOCKED_IN no longer possible this period + test_blocks = self.generate_blocks(1, 4, test_blocks) # 0x00000004 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['statistics']['elapsed'], 47) + assert_equal(self.get_bip9_status(bipName)['statistics']['count'], 10) + assert_equal(self.get_bip9_status(bipName)['statistics']['possible'], False) + + # Test 1-C + # finish period with "ready" blocks, but soft fork will still fail to advance to LOCKED_IN + test_blocks = self.generate_blocks(97, activated_version) # 0x20000001 (signalling ready) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['statistics']['elapsed'], 0) + assert_equal(self.get_bip9_status(bipName)['statistics']['count'], 0) + assert_equal(self.get_bip9_status(bipName)['statistics']['possible'], True) + assert_equal(self.get_bip9_status(bipName)['status'], 'started') + # Test 2 # Fail to achieve LOCKED_IN 100 out of 144 signal bit 1 # using a variety of bits to simulate multiple parallel softforks @@ -116,6 +147,8 @@ class BIP9SoftForksTest(ComparisonTestFramework): assert_equal(self.get_bip9_status(bipName)['status'], 'started') assert_equal(self.get_bip9_status(bipName)['since'], 144) + assert_equal(self.get_bip9_status(bipName)['statistics']['elapsed'], 0) + assert_equal(self.get_bip9_status(bipName)['statistics']['count'], 0) tmpl = self.nodes[0].getblocktemplate({}) assert(bipName not in tmpl['rules']) assert_equal(tmpl['vbavailable'][bipName], bitno) @@ -125,14 +158,24 @@ class BIP9SoftForksTest(ComparisonTestFramework): # Test 3 # 108 out of 144 signal bit 1 to achieve LOCKED_IN # using a variety of bits to simulate multiple parallel softforks - test_blocks = self.generate_blocks(58, activated_version) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(57, activated_version) # 0x20000001 (signalling ready) test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) test_blocks = self.generate_blocks(50, activated_version, test_blocks) # 0x20000101 (signalling ready) test_blocks = self.generate_blocks(10, 4, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) + # check counting stats and "possible" flag before last block of this period achieves LOCKED_IN... + assert_equal(self.get_bip9_status(bipName)['statistics']['elapsed'], 143) + assert_equal(self.get_bip9_status(bipName)['statistics']['count'], 107) + assert_equal(self.get_bip9_status(bipName)['statistics']['possible'], True) + assert_equal(self.get_bip9_status(bipName)['status'], 'started') + + # ...continue with Test 3 + test_blocks = self.generate_blocks(1, activated_version) # 0x20000001 (signalling ready) + yield TestInstance(test_blocks, sync_every_block=False) + assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') - assert_equal(self.get_bip9_status(bipName)['since'], 432) + assert_equal(self.get_bip9_status(bipName)['since'], 576) tmpl = self.nodes[0].getblocktemplate({}) assert(bipName not in tmpl['rules']) @@ -142,7 +185,7 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance(test_blocks, sync_every_block=False) assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') - assert_equal(self.get_bip9_status(bipName)['since'], 432) + assert_equal(self.get_bip9_status(bipName)['since'], 576) tmpl = self.nodes[0].getblocktemplate({}) assert(bipName not in tmpl['rules']) @@ -168,7 +211,7 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance([[block, True]]) assert_equal(self.get_bip9_status(bipName)['status'], 'active') - assert_equal(self.get_bip9_status(bipName)['since'], 576) + assert_equal(self.get_bip9_status(bipName)['since'], 720) tmpl = self.nodes[0].getblocktemplate({}) assert(bipName in tmpl['rules']) assert(bipName not in tmpl['vbavailable']) diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 00ae3d7572..b6112c7280 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -10,6 +10,7 @@ Test the following RPCs: - getbestblockhash - getblockhash - getblockheader + - getnetworkhashps - verifychain Tests correspond to code in rpc/blockchain.cpp. @@ -23,8 +24,6 @@ from test_framework.util import ( assert_raises_jsonrpc, assert_is_hex_string, assert_is_hash_string, - start_nodes, - connect_nodes_bi, ) @@ -33,12 +32,13 @@ class BlockchainTest(BitcoinTestFramework): def __init__(self): super().__init__() self.setup_clean_chain = False - self.num_nodes = 2 + self.num_nodes = 1 def run_test(self): self._test_gettxoutsetinfo() self._test_getblockheader() self._test_getdifficulty() + self._test_getnetworkhashps() self.nodes[0].verifychain(4, 0) def _test_gettxoutsetinfo(self): @@ -50,9 +50,33 @@ class BlockchainTest(BitcoinTestFramework): assert_equal(res['height'], 200) assert_equal(res['txouts'], 200) assert_equal(res['bytes_serialized'], 13924), + assert_equal(res['bestblock'], node.getblockhash(200)) assert_equal(len(res['bestblock']), 64) assert_equal(len(res['hash_serialized']), 64) + self.log.info("Test that gettxoutsetinfo() works for blockchain with just the genesis block") + b1hash = node.getblockhash(1) + node.invalidateblock(b1hash) + + res2 = node.gettxoutsetinfo() + assert_equal(res2['transactions'], 0) + assert_equal(res2['total_amount'], Decimal('0')) + assert_equal(res2['height'], 0) + assert_equal(res2['txouts'], 0) + assert_equal(res2['bestblock'], node.getblockhash(0)) + assert_equal(len(res2['hash_serialized']), 64) + + self.log.info("Test that gettxoutsetinfo() returns the same result after invalidate/reconsider block") + node.reconsiderblock(b1hash) + + res3 = node.gettxoutsetinfo() + assert_equal(res['total_amount'], res3['total_amount']) + assert_equal(res['transactions'], res3['transactions']) + assert_equal(res['height'], res3['height']) + assert_equal(res['txouts'], res3['txouts']) + assert_equal(res['bestblock'], res3['bestblock']) + assert_equal(res['hash_serialized'], res3['hash_serialized']) + def _test_getblockheader(self): node = self.nodes[0] @@ -85,5 +109,10 @@ class BlockchainTest(BitcoinTestFramework): # binary => decimal => binary math is why we do this check assert abs(difficulty * 2**31 - 1) < 0.0001 + def _test_getnetworkhashps(self): + hashes_per_second = self.nodes[0].getnetworkhashps() + # This should be 2 hashes every 10 minutes or 1/300 + assert abs(hashes_per_second * 300 - 1) < 0.0001 + if __name__ == '__main__': BlockchainTest().main() diff --git a/test/functional/disablewallet.py b/test/functional/disablewallet.py index 3f77a1828d..d344513414 100755 --- a/test/functional/disablewallet.py +++ b/test/functional/disablewallet.py @@ -21,6 +21,8 @@ class DisableWalletTest (BitcoinTestFramework): self.extra_args = [["-disablewallet"]] def run_test (self): + # Make sure wallet is really disabled + assert_raises_jsonrpc(-32601, 'Method not found', self.nodes[0].getwalletinfo) x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') assert(x['isvalid'] == False) x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index 50d79db903..f453fc0261 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test node disconnect and ban behavior""" +import time from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework @@ -56,11 +57,16 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("setban: test persistence across node restart") self.nodes[1].setban("127.0.0.0/32", "add") self.nodes[1].setban("127.0.0.0/24", "add") + # Set the mocktime so we can control when bans expire + old_time = int(time.time()) + self.nodes[1].setmocktime(old_time) self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[1].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) - assert wait_until(lambda: len(self.nodes[1].listbanned()) == 3, timeout=10) + # Move time forward by 3 seconds so the third ban has expired + self.nodes[1].setmocktime(old_time + 3) + assert_equal(len(self.nodes[1].listbanned()), 3) stop_node(self.nodes[1], 1) diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index c22b7ff020..7b15476ea2 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -6,11 +6,11 @@ By default, bitcoind will dump mempool on shutdown and then reload it on startup. This can be overridden with -the -persistmempool=false command line option. +the -persistmempool=0 command line option. Test is as follows: - - start node0, node1 and node2. node1 has -persistmempool=false + - start node0, node1 and node2. node1 has -persistmempool=0 - create 5 transactions on node2 to its own address. Note that these are not sent to node0 or node1 addresses because we don't want them to be saved in the wallet. @@ -20,17 +20,19 @@ Test is as follows: in its mempool. Shutdown node0. This tests that by default the mempool is persistent. - startup node1. Verify that its mempool is empty. Shutdown node1. - This tests that with -persistmempool=false, the mempool is not + This tests that with -persistmempool=0, the mempool is not dumped to disk when the node is shut down. - - Restart node0 with -persistmempool=false. Verify that its mempool is - empty. Shutdown node0. This tests that with -persistmempool=false, + - Restart node0 with -persistmempool=0. Verify that its mempool is + empty. Shutdown node0. This tests that with -persistmempool=0, the mempool is not loaded from disk on start up. - - Restart node0 with -persistmempool=true. Verify that it has 5 - transactions in its mempool. This tests that -persistmempool=false + - Restart node0 with -persistmempool. Verify that it has 5 + transactions in its mempool. This tests that -persistmempool=0 does not overwrite a previously valid mempool stored on disk. """ +import time +from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -38,18 +40,10 @@ class MempoolPersistTest(BitcoinTestFramework): def __init__(self): super().__init__() + # We need 3 nodes for this test. Node1 does not have a persistent mempool. self.num_nodes = 3 self.setup_clean_chain = False - - def setup_network(self): - # We need 3 nodes for this test. Node1 does not have a persistent mempool. - self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir)) - self.nodes.append(start_node(1, self.options.tmpdir, ["-persistmempool=false"])) - self.nodes.append(start_node(2, self.options.tmpdir)) - connect_nodes_bi(self.nodes, 0, 2) - connect_nodes_bi(self.nodes, 1, 2) - self.is_network_split = False + self.extra_args = [[], ["-persistmempool=0"], []] def run_test(self): chain_height = self.nodes[0].getblockcount() @@ -57,6 +51,7 @@ class MempoolPersistTest(BitcoinTestFramework): self.log.debug("Mine a single block to get out of IBD") self.nodes[0].generate(1) + self.sync_all() self.log.debug("Send 5 transactions from node2 (to its own address)") for i in range(5): @@ -72,20 +67,24 @@ class MempoolPersistTest(BitcoinTestFramework): self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir)) self.nodes.append(start_node(1, self.options.tmpdir)) - assert_equal(len(self.nodes[0].getrawmempool()), 5) + # Give bitcoind a second to reload the mempool + time.sleep(1) + assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) assert_equal(len(self.nodes[1].getrawmempool()), 0) - self.log.debug("Stop-start node0 with -persistmempool=false. 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.") stop_nodes(self.nodes) self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-persistmempool=false"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-persistmempool=0"])) + # Give bitcoind a second to reload the mempool + time.sleep(1) assert_equal(len(self.nodes[0].getrawmempool()), 0) self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.") stop_nodes(self.nodes) self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir)) - assert_equal(len(self.nodes[0].getrawmempool()), 5) + assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) if __name__ == '__main__': MempoolPersistTest().main() diff --git a/test/functional/net.py b/test/functional/net.py index 16476f7d34..fb46064441 100755 --- a/test/functional/net.py +++ b/test/functional/net.py @@ -15,7 +15,6 @@ from test_framework.util import ( assert_raises_jsonrpc, connect_nodes_bi, p2p_port, - start_nodes, ) diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 335777b2ab..24d4d37c42 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -61,16 +61,6 @@ class TestNode(NodeConnCB): self.send_message(msg) self.wait_for_getdata() - def announce_block(self, block, use_header): - with mininode_lock: - self.last_message.pop("getdata", None) - if use_header: - msg = msg_headers() - msg.headers = [ CBlockHeader(block) ] - self.send_message(msg) - else: - self.send_message(msg_inv(inv=[CInv(2, block.sha256)])) - def request_block(self, blockhash, inv_type, timeout=60): with mininode_lock: self.last_message.pop("block", None) @@ -926,9 +916,9 @@ class SegWitTest(BitcoinTestFramework): tx3.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ] # Also check that old_node gets a tx announcement, even though this is # a witness transaction. - self.old_node.wait_for_inv(CInv(1, tx2.sha256)) # wait until tx2 was inv'ed + self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=True) - self.old_node.wait_for_inv(CInv(1, tx3.sha256)) + self.old_node.wait_for_inv([CInv(1, tx3.sha256)]) # Test that getrawtransaction returns correct witness information # hash, size, vsize @@ -1029,13 +1019,18 @@ class SegWitTest(BitcoinTestFramework): block4 = self.build_next_block(nVersion=4) block4.solve() self.old_node.getdataset = set() + # Blocks can be requested via direct-fetch (immediately upon processing the announcement) # or via parallel download (with an indeterminate delay from processing the announcement) # so to test that a block is NOT requested, we could guess a time period to sleep for, # and then check. We can avoid the sleep() by taking advantage of transaction getdata's # being processed after block getdata's, and announce a transaction as well, # and then check to see if that particular getdata has been received. - self.old_node.announce_block(block4, use_header=False) + # Since 0.14, inv's will only be responded to with a getheaders, so send a header + # to announce this block. + msg = msg_headers() + msg.headers = [ CBlockHeader(block4) ] + self.old_node.send_message(msg) self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0]) assert(block4.sha256 not in self.old_node.getdataset) diff --git a/test/functional/prioritise_transaction.py b/test/functional/prioritise_transaction.py index a07923edba..9c3b3fd5d9 100755 --- a/test/functional/prioritise_transaction.py +++ b/test/functional/prioritise_transaction.py @@ -13,8 +13,8 @@ class PrioritiseTransactionTest(BitcoinTestFramework): def __init__(self): super().__init__() self.setup_clean_chain = True - self.num_nodes = 1 - self.extra_args = [["-printpriority=1"]] + self.num_nodes = 2 + self.extra_args = [["-printpriority=1"], ["-printpriority=1"]] def run_test(self): self.txouts = gen_return_txouts() @@ -115,5 +115,16 @@ class PrioritiseTransactionTest(BitcoinTestFramework): assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id) assert(tx_id in self.nodes[0].getrawmempool()) + # Test that calling prioritisetransaction is sufficient to trigger + # getblocktemplate to (eventually) return a new block. + mock_time = int(time.time()) + self.nodes[0].setmocktime(mock_time) + template = self.nodes[0].getblocktemplate() + self.nodes[0].prioritisetransaction(tx_id, -int(self.relayfee*COIN)) + self.nodes[0].setmocktime(mock_time+10) + new_template = self.nodes[0].getblocktemplate() + + assert(template != new_template) + if __name__ == '__main__': PrioritiseTransactionTest().main() diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py index fd81b02ead..3b286000a1 100755 --- a/test/functional/rpcnamedargs.py +++ b/test/functional/rpcnamedargs.py @@ -8,7 +8,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_jsonrpc, - start_nodes, ) diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index 97d64c0d98..44c357c6db 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -243,7 +243,7 @@ class SendHeadersTest(BitcoinTestFramework): if i == 0: # first request the block test_node.get_data([tip]) - test_node.wait_for_block(tip, timeout=5) + test_node.wait_for_block(tip) elif i == 1: # next try requesting header and block test_node.get_headers(locator=[old_tip], hashstop=tip) @@ -258,7 +258,7 @@ class SendHeadersTest(BitcoinTestFramework): new_block = create_block(tip, create_coinbase(height+1), block_time) new_block.solve() test_node.send_header_for_blocks([new_block]) - test_node.wait_for_getdata([new_block.sha256], timeout=5) + test_node.wait_for_getdata([new_block.sha256]) test_node.send_message(msg_block(new_block)) test_node.sync_with_ping() # make sure this block is processed inv_node.clear_last_announcement() @@ -297,18 +297,18 @@ class SendHeadersTest(BitcoinTestFramework): if j == 0: # Announce via inv test_node.send_block_inv(tip) - test_node.wait_for_getheaders(timeout=5) + test_node.wait_for_getheaders() # Should have received a getheaders now test_node.send_header_for_blocks(blocks) # Test that duplicate inv's won't result in duplicate # getdata requests, or duplicate headers announcements [ inv_node.send_block_inv(x.sha256) for x in blocks ] - test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + test_node.wait_for_getdata([x.sha256 for x in blocks]) inv_node.sync_with_ping() else: # Announce via headers test_node.send_header_for_blocks(blocks) - test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + test_node.wait_for_getdata([x.sha256 for x in blocks]) # Test that duplicate headers won't result in duplicate # getdata requests (the check is further down) inv_node.send_header_for_blocks(blocks) @@ -495,7 +495,7 @@ class SendHeadersTest(BitcoinTestFramework): with mininode_lock: test_node.last_message.pop("getheaders", None) test_node.send_header_for_blocks([blocks[1]]) - test_node.wait_for_getheaders(timeout=1) + test_node.wait_for_getheaders() test_node.send_header_for_blocks(blocks) test_node.wait_for_getdata([x.sha256 for x in blocks]) [ test_node.send_message(msg_block(x)) for x in blocks ] @@ -518,7 +518,7 @@ class SendHeadersTest(BitcoinTestFramework): with mininode_lock: test_node.last_message.pop("getheaders", None) test_node.send_header_for_blocks([blocks[i]]) - test_node.wait_for_getheaders(timeout=1) + test_node.wait_for_getheaders() # Next header will connect, should re-set our count: test_node.send_header_for_blocks([blocks[0]]) @@ -533,7 +533,7 @@ class SendHeadersTest(BitcoinTestFramework): with mininode_lock: test_node.last_message.pop("getheaders", None) test_node.send_header_for_blocks([blocks[i%len(blocks)]]) - test_node.wait_for_getheaders(timeout=1) + test_node.wait_for_getheaders() # Eventually this stops working. test_node.send_header_for_blocks([blocks[-1]]) diff --git a/test/functional/signmessages.py b/test/functional/signmessages.py index bfde8e40ec..42f6a9daaf 100755 --- a/test/functional/signmessages.py +++ b/test/functional/signmessages.py @@ -5,7 +5,6 @@ """Test RPC commands for signing and verifying messages.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * class SignMessagesTest(BitcoinTestFramework): diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py index fc49c23b9f..437905e764 100755 --- a/test/functional/signrawtransactions.py +++ b/test/functional/signrawtransactions.py @@ -114,6 +114,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): # 5) Script verification errors have certain properties assert 'txid' in rawTxSigned['errors'][0] assert 'vout' in rawTxSigned['errors'][0] + assert 'witness' in rawTxSigned['errors'][0] assert 'scriptSig' in rawTxSigned['errors'][0] assert 'sequence' in rawTxSigned['errors'][0] assert 'error' in rawTxSigned['errors'][0] @@ -123,6 +124,32 @@ class SignRawTransactionsTest(BitcoinTestFramework): assert_equal(rawTxSigned['errors'][0]['vout'], inputs[1]['vout']) assert_equal(rawTxSigned['errors'][1]['txid'], inputs[2]['txid']) assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout']) + assert not rawTxSigned['errors'][0]['witness'] + + # Now test signing failure for transaction with input witnesses + p2wpkh_raw_tx = "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000" + + rawTxSigned = self.nodes[0].signrawtransaction(p2wpkh_raw_tx) + + # 7) The transaction has no complete set of signatures + assert 'complete' in rawTxSigned + assert_equal(rawTxSigned['complete'], False) + + # 8) Two script verification errors occurred + assert 'errors' in rawTxSigned + assert_equal(len(rawTxSigned['errors']), 2) + + # 9) Script verification errors have certain properties + assert 'txid' in rawTxSigned['errors'][0] + assert 'vout' in rawTxSigned['errors'][0] + assert 'witness' in rawTxSigned['errors'][0] + assert 'scriptSig' in rawTxSigned['errors'][0] + assert 'sequence' in rawTxSigned['errors'][0] + assert 'error' in rawTxSigned['errors'][0] + + # Non-empty witness checked here + assert_equal(rawTxSigned['errors'][1]['witness'], ["304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01", "025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"]) + assert not rawTxSigned['errors'][0]['witness'] def run_test(self): self.successful_signing_test() diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index 19ffe9e851..4124f8025e 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -116,8 +116,8 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): for i,e in enumerate(all_estimates): # estimate is for i+1 if e >= 0: valid_estimate = True - # estimatesmartfee should return the same result - assert_equal(node.estimatesmartfee(i+1)["feerate"], e) + if i >= 13: # for n>=14 estimatesmartfee(n/2) should be at least as high as estimatefee(n) + assert(node.estimatesmartfee((i+1)//2)["feerate"] > float(e) - delta) else: invalid_estimates += 1 diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py index 9ab3094b06..dfcc524313 100644 --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -42,6 +42,7 @@ import decimal import json import logging import socket +import time try: import urllib.parse as urlparse except ImportError: @@ -163,6 +164,7 @@ class AuthServiceProxy(object): return self._request('POST', self.__url.path, postdata.encode('utf-8')) def _get_response(self): + req_start_time = time.time() try: http_response = self.__conn.getresponse() except socket.timeout as e: @@ -183,8 +185,9 @@ class AuthServiceProxy(object): responsedata = http_response.read().decode('utf8') response = json.loads(responsedata, parse_float=decimal.Decimal) + elapsed = time.time() - req_start_time if "error" in response and response["error"] is None: - log.debug("<-%s- %s"%(response["id"], json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) + log.debug("<-%s- [%.6f] %s"%(response["id"], elapsed, json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) else: - log.debug("<-- "+responsedata) + log.debug("<-- [%.6f] %s"%(elapsed,responsedata)) return response diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 03db0d1092..fb3ed1473a 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1358,6 +1358,8 @@ class msg_reject(object): # Helper function def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf')): + if attempts == float('inf') and timeout == float('inf'): + timeout = 60 attempt = 0 elapsed = 0 @@ -1604,7 +1606,12 @@ class NodeConnCB(object): assert wait_until(test_function, timeout=timeout) def wait_for_inv(self, expected_inv, timeout=60): - test_function = lambda: self.last_message.get("inv") and self.last_message["inv"] != expected_inv + """Waits for an INV message and checks that the first inv object in the message was as expected.""" + if len(expected_inv) > 1: + raise NotImplementedError("wait_for_inv() will only verify the first inv object") + 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].hash == expected_inv[0].hash assert wait_until(test_function, timeout=timeout) def wait_for_verack(self, timeout=60): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 3832f04ecd..4b5b311385 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -8,28 +8,55 @@ from collections import deque import logging import optparse import os -import sys import shutil +import subprocess +import sys import tempfile import time from .util import ( - initialize_chain, - start_nodes, + PortSeed, + MAX_NODES, + bitcoind_processes, + check_json_precision, connect_nodes_bi, + disable_mocktime, disconnect_nodes, + enable_coverage, + enable_mocktime, + get_mocktime, + get_rpc_proxy, + initialize_datadir, + log_filename, + p2p_port, + rpc_url, + set_node_times, + start_node, + start_nodes, + stop_node, + stop_nodes, sync_blocks, sync_mempools, - stop_nodes, - stop_node, - enable_coverage, - check_json_precision, - initialize_chain_clean, - PortSeed, + wait_for_bitcoind_start, ) from .authproxy import JSONRPCException class BitcoinTestFramework(object): + """Base class for a bitcoin test script. + + Individual bitcoin test scripts should subclass this class and override the following methods: + + - __init__() + - add_options() + - setup_chain() + - setup_network() + - run_test() + + The main() method should not be overridden. + + This class also contains various public and private helper methods.""" + + # Methods to override in subclass test scripts. TEST_EXIT_PASSED = 0 TEST_EXIT_FAILED = 1 @@ -40,27 +67,15 @@ class BitcoinTestFramework(object): self.setup_clean_chain = False self.nodes = None - def run_test(self): - raise NotImplementedError - def add_options(self, parser): pass def setup_chain(self): self.log.info("Initializing test directory "+self.options.tmpdir) if self.setup_clean_chain: - initialize_chain_clean(self.options.tmpdir, self.num_nodes) + self._initialize_chain_clean(self.options.tmpdir, self.num_nodes) else: - initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) - - def stop_node(self, num_node): - stop_node(self.nodes[num_node], num_node) - - def setup_nodes(self): - extra_args = None - if hasattr(self, "extra_args"): - extra_args = self.extra_args - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self._initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) def setup_network(self): self.setup_nodes() @@ -72,27 +87,16 @@ class BitcoinTestFramework(object): connect_nodes_bi(self.nodes, i, i + 1) self.sync_all() - def split_network(self): - """ - Split the network of four nodes into nodes 0/1 and 2/3. - """ - disconnect_nodes(self.nodes[1], 2) - disconnect_nodes(self.nodes[2], 1) - self.sync_all([self.nodes[:2], self.nodes[2:]]) - - def sync_all(self, node_groups=None): - if not node_groups: - node_groups = [self.nodes] + def setup_nodes(self): + extra_args = None + if hasattr(self, "extra_args"): + extra_args = self.extra_args + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) - [sync_blocks(group) for group in node_groups] - [sync_mempools(group) for group in node_groups] + def run_test(self): + raise NotImplementedError - def join_network(self): - """ - Join the (previously split) network halves together. - """ - connect_nodes_bi(self.nodes, 1, 2) - self.sync_all() + # Main function. This should not be overridden by the subclass test scripts. def main(self): @@ -105,8 +109,7 @@ class BitcoinTestFramework(object): help="Source directory containing bitcoind/bitcoin-cli (default: %default)") parser.add_option("--cachedir", dest="cachedir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../cache"), help="Directory for caching pregenerated datadirs") - parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), - help="Root directory for datadirs") + parser.add_option("--tmpdir", dest="tmpdir", help="Root directory for datadirs") parser.add_option("-l", "--loglevel", dest="loglevel", default="INFO", help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", @@ -120,9 +123,6 @@ class BitcoinTestFramework(object): self.add_options(parser) (self.options, self.args) = parser.parse_args() - # backup dir variable for removal at cleanup - self.options.root, self.options.tmpdir = self.options.tmpdir, self.options.tmpdir + '/' + str(self.options.port_seed) - if self.options.coveragedir: enable_coverage(self.options.coveragedir) @@ -133,7 +133,10 @@ class BitcoinTestFramework(object): check_json_precision() # Set up temp directory and start logging - os.makedirs(self.options.tmpdir, exist_ok=False) + if self.options.tmpdir: + os.makedirs(self.options.tmpdir, exist_ok=False) + else: + self.options.tmpdir = tempfile.mkdtemp(prefix="test") self._start_logging() success = False @@ -156,15 +159,13 @@ class BitcoinTestFramework(object): if not self.options.noshutdown: self.log.info("Stopping nodes") - stop_nodes(self.nodes) + self.stop_nodes() else: self.log.info("Note: bitcoinds were not stopped and may still be running") if not self.options.nocleanup and not self.options.noshutdown and success: self.log.info("Cleaning up") shutil.rmtree(self.options.tmpdir) - if not os.listdir(self.options.root): - os.rmdir(self.options.root) else: self.log.warning("Not cleaning up dir %s" % self.options.tmpdir) if os.getenv("PYTHON_DEBUG", ""): @@ -190,6 +191,45 @@ class BitcoinTestFramework(object): logging.shutdown() sys.exit(self.TEST_EXIT_FAILED) + # Public helper methods. These can be accessed by the subclass test scripts. + + def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): + return start_node(i, dirname, extra_args, rpchost, timewait, binary, stderr) + + def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + return start_nodes(num_nodes, dirname, extra_args, rpchost, timewait, binary) + + def stop_node(self, num_node): + stop_node(self.nodes[num_node], num_node) + + def stop_nodes(self): + stop_nodes(self.nodes) + + def split_network(self): + """ + Split the network of four nodes into nodes 0/1 and 2/3. + """ + disconnect_nodes(self.nodes[1], 2) + disconnect_nodes(self.nodes[2], 1) + self.sync_all([self.nodes[:2], self.nodes[2:]]) + + def join_network(self): + """ + Join the (previously split) network halves together. + """ + connect_nodes_bi(self.nodes, 1, 2) + self.sync_all() + + def sync_all(self, node_groups=None): + if not node_groups: + node_groups = [self.nodes] + + for group in node_groups: + sync_blocks(group) + sync_mempools(group) + + # Private helper methods. These should not be accessed by the subclass test scripts. + def _start_logging(self): # Add logger and logging handlers self.log = logging.getLogger('TestFramework') @@ -218,6 +258,88 @@ class BitcoinTestFramework(object): rpc_handler.setLevel(logging.DEBUG) rpc_logger.addHandler(rpc_handler) + def _initialize_chain(self, test_dir, num_nodes, cachedir): + """Initialize a pre-mined blockchain for use by the test. + + Create a cache of a 200-block-long chain (with wallet) for MAX_NODES + Afterward, create num_nodes copies from the cache.""" + + assert num_nodes <= MAX_NODES + create_cache = False + for i in range(MAX_NODES): + if not os.path.isdir(os.path.join(cachedir, 'node' + str(i))): + create_cache = True + break + + if create_cache: + self.log.debug("Creating data directories from cached datadir") + + # find and delete old cache directories if any exist + for i in range(MAX_NODES): + if os.path.isdir(os.path.join(cachedir, "node" + str(i))): + shutil.rmtree(os.path.join(cachedir, "node" + str(i))) + + # Create cache directories, run bitcoinds: + for i in range(MAX_NODES): + datadir = initialize_datadir(cachedir, i) + args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"] + if i > 0: + args.append("-connect=127.0.0.1:" + str(p2p_port(0))) + bitcoind_processes[i] = subprocess.Popen(args) + self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") + wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) + self.log.debug("initialize_chain: RPC successfully started") + + self.nodes = [] + for i in range(MAX_NODES): + try: + self.nodes.append(get_rpc_proxy(rpc_url(i), i)) + except: + self.log.exception("Error connecting to node %d" % i) + sys.exit(1) + + # Create a 200-block-long chain; each of the 4 first nodes + # gets 25 mature blocks and 25 immature. + # Note: To preserve compatibility with older versions of + # initialize_chain, only 4 nodes will generate coins. + # + # blocks are created with timestamps 10 minutes apart + # starting from 2010 minutes in the past + enable_mocktime() + block_time = get_mocktime() - (201 * 10 * 60) + for i in range(2): + for peer in range(4): + for j in range(25): + set_node_times(self.nodes, block_time) + self.nodes[peer].generate(1) + block_time += 10 * 60 + # Must sync before next peer starts generating blocks + sync_blocks(self.nodes) + + # Shut them down, and clean up cache directories: + self.stop_nodes() + self.nodes = [] + disable_mocktime() + for i in range(MAX_NODES): + os.remove(log_filename(cachedir, i, "debug.log")) + os.remove(log_filename(cachedir, i, "db.log")) + os.remove(log_filename(cachedir, i, "peers.dat")) + os.remove(log_filename(cachedir, i, "fee_estimates.dat")) + + for i in range(num_nodes): + from_dir = os.path.join(cachedir, "node" + str(i)) + to_dir = os.path.join(test_dir, "node" + str(i)) + shutil.copytree(from_dir, to_dir) + initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf + + def _initialize_chain_clean(self, test_dir, num_nodes): + """Initialize empty blockchain for use by the test. + + Create an empty blockchain and num_nodes wallets. + Useful if a test case wants complete control over initialization.""" + for i in range(num_nodes): + initialize_datadir(test_dir, i) + # Test framework for doing p2p comparison testing, which sets up some bitcoind # binaries: # 1 binary: test binary @@ -240,7 +362,7 @@ class ComparisonTestFramework(BitcoinTestFramework): help="bitcoind binary to use for reference nodes (if any)") def setup_network(self): - self.nodes = start_nodes( + self.nodes = self.start_nodes( self.num_nodes, self.options.tmpdir, extra_args=[['-whitelist=127.0.0.1']] * self.num_nodes, binary=[self.options.testbinary] + diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 9186c3cbe9..2b56fe8d62 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -226,87 +226,6 @@ def wait_for_bitcoind_start(process, url, i): raise # unknown JSON RPC exception time.sleep(0.25) -def initialize_chain(test_dir, num_nodes, cachedir): - """ - Create a cache of a 200-block-long chain (with wallet) for MAX_NODES - Afterward, create num_nodes copies from the cache - """ - - assert num_nodes <= MAX_NODES - create_cache = False - for i in range(MAX_NODES): - if not os.path.isdir(os.path.join(cachedir, 'node'+str(i))): - create_cache = True - break - - if create_cache: - logger.debug("Creating data directories from cached datadir") - - #find and delete old cache directories if any exist - for i in range(MAX_NODES): - if os.path.isdir(os.path.join(cachedir,"node"+str(i))): - shutil.rmtree(os.path.join(cachedir,"node"+str(i))) - - # Create cache directories, run bitcoinds: - for i in range(MAX_NODES): - datadir=initialize_datadir(cachedir, i) - args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ] - if i > 0: - args.append("-connect=127.0.0.1:"+str(p2p_port(0))) - bitcoind_processes[i] = subprocess.Popen(args) - logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up") - wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) - logger.debug("initialize_chain: RPC successfully started") - - rpcs = [] - for i in range(MAX_NODES): - try: - rpcs.append(get_rpc_proxy(rpc_url(i), i)) - except: - sys.stderr.write("Error connecting to "+url+"\n") - sys.exit(1) - - # Create a 200-block-long chain; each of the 4 first nodes - # gets 25 mature blocks and 25 immature. - # Note: To preserve compatibility with older versions of - # initialize_chain, only 4 nodes will generate coins. - # - # blocks are created with timestamps 10 minutes apart - # starting from 2010 minutes in the past - enable_mocktime() - block_time = get_mocktime() - (201 * 10 * 60) - for i in range(2): - for peer in range(4): - for j in range(25): - set_node_times(rpcs, block_time) - rpcs[peer].generate(1) - block_time += 10*60 - # Must sync before next peer starts generating blocks - sync_blocks(rpcs) - - # Shut them down, and clean up cache directories: - stop_nodes(rpcs) - disable_mocktime() - for i in range(MAX_NODES): - os.remove(log_filename(cachedir, i, "debug.log")) - os.remove(log_filename(cachedir, i, "db.log")) - os.remove(log_filename(cachedir, i, "peers.dat")) - os.remove(log_filename(cachedir, i, "fee_estimates.dat")) - - for i in range(num_nodes): - from_dir = os.path.join(cachedir, "node"+str(i)) - to_dir = os.path.join(test_dir, "node"+str(i)) - shutil.copytree(from_dir, to_dir) - initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf - -def initialize_chain_clean(test_dir, num_nodes): - """ - Create an empty blockchain and num_nodes wallets. - Useful if a test case wants complete control over initialization. - """ - for i in range(num_nodes): - datadir=initialize_datadir(test_dir, i) - def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): """ diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index c87010b0f4..b2aee7c739 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -16,6 +16,7 @@ For a description of arguments recognized by test scripts, see import argparse import configparser +import datetime import os import time import shutil @@ -163,17 +164,18 @@ def main(): Help text and arguments for individual test script:''', formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface') - parser.add_argument('--exclude', '-x', help='specify a comma-seperated-list of scripts to exclude. Do not include the .py extension in the name.') + parser.add_argument('--exclude', '-x', help='specify a comma-seperated-list of scripts to exclude.') parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests') parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).') parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit') parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.') parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.') parser.add_argument('--quiet', '-q', action='store_true', help='only print results summary and failure logs') + parser.add_argument('--tmpdirprefix', '-t', default=tempfile.gettempdir(), help="Root directory for datadirs") args, unknown_args = parser.parse_known_args() - # Create a set to store arguments and create the passon string - tests = set(arg for arg in unknown_args if arg[:2] != "--") + # args to be passed on always start with two dashes; tests are the remaining unknown args + tests = [arg for arg in unknown_args if arg[:2] != "--"] passon_args = [arg for arg in unknown_args if arg[:2] == "--"] # Read config generated by configure. @@ -187,6 +189,12 @@ def main(): logging_level = logging.INFO if args.quiet else logging.DEBUG logging.basicConfig(format='%(message)s', level=logging_level) + # Create base test directory + tmpdir = "%s/bitcoin_test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) + os.makedirs(tmpdir) + + logging.debug("Temporary test directory at %s" % tmpdir) + enable_wallet = config["components"].getboolean("ENABLE_WALLET") enable_utils = config["components"].getboolean("ENABLE_UTILS") enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND") @@ -206,8 +214,13 @@ def main(): if tests: # Individual tests have been specified. Run specified tests that exist # in the ALL_SCRIPTS list. Accept the name with or without .py extension. - test_list = [t for t in ALL_SCRIPTS if - (t in tests or re.sub(".py$", "", t) in tests)] + tests = [re.sub("\.py$", "", t) + ".py" for t in tests] + test_list = [] + for t in tests: + if t in ALL_SCRIPTS: + test_list.append(t) + else: + print("{}WARNING!{} Test '{}' not found in full test list.".format(BOLD[1], BOLD[0], t)) else: # No individual tests have been specified. # Run all base tests, and optionally run extended tests. @@ -219,9 +232,12 @@ def main(): # Remove the test cases that the user has explicitly asked to exclude. if args.exclude: - for exclude_test in args.exclude.split(','): - if exclude_test + ".py" in test_list: - test_list.remove(exclude_test + ".py") + tests_excl = [re.sub("\.py$", "", t) + ".py" for t in args.exclude.split(',')] + for exclude_test in tests_excl: + if exclude_test in test_list: + test_list.remove(exclude_test) + else: + print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], exclude_test)) if not test_list: print("No valid test scripts specified. Check that your test is in one " @@ -239,9 +255,9 @@ def main(): if not args.keepcache: shutil.rmtree("%s/test/cache" % config["environment"]["BUILDDIR"], ignore_errors=True) - run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args) + run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], tmpdir, args.jobs, args.coverage, passon_args) -def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]): +def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_coverage=False, args=[]): # Warn if bitcoind is already running (unix only) try: if subprocess.check_output(["pidof", "bitcoind"]) is not None: @@ -272,10 +288,10 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal if len(test_list) > 1 and jobs > 1: # Populate cache - subprocess.check_output([tests_dir + 'create_cache.py'] + flags) + subprocess.check_output([tests_dir + 'create_cache.py'] + flags + ["--tmpdir=%s/cache" % tmpdir]) #Run Tests - job_queue = TestHandler(jobs, tests_dir, test_list, flags) + job_queue = TestHandler(jobs, tests_dir, tmpdir, test_list, flags) time0 = time.time() test_results = [] @@ -302,6 +318,10 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal logging.debug("Cleaning up coverage data") coverage.cleanup() + # Clear up the temp directory if all subdirectories are gone + if not os.listdir(tmpdir): + os.rmdir(tmpdir) + all_passed = all(map(lambda test_result: test_result.was_successful, test_results)) sys.exit(not all_passed) @@ -329,10 +349,11 @@ class TestHandler: Trigger the testscrips passed in via the list. """ - def __init__(self, num_tests_parallel, tests_dir, test_list=None, flags=None): + def __init__(self, num_tests_parallel, tests_dir, tmpdir, test_list=None, flags=None): assert(num_tests_parallel >= 1) self.num_jobs = num_tests_parallel self.tests_dir = tests_dir + self.tmpdir = tmpdir self.test_list = test_list self.flags = flags self.num_running = 0 @@ -347,13 +368,15 @@ class TestHandler: # Add tests self.num_running += 1 t = self.test_list.pop(0) - port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)] + portseed = len(self.test_list) + self.portseed_offset + portseed_arg = ["--portseed={}".format(portseed)] log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) test_argv = t.split() + tmpdir = ["--tmpdir=%s/%s_%s" % (self.tmpdir, re.sub(".py$", "", test_argv[0]), portseed)] self.jobs.append((t, time.time(), - subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + port_seed, + subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + portseed_arg + tmpdir, universal_newlines=True, stdout=log_stdout, stderr=log_stderr), diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py index 8dc1589117..e6635bea1c 100755 --- a/test/functional/wallet-accounts.py +++ b/test/functional/wallet-accounts.py @@ -15,7 +15,6 @@ RPCs tested are: from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( - start_nodes, assert_equal, ) diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py index bbf53e7dba..aab3b4bc2d 100755 --- a/test/functional/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -6,7 +6,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( - start_nodes, start_node, assert_equal, connect_nodes_bi, diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 57f6dfdaa9..efde2e005e 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -57,8 +57,13 @@ class WalletTest(BitcoinTestFramework): assert_equal(len(self.nodes[2].listunspent()), 0) # Send 21 BTC from 0 to 2 using sendtoaddress call. + # Locked memory should use at least 32 bytes to sign each transaction + self.log.info("test getmemoryinfo") + memory_before = self.nodes[0].getmemoryinfo() self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + memory_after = self.nodes[0].getmemoryinfo() + assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used']) self.log.info("test gettxout") # utxo spent in mempool should be visible if you exclude mempool @@ -78,7 +83,6 @@ class WalletTest(BitcoinTestFramework): # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) - walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) |