diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py index f322b3a880..98eee67f43 100755 --- a/contrib/devtools/clang-format-diff.py +++ b/contrib/devtools/clang-format-diff.py @@ -106,7 +106,7 @@ def main(): filename = None lines_by_file = {} for line in sys.stdin: - match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) + match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) if match: filename = match.group(2) if filename is None: @@ -119,7 +119,7 @@ def main(): if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): continue - match = re.search('^@@.*\+(\d+)(,(\d+))?', line) + match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) if match: start_line = int(match.group(1)) line_count = 1 diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index 827cf871b3..784ec186b5 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -41,8 +41,7 @@ def applies_to_file(filename): for excluded_dir in EXCLUDE_DIRS: if filename.startswith(excluded_dir): return False - return ((EXCLUDE_COMPILED.match(filename) is None) and - (INCLUDE_COMPILED.match(filename) is not None)) + return ((EXCLUDE_COMPILED.match(filename) is None) and (INCLUDE_COMPILED.match(filename) is not None)) ################################################################################ # obtain list of files in repo according to INCLUDE and EXCLUDE @@ -71,7 +70,7 @@ def get_filenames_to_examine(base_directory): ################################################################################ -COPYRIGHT_WITH_C = 'Copyright \(c\)' +COPYRIGHT_WITH_C = 'Copyright (c)' COPYRIGHT_WITHOUT_C = 'Copyright' ANY_COPYRIGHT_STYLE = '(%s|%s)' % (COPYRIGHT_WITH_C, COPYRIGHT_WITHOUT_C) @@ -90,8 +89,8 @@ def compile_copyright_regex(copyright_style, year_style, name): EXPECTED_HOLDER_NAMES = [ "Satoshi Nakamoto\n", "The Bitcoin Core developers\n", - "BitPay Inc\.\n", - "University of Illinois at Urbana-Champaign\.\n", + "BitPay Inc.\n", + "University of Illinois at Urbana-Champaign.\n", "Pieter Wuille\n", "Wladimir J. van der Laan\n", "Jeff Garzik\n", @@ -330,7 +329,7 @@ def write_file_lines(filename, file_lines): # update header years execution ################################################################################ -COPYRIGHT = 'Copyright \(c\)' +COPYRIGHT = 'Copyright (c)' YEAR = "20[0-9][0-9]" YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR) HOLDER = 'The Bitcoin Core developers' @@ -369,9 +368,7 @@ def create_updated_copyright_line(line, last_git_change_year): start_year, end_year = parse_year_range(year_range) if end_year == last_git_change_year: return line - return (before_copyright + copyright_splitter + - year_range_to_str(start_year, last_git_change_year) + ' ' + - ' '.join(space_split[1:])) + return (before_copyright + copyright_splitter + year_range_to_str(start_year, last_git_change_year) + ' ' + ' '.join(space_split[1:])) def update_updatable_copyright(filename): file_lines = read_file_lines(filename) diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py index 13aeaa164a..461d46f69c 100755 --- a/contrib/devtools/optimize-pngs.py +++ b/contrib/devtools/optimize-pngs.py @@ -44,8 +44,8 @@ def content_hash(filename): try: subprocess.call([pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path], - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except: + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + except FileNotFoundError: print("pngcrush is not installed, aborting...") sys.exit(0) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index c507a1b660..8e390b20e9 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -153,7 +153,7 @@ def check_PE_HIGH_ENTROPY_VA(executable): if arch == 'i386:x86-64': reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA else: # Unnecessary on 32-bit - assert(arch == 'i386') + assert (arch == 'i386') reqbits = 0 return (bits & reqbits) == reqbits diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index be80e15e44..b0edbb5a27 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -141,7 +141,7 @@ def read_libraries(filename): for line in stdout.splitlines(): tokens = line.split() if len(tokens)>2 and tokens[1] == '(NEEDED)': - match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:])) + match = re.match(r'^Shared library: \[(.*)\]$', ' '.join(tokens[2:])) if match: libraries.append(match.group(1)) else: diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index bd7b49a563..1693a4bd04 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -29,8 +29,7 @@ def uint32(x): return x & 0xffffffff def bytereverse(x): - return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) | - (((x) >> 8) & 0x0000ff00) | ((x) >> 24) )) + return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) | (((x) >> 8) & 0x0000ff00) | ((x) >> 24) )) def bufreverse(in_buf): out_words = [] @@ -263,12 +262,12 @@ def run(self): f = open(sys.argv[1], encoding="utf8") for line in f: # skip comment lines - m = re.search('^\s*#', line) + m = re.search(r'^\s*#', line) if m: continue # parse key=value lines - m = re.search('^(\w+)\s*=\s*(\S.*)$', line) + m = re.search(r'^(\w+)\s*=\s*(\S.*)$', line) if m is None: continue settings[m.group(1)] = m.group(2) diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py index 2abf75e8b6..0e5600ca41 100755 --- a/contrib/linearize/linearize-hashes.py +++ b/contrib/linearize/linearize-hashes.py @@ -83,7 +83,7 @@ def get_block_hashes(settings, max_blocks_per_call=10000): if rpc.response_is_error(resp_obj): print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr) sys.exit(1) - assert(resp_obj['id'] == x) # assume replies are in-sequence + assert (resp_obj['id'] == x) # assume replies are in-sequence if settings['rev_hash_bytes'] == 'true': resp_obj['result'] = hex_switchEndian(resp_obj['result']) print(resp_obj['result']) @@ -106,12 +106,12 @@ def get_rpc_cookie(): f = open(sys.argv[1], encoding="utf8") for line in f: # skip comment lines - m = re.search('^\s*#', line) + m = re.search(r'^\s*#', line) if m: continue # parse key=value lines - m = re.search('^(\w+)\s*=\s*(\S.*)$', line) + m = re.search(r'^(\w+)\s*=\s*(\S.*)$', line) if m is None: continue settings[m.group(1)] = m.group(2) diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 2637364c13..53f2a508a3 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -61,13 +61,13 @@ def name_to_ipv6(addr): if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end continue x += 1 # :: skips to suffix - assert(x < 2) + assert (x < 2) else: # two bytes per component val = int(comp, 16) sub[x].append(val >> 8) sub[x].append(val & 0xff) nullbytes = 16 - len(sub[0]) - len(sub[1]) - assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) + assert ((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) return bytearray(sub[0] + ([0] * nullbytes) + sub[1]) elif addr.startswith('0x'): # IPv4-in-little-endian return pchIPv4 + bytearray(reversed(a2b_hex(addr[2:]))) @@ -75,7 +75,7 @@ def name_to_ipv6(addr): raise ValueError('Could not parse address %s' % addr) def parse_spec(s, defaultport): - match = re.match('\[([0-9a-fA-F:]+)\](?::([0-9]+))?$', s) + match = re.match(r'\[([0-9a-fA-F:]+)\](?::([0-9]+))?$', s) if match: # ipv6 host = match.group(1) port = match.group(2) diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 71eead14dc..15aa5d6da6 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -139,7 +139,7 @@ def filterbyasn(ips, max_per_asn, max_total): continue asn_count[asn] += 1 result.append(ip) - except: + except ModuleNotFoundError: sys.stderr.write('ERR: Could not resolve ASN for "' + ip['ip'] + '"\n') # Add back Onions diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py index 2253cfc31a..12d618f573 100644 --- a/contrib/testgen/base58.py +++ b/contrib/testgen/base58.py @@ -107,7 +107,7 @@ def get_bcaddress_version(strAddress): if __name__ == '__main__': # Test case (from http://gitorious.org/bitcoin/python-base58.git) - assert get_bcaddress_version('15VjRaDX9zpbA8LVnbrCAFzrVzN7ixHNsC') is 0 + assert get_bcaddress_version('15VjRaDX9zpbA8LVnbrCAFzrVzN7ixHNsC') == 0 _ohai = 'o hai'.encode('ascii') _tmp = b58encode(_ohai) assert _tmp == 'DYB3oMS' diff --git a/test/README.md b/test/README.md index 11e39d7cff..fb1a1b5b68 100644 --- a/test/README.md +++ b/test/README.md @@ -6,10 +6,10 @@ etc. This directory contains the following sets of tests: - [functional](/test/functional) which test the functionality of -defid and defi-qt by interacting with them through the RPC and P2P -interfaces. + defid and defi-qt by interacting with them through the RPC and P2P + interfaces. - [util](/test/util) which tests the defi utilities, currently only -defi-tx. + defi-tx. - [lint](/test/lint/) which perform various static analysis checks. The util tests are run as part of `make check` target. The functional @@ -17,8 +17,7 @@ tests and lint scripts can be run as explained in the sections below. # Running tests locally -Before tests can be run locally, DeFi Blockchain must be built. See the [building instructions](/doc#building) for help. - +Before tests can be run locally, DeFi Blockchain must be built. See the [building instructions](/doc#building) for help. ### Functional tests @@ -119,7 +118,6 @@ or pkill -9 defid ``` - ##### Data directory cache A pre-mined blockchain with 200 blocks is generated the first time a diff --git a/test/functional/README.md b/test/functional/README.md index d832a3cd38..a99aeea657 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -23,7 +23,8 @@ don't have test cases for. - The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md). Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version), to prevent accidentally introducing modern syntax from an unsupported Python version. - The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126). + The Travis linter also checks this, + but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126). - See [the python lint script](/test/lint/lint-python.sh) that checks for violations that could lead to bugs and issues in the test code. - Avoid wildcard imports @@ -46,7 +47,8 @@ don't have test cases for. - `tool` for tests for tools, eg `tool_wallet.py` - `wallet` for tests for wallet features, eg `wallet_keypool.py` - use an underscore to separate words - - exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py` + - exception: for tests for specific RPCs or command line options which don't include underscores, name the test + after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py` - Don't use the redundant word `test` in the name, eg `interface_zmq.py`, not `interface_zmq_test.py` #### General test-writing advice @@ -83,45 +85,53 @@ P2P messages. These can be found in the following source files: #### Using the P2P interface - `messages.py` contains all the definitions for objects that pass -over the network (`CBlock`, `CTransaction`, etc, along with the network-level -wrappers for them, `msg_block`, `msg_tx`, etc). + over the network (`CBlock`, `CTransaction`, etc, along with the network-level + wrappers for them, `msg_block`, `msg_tx`, etc). - P2P tests have two threads. One thread handles all network communication -with the defid(s) being tested in a callback-based event loop; the other -implements the test logic. + with the defid(s) being tested in a callback-based event loop; the other + implements the test logic. - `P2PConnection` is the class used to connect to a defid. `P2PInterface` -contains the higher level logic for processing P2P payloads and connecting to -the DeFi Blockchain node application logic. For custom behaviour, subclass the -P2PInterface object and override the callback methods. + contains the higher level logic for processing P2P payloads and connecting to + the DeFi Blockchain node application logic. For custom behaviour, subclass the + P2PInterface object and override the callback methods. - Can be used to write tests where specific P2P protocol behavior is tested. -Examples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`. + Examples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`. ### test-framework modules #### [test_framework/authproxy.py](test_framework/authproxy.py) + Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc). #### [test_framework/test_framework.py](test_framework/test_framework.py) + Base class for functional tests. #### [test_framework/util.py](test_framework/util.py) + Generally useful functions. #### [test_framework/mininode.py](test_framework/mininode.py) + Basic code to support P2P connectivity to a defid. #### [test_framework/script.py](test_framework/script.py) + Utilities for manipulating transaction scripts (originally from python-bitcoinlib) #### [test_framework/key.py](test_framework/key.py) + Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib) #### [test_framework/bignum.py](test_framework/bignum.py) + Helpers for script.py #### [test_framework/blocktools.py](test_framework/blocktools.py) + Helper functions for creating blocks and transactions. ### Benchmarking with perf diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py index f155570686..9892791ee8 100755 --- a/test/functional/combine_logs.py +++ b/test/functional/combine_logs.py @@ -28,6 +28,7 @@ LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event']) + def main(): """Main function. Parses args, reads the log files and renders them as text or html.""" parser = argparse.ArgumentParser( @@ -36,8 +37,10 @@ def main(): 'testdir', nargs='?', default='', help=('temporary test directory to combine logs from. ' 'Defaults to the most recent')) - parser.add_argument('-c', '--color', dest='color', action='store_true', help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)') - parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2') + parser.add_argument('-c', '--color', dest='color', action='store_true', + help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)') + parser.add_argument('--html', dest='html', action='store_true', + help='outputs the combined log as html. Requires jinja2. pip install jinja2') args = parser.parse_args() if args.html and args.color: @@ -81,7 +84,7 @@ def read_logs(tmp_dir): chain = glob.glob("{}/node0/*/debug.log".format(tmp_dir)) if chain: chain = chain[0] # pick the first one if more than one chain was found (should never happen) - chain = re.search('node0/(.+?)/debug\.log$', chain).group(1) # extract the chain name + chain = re.search(r'node0/(.+?)/debug\.log$', chain).group(1) # extract the chain name else: chain = 'regtest' # fallback to regtest (should only happen when none exists) @@ -125,9 +128,9 @@ def join_tmp(basename): def is_valid_test_tmpdir(basename): fullpath = join_tmp(basename) return ( - os.path.isdir(fullpath) - and basename.startswith(TMPDIR_PREFIX) - and os.access(fullpath, os.R_OK) + os.path.isdir(fullpath) + and basename.startswith(TMPDIR_PREFIX) + and os.access(fullpath, os.R_OK) ) testdir_paths = [ @@ -190,8 +193,8 @@ def print_logs_html(log_events): print("jinja2 not found. Try `pip install jinja2`") sys.exit(1) print(jinja2.Environment(loader=jinja2.FileSystemLoader('./')) - .get_template('combined_log_template.html') - .render(title="Combined Logs from testcase", log_events=[event._asdict() for event in log_events])) + .get_template('combined_log_template.html') + .render(title="Combined Logs from testcase", log_events=[event._asdict() for event in log_events])) if __name__ == '__main__': diff --git a/test/functional/combined_log_template.html b/test/functional/combined_log_template.html index c0b854b080..33c8da2a02 100644 --- a/test/functional/combined_log_template.html +++ b/test/functional/combined_log_template.html @@ -6,25 +6,32 @@ list-style-type: none; font-family: monospace; } + li { border: 1px solid slategray; margin-bottom: 1px; } + li:hover { filter: brightness(85%); } + li.log-test { background-color: cyan; } + li.log-node0 { background-color: lightblue; } + li.log-node1 { background-color: lightgreen; } + li.log-node2 { background-color: lightsalmon; } + li.log-node3 { background-color: lightyellow; } @@ -32,9 +39,9 @@