aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--src/init.cpp39
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/wallet/wallet.cpp4
-rw-r--r--src/zmq/zmqpublishnotifier.cpp3
-rwxr-xr-xtest/functional/assumevalid.py102
-rwxr-xr-xtest/functional/combine_logs.py7
-rwxr-xr-xtest/functional/fundrawtransaction.py36
-rwxr-xr-xtest/functional/test_framework/test_framework.py16
-rwxr-xr-xtest/functional/test_runner.py46
10 files changed, 163 insertions, 96 deletions
diff --git a/.travis.yml b/.travis.yml
index 503172f2a9..d8395255bc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -71,7 +71,7 @@ script:
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS check VERBOSE=1; fi
- if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude pruning"; fi
- - if [ "$RUN_TESTS" = "true" ]; then test/functional/test_runner.py --coverage ${extended}; fi
+ - if [ "$RUN_TESTS" = "true" ]; then test/functional/test_runner.py --coverage --quiet ${extended}; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
- echo $TRAVIS_COMMIT_LOG
diff --git a/src/init.cpp b/src/init.cpp
index 5cdac21a21..253337c162 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -265,18 +265,31 @@ void Shutdown()
}
/**
- * Signal handlers are very limited in what they are allowed to do, so:
+ * Signal handlers are very limited in what they are allowed to do.
+ * The execution context the handler is invoked in is not guaranteed,
+ * so we restrict handler operations to just touching variables:
*/
-void HandleSIGTERM(int)
+static void HandleSIGTERM(int)
{
fRequestShutdown = true;
}
-void HandleSIGHUP(int)
+static void HandleSIGHUP(int)
{
fReopenDebugLog = true;
}
+#ifndef WIN32
+static void registerSignalHandler(int signal, void(*handler)(int))
+{
+ struct sigaction sa;
+ sa.sa_handler = handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(signal, &sa, NULL);
+}
+#endif
+
bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {
if (!(flags & BF_EXPLICIT) && IsLimited(addr))
return false;
@@ -360,13 +373,13 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD));
strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME));
strUsage += HelpMessageOpt("-bind=<addr>", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6"));
- strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections"));
+ strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections"));
strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)"));
strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP));
- strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)"));
+ strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)"));
strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address"));
strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED));
- strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)"));
+ strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)"));
strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION));
strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
@@ -848,19 +861,11 @@ bool AppInitBasicSetup()
}
// Clean shutdown on SIGTERM
- struct sigaction sa;
- sa.sa_handler = HandleSIGTERM;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
+ registerSignalHandler(SIGTERM, HandleSIGTERM);
+ registerSignalHandler(SIGINT, HandleSIGTERM);
// Reopen debug.log on SIGHUP
- struct sigaction sa_hup;
- sa_hup.sa_handler = HandleSIGHUP;
- sigemptyset(&sa_hup.sa_mask);
- sa_hup.sa_flags = 0;
- sigaction(SIGHUP, &sa_hup, NULL);
+ registerSignalHandler(SIGHUP, HandleSIGHUP);
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
signal(SIGPIPE, SIG_IGN);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 7a0d0b3e0a..5167232d6a 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -175,6 +175,10 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
nDepthInsideSensitive = 1;
filter_begin_pos = chpos;
}
+ // Make sure stack is not empty before adding something
+ if (stack.empty()) {
+ stack.push_back(std::vector<std::string>());
+ }
stack.back().push_back(strArg);
};
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 445e40b043..39e2ab7c1f 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2023,7 +2023,7 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const
}
}
-static void ApproximateBestSubset(std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
+static void ApproximateBestSubset(const std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > >& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{
std::vector<char> vfIncluded;
@@ -2885,7 +2885,7 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
/**
* Mark old keypool keys as used,
- * and generate all new keys
+ * and generate all new keys
*/
bool CWallet::NewKeyPool()
{
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index caca1248a1..4e13cbcaf4 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -30,6 +30,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
if (rc != 0)
{
zmqError("Unable to initialize ZMQ msg");
+ va_end(args);
return -1;
}
@@ -43,6 +44,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
{
zmqError("Unable to send ZMQ msg");
zmq_msg_close(&msg);
+ va_end(args);
return -1;
}
@@ -53,6 +55,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
size = va_arg(args, size_t);
}
+ va_end(args);
return 0;
}
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/combine_logs.py b/test/functional/combine_logs.py
index 0c2f60172f..3ca74ea35e 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -6,8 +6,8 @@ to write to an outputfile."""
import argparse
from collections import defaultdict, namedtuple
-import glob
import heapq
+import itertools
import os
import re
import sys
@@ -49,7 +49,10 @@ def read_logs(tmp_dir):
for each of the input log files."""
files = [("test", "%s/test_framework.log" % tmp_dir)]
- for i, logfile in enumerate(glob.glob("%s/node*/regtest/debug.log" % tmp_dir)):
+ for i in itertools.count():
+ logfile = "{}/node{}/regtest/debug.log".format(tmp_dir, i)
+ if not os.path.isfile(logfile):
+ break
files.append(("node%d" % i, logfile))
return heapq.merge(*[get_log_events(source, f) for source, f in files])
diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index fcae56f7dd..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, "Keypool ran out, please call keypoolrefill first", 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 0f730aeaac..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
@@ -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")
@@ -211,6 +225,8 @@ def main():
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)
@@ -330,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):
"""