aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/assumevalid.py102
-rwxr-xr-xtest/functional/fundrawtransaction.py36
-rwxr-xr-xtest/functional/test_framework/test_framework.py16
-rwxr-xr-xtest/functional/test_runner.py55
4 files changed, 131 insertions, 78 deletions
diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py
index c60c8e6d1a..da680a5d24 100755
--- a/test/functional/assumevalid.py
+++ b/test/functional/assumevalid.py
@@ -15,7 +15,7 @@ transactions:
2-101: bury that block with 100 blocks so the coinbase transaction
output can be spent
102: a block containing a transaction spending the coinbase
- transaction output. The transaction has an invalid signature.
+ transaction output. The transaction has an invalid signature.
103-2202: bury the bad block with just over two weeks' worth of blocks
(2100 blocks)
@@ -29,40 +29,34 @@ Start three nodes:
block 200. node2 will reject block 102 since it's assumed valid, but it
isn't buried by at least two weeks' work.
"""
+import time
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.blocktools import create_block, create_coinbase
+from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.key import CECKey
-from test_framework.script import *
+from test_framework.mininode import (CBlockHeader,
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxOut,
+ NetworkThread,
+ NodeConn,
+ SingleNodeConnCB,
+ msg_block,
+ msg_headers)
+from test_framework.script import (CScript, OP_TRUE)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (start_node, p2p_port, assert_equal)
class BaseNode(SingleNodeConnCB):
def __init__(self):
- SingleNodeConnCB.__init__(self)
- self.last_inv = None
- self.last_headers = None
- self.last_block = None
- self.last_getdata = None
- self.block_announced = False
- self.last_getheaders = None
- self.disconnected = False
- self.last_blockhash_announced = None
-
- def on_close(self, conn):
- self.disconnected = True
-
- def wait_for_disconnect(self, timeout=60):
- test_function = lambda: self.disconnected
- assert(wait_until(test_function, timeout=timeout))
- return
+ super().__init__()
def send_header_for_blocks(self, new_blocks):
headers_message = msg_headers()
- headers_message.headers = [ CBlockHeader(b) for b in new_blocks ]
+ headers_message.headers = [CBlockHeader(b) for b in new_blocks]
self.send_message(headers_message)
-class SendHeadersTest(BitcoinTestFramework):
+class AssumeValidTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = True
@@ -72,8 +66,34 @@ class SendHeadersTest(BitcoinTestFramework):
# Start node0. We don't start the other nodes yet since
# we need to pre-mine a block with an invalid transaction
# signature so we can pass in the block hash as assumevalid.
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes = [start_node(0, self.options.tmpdir)]
+
+ def send_blocks_until_disconnected(self, node):
+ """Keep sending blocks to the node until we're disconnected."""
+ for i in range(len(self.blocks)):
+ try:
+ node.send_message(msg_block(self.blocks[i]))
+ except IOError as e:
+ assert str(e) == 'Not connected, no pushbuf'
+ break
+
+ def assert_blockchain_height(self, node, height):
+ """Wait until the blockchain is no longer advancing and verify it's reached the expected height."""
+ last_height = node.getblock(node.getbestblockhash())['height']
+ timeout = 10
+ while True:
+ time.sleep(0.25)
+ current_height = node.getblock(node.getbestblockhash())['height']
+ if current_height != last_height:
+ last_height = current_height
+ if timeout < 0:
+ assert False, "blockchain too short after timeout: %d" % current_height
+ timeout - 0.25
+ continue
+ elif current_height > height:
+ assert False, "blockchain too long: %d" % current_height
+ elif current_height == height:
+ break
def run_test(self):
@@ -83,7 +103,7 @@ class SendHeadersTest(BitcoinTestFramework):
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
node0.add_connection(connections[0])
- NetworkThread().start() # Start up network handling in another thread
+ NetworkThread().start() # Start up network handling in another thread
node0.wait_for_verack()
# Build the blockchain
@@ -120,7 +140,7 @@ class SendHeadersTest(BitcoinTestFramework):
# Create a transaction spending the coinbase output with an invalid (null) signature
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b""))
- tx.vout.append(CTxOut(49*100000000, CScript([OP_TRUE])))
+ tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
tx.calc_sha256()
block102 = create_block(self.tip, create_coinbase(height), self.block_time)
@@ -166,25 +186,19 @@ class SendHeadersTest(BitcoinTestFramework):
node1.send_header_for_blocks(self.blocks[2000:])
node2.send_header_for_blocks(self.blocks[0:200])
- # Send 102 blocks to node0. Block 102 will be rejected.
- for i in range(101):
- node0.send_message(msg_block(self.blocks[i]))
- node0.sync_with_ping() # make sure the most recent block is synced
- node0.send_message(msg_block(self.blocks[101]))
- assert_equal(self.nodes[0].getblock(self.nodes[0].getbestblockhash())['height'], 101)
+ # Send blocks to node0. Block 102 will be rejected.
+ self.send_blocks_until_disconnected(node0)
+ self.assert_blockchain_height(self.nodes[0], 101)
- # Send 3102 blocks to node1. All blocks will be accepted.
+ # Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
node1.send_message(msg_block(self.blocks[i]))
- node1.sync_with_ping() # make sure the most recent block is synced
+ node1.sync_with_ping() # make sure the most recent block is synced
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
- # Send 102 blocks to node2. Block 102 will be rejected.
- for i in range(101):
- node2.send_message(msg_block(self.blocks[i]))
- node2.sync_with_ping() # make sure the most recent block is synced
- node2.send_message(msg_block(self.blocks[101]))
- assert_equal(self.nodes[2].getblock(self.nodes[2].getbestblockhash())['height'], 101)
+ # Send blocks to node2. Block 102 will be rejected.
+ self.send_blocks_until_disconnected(node2)
+ self.assert_blockchain_height(self.nodes[2], 101)
if __name__ == '__main__':
- SendHeadersTest().main()
+ AssumeValidTest().main()
diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index 1dc00f2ba1..3bfc05d37b 100755
--- a/test/functional/fundrawtransaction.py
+++ b/test/functional/fundrawtransaction.py
@@ -322,8 +322,8 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee of a standard pubkeyhash transaction
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)
@@ -338,8 +338,8 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee of a standard pubkeyhash transaction with multiple outputs
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendmany("", outputs)
signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']
@@ -364,8 +364,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {mSigObj:1.1}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
@@ -397,8 +397,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {mSigObj:1.1}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
@@ -432,8 +432,8 @@ class RawTransactionsTest(BitcoinTestFramework):
oldBalance = self.nodes[1].getbalance()
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1}
- rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[2].fundrawtransaction(rawTx)
+ rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[2].fundrawtransaction(rawtx)
signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])
txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
@@ -469,10 +469,10 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[1].getnewaddress()
inputs = []
outputs = {self.nodes[0].getnewaddress():1.1}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
- assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[1].fundrawtransaction, rawtx)
+ assert_raises_jsonrpc(-4, "Keypool ran out, please call keypoolrefill first", self.nodes[1].fundrawtransaction, rawtx)
#refill the keypool
self.nodes[1].walletpassphrase("test", 100)
@@ -484,8 +484,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {self.nodes[0].getnewaddress():1.1}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[1].fundrawtransaction(rawtx)
#now we need to unlock
self.nodes[1].walletpassphrase("test", 600)
@@ -516,8 +516,8 @@ class RawTransactionsTest(BitcoinTestFramework):
#fund a tx with ~20 small inputs
inputs = []
outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[1].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[1].sendmany("", outputs)
@@ -548,8 +548,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[1].fundrawtransaction(rawtx)
fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
self.sync_all()
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 26a8aacb41..473b7c14a9 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Base class for RPC testing."""
+from collections import deque
import logging
import optparse
import os
@@ -177,12 +178,17 @@ class BitcoinTestFramework(object):
# Dump the end of the debug logs, to aid in debugging rare
# travis failures.
import glob
- filenames = glob.glob(self.options.tmpdir + "/node*/regtest/debug.log")
+ filenames = [self.options.tmpdir + "/test_framework.log"]
+ filenames += glob.glob(self.options.tmpdir + "/node*/regtest/debug.log")
MAX_LINES_TO_PRINT = 1000
- for f in filenames:
- print("From" , f, ":")
- from collections import deque
- print("".join(deque(open(f), MAX_LINES_TO_PRINT)))
+ for fn in filenames:
+ try:
+ with open(fn, 'r') as f:
+ print("From" , fn, ":")
+ print("".join(deque(f, MAX_LINES_TO_PRINT)))
+ except OSError:
+ print("Opening file %s failed." % fn)
+ traceback.print_exc()
if success:
self.log.info("Tests successful")
sys.exit(self.TEST_EXIT_PASSED)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 5bd71fe328..37a2ab62a4 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -23,6 +23,7 @@ import sys
import subprocess
import tempfile
import re
+import logging
TEST_EXIT_PASSED = 0
TEST_EXIT_SKIPPED = 77
@@ -90,7 +91,7 @@ BASE_SCRIPTS= [
ZMQ_SCRIPTS = [
# ZMQ test can only be run if bitcoin was built with zmq-enabled.
# call test_runner.py with -nozmq to explicitly exclude these tests.
- "zmq_test.py"]
+ 'zmq_test.py']
EXTENDED_SCRIPTS = [
# These tests are not run by the travis build process.
@@ -110,6 +111,7 @@ EXTENDED_SCRIPTS = [
'p2p-feefilter.py',
'rpcbind_test.py',
# vv Tests less than 30s vv
+ 'assumevalid.py',
'bip65-cltv.py',
'bip65-cltv-p2p.py',
'bipdersig-p2p.py',
@@ -126,6 +128,13 @@ EXTENDED_SCRIPTS = [
ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS
+NON_SCRIPTS = [
+ # These are python files that live in the functional tests directory, but are not test scripts.
+ "combine_logs.py",
+ "create_cache.py",
+ "test_runner.py",
+]
+
def main():
# Parse arguments and pass through unrecognised args
parser = argparse.ArgumentParser(add_help=False,
@@ -140,6 +149,7 @@ def main():
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('--quiet', '-q', action='store_true', help='only print results summary and failure logs')
parser.add_argument('--nozmq', action='store_true', help='do not run the zmq tests')
args, unknown_args = parser.parse_known_args()
@@ -151,6 +161,10 @@ def main():
config = configparser.ConfigParser()
config.read_file(open(os.path.dirname(__file__) + "/config.ini"))
+ # Set up logging
+ logging_level = logging.INFO if args.quiet else logging.DEBUG
+ logging.basicConfig(format='%(message)s', level=logging_level)
+
enable_wallet = config["components"].getboolean("ENABLE_WALLET")
enable_utils = config["components"].getboolean("ENABLE_UTILS")
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
@@ -206,11 +220,13 @@ def main():
sys.exit(0)
if args.help:
- # Print help for test_runner.py, then print help of the first script and exit.
+ # Print help for test_runner.py, then print help of the first script (with args removed) and exit.
parser.print_help()
- subprocess.check_call((config["environment"]["SRCDIR"] + '/test/functional/' + test_list[0]).split() + ['-h'])
+ subprocess.check_call([(config["environment"]["SRCDIR"] + '/test/functional/' + test_list[0].split()[0])] + ['-h'])
sys.exit(0)
+ check_script_list(config["environment"]["SRCDIR"])
+
run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
@@ -232,7 +248,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal
if enable_coverage:
coverage = RPCCoverage()
flags.append(coverage.flag)
- print("Initializing coverage directory at %s\n" % coverage.dir)
+ logging.debug("Initializing coverage directory at %s" % coverage.dir)
else:
coverage = None
@@ -248,16 +264,20 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal
job_queue = TestHandler(jobs, tests_dir, test_list, flags)
max_len_name = len(max(test_list, key=len))
- results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0]
+ results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0]
for _ in range(len(test_list)):
(name, stdout, stderr, status, duration) = job_queue.get_next()
all_passed = all_passed and status != "Failed"
time_sum += duration
- print('\n' + BOLD[1] + name + BOLD[0] + ":")
- print('' if status == "Passed" else stdout + '\n', end='')
- print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
- print("Status: %s%s%s, Duration: %s s\n" % (BOLD[1], status, BOLD[0], duration))
+ if status == "Passed":
+ logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], name, BOLD[0], duration))
+ elif status == "Skipped":
+ logging.debug("\n%s%s%s skipped" % (BOLD[1], name, BOLD[0]))
+ else:
+ print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], name, BOLD[0], duration))
+ print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
+ print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
results += "%s | %s | %s s\n" % (name.ljust(max_len_name), status.ljust(7), duration)
@@ -268,7 +288,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal
if coverage:
coverage.report_rpc_coverage()
- print("Cleaning up coverage data")
+ logging.debug("Cleaning up coverage data")
coverage.cleanup()
sys.exit(not all_passed)
@@ -299,9 +319,10 @@ class TestHandler:
port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)]
log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
+ test_argv = t.split()
self.jobs.append((t,
time.time(),
- subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed,
+ subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + port_seed,
universal_newlines=True,
stdout=log_stdout,
stderr=log_stderr),
@@ -329,6 +350,18 @@ class TestHandler:
return name, stdout, stderr, status, int(time.time() - time0)
print('.', end='', flush=True)
+def check_script_list(src_dir):
+ """Check scripts directory.
+
+ Check that there are no scripts in the functional tests directory which are
+ not being run by pull-tester.py."""
+ script_dir = src_dir + '/test/functional/'
+ python_files = set([t for t in os.listdir(script_dir) if t[-3:] == ".py"])
+ missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))
+ if len(missed_tests) != 0:
+ print("The following scripts are not being run:" + str(missed_tests))
+ print("Check the test lists in test_runner.py")
+ sys.exit(1)
class RPCCoverage(object):
"""