diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/functional/rpc_net.py | 55 | ||||
-rwxr-xr-x | test/fuzz/test_runner.py | 72 |
2 files changed, 98 insertions, 29 deletions
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 068a76f36b..d4cfb48881 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -8,6 +8,8 @@ Tests correspond to code in rpc/net.cpp. """ from decimal import Decimal +from itertools import product +import time from test_framework.p2p import P2PInterface import test_framework.messages @@ -17,6 +19,7 @@ from test_framework.messages import ( ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( + assert_approx, assert_equal, assert_greater_than_or_equal, assert_greater_than, @@ -48,25 +51,27 @@ class NetTest(BitcoinTestFramework): self.supports_cli = False def run_test(self): - self.log.info('Get out of IBD for the minfeefilter test') - self.nodes[0].generate(1) - self.log.info('Connect nodes both way') + # Get out of IBD for the minfeefilter and getpeerinfo tests. + self.nodes[0].generate(101) + # Connect nodes both ways. connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 0) - self._test_connection_count() - self._test_getnettotals() - self._test_getnetworkinfo() - self._test_getaddednodeinfo() - self._test_getpeerinfo() + self.test_connection_count() + self.test_getpeerinfo() + self.test_getnettotals() + self.test_getnetworkinfo() + self.test_getaddednodeinfo() self.test_service_flags() - self._test_getnodeaddresses() + self.test_getnodeaddresses() - def _test_connection_count(self): - # connect_nodes connects each node to the other + def test_connection_count(self): + self.log.info("Test getconnectioncount") + # After using `connect_nodes` to connect nodes 0 and 1 to each other. assert_equal(self.nodes[0].getconnectioncount(), 2) - def _test_getnettotals(self): + def test_getnettotals(self): + self.log.info("Test getnettotals") # getnettotals totalbytesrecv and totalbytessent should be # consistent with getpeerinfo. Since the RPC calls are not atomic, # and messages might have been recvd or sent between RPC calls, call @@ -96,7 +101,8 @@ class NetTest(BitcoinTestFramework): assert_greater_than_or_equal(after['bytesrecv_per_msg'].get('pong', 0), before['bytesrecv_per_msg'].get('pong', 0) + 32) assert_greater_than_or_equal(after['bytessent_per_msg'].get('ping', 0), before['bytessent_per_msg'].get('ping', 0) + 32) - def _test_getnetworkinfo(self): + def test_getnetworkinfo(self): + self.log.info("Test getnetworkinfo") assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) @@ -108,7 +114,7 @@ class NetTest(BitcoinTestFramework): with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']): self.nodes[0].setnetworkactive(state=True) - self.log.info('Connect nodes both way') + # Connect nodes both ways. connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 0) @@ -120,7 +126,8 @@ class NetTest(BitcoinTestFramework): for info in network_info: assert_net_servicesnames(int(info["localservices"], 0x10), info["localservicesnames"]) - def _test_getaddednodeinfo(self): + def test_getaddednodeinfo(self): + self.log.info("Test getaddednodeinfo") assert_equal(self.nodes[0].getaddednodeinfo(), []) # add a node (node2) to node0 ip_port = "127.0.0.1:{}".format(p2p_port(2)) @@ -139,8 +146,20 @@ class NetTest(BitcoinTestFramework): # check that a non-existent node returns an error assert_raises_rpc_error(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1') - def _test_getpeerinfo(self): + def test_getpeerinfo(self): + self.log.info("Test getpeerinfo") + # Create a few getpeerinfo last_block/last_transaction values. + if self.is_wallet_compiled(): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) + self.nodes[1].generate(1) + self.sync_all() + time_now = int(time.time()) peer_info = [x.getpeerinfo() for x in self.nodes] + # Verify last_block and last_transaction keys/values. + for node, peer, field in product(range(self.num_nodes), range(2), ['last_block', 'last_transaction']): + assert field in peer_info[node][peer].keys() + if peer_info[node][peer][field] != 0: + assert_approx(peer_info[node][peer][field], time_now, vspan=60) # check both sides of bidirectional connection between nodes # the address bound to on one side will be the source address for the other node assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr']) @@ -152,11 +171,13 @@ class NetTest(BitcoinTestFramework): assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"]) def test_service_flags(self): + self.log.info("Test service flags") self.nodes[0].add_p2p_connection(P2PInterface(), services=(1 << 4) | (1 << 63)) assert_equal(['UNKNOWN[2^4]', 'UNKNOWN[2^63]'], self.nodes[0].getpeerinfo()[-1]['servicesnames']) self.nodes[0].disconnect_p2ps() - def _test_getnodeaddresses(self): + def test_getnodeaddresses(self): + self.log.info("Test getnodeaddresses") self.nodes[0].add_p2p_connection(P2PInterface()) # Add some addresses to the Address Manager over RPC. Due to the way diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 56b18752ec..c7895edbcc 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -56,6 +56,14 @@ def main(): '--m_dir', help='Merge inputs from this directory into the seed_dir. Needs /target subdirectory.', ) + parser.add_argument( + '-g', + '--generate', + action='store_true', + help='Create new corpus seeds (or extend the existing ones) by running' + ' the given targets for a finite number of times. Outputs them to' + ' the passed seed_dir.' + ) args = parser.parse_args() @@ -100,19 +108,20 @@ def main(): logging.info("{} of {} detected fuzz target(s) selected: {}".format(len(test_list_selection), len(test_list_all), " ".join(test_list_selection))) - test_list_seedless = [] - for t in test_list_selection: - corpus_path = os.path.join(args.seed_dir, t) - if not os.path.exists(corpus_path) or len(os.listdir(corpus_path)) == 0: - test_list_seedless.append(t) - test_list_seedless.sort() - if test_list_seedless: - logging.info( - "Fuzzing harnesses lacking a seed corpus: {}".format( - " ".join(test_list_seedless) + if not args.generate: + test_list_seedless = [] + for t in test_list_selection: + corpus_path = os.path.join(args.seed_dir, t) + if not os.path.exists(corpus_path) or len(os.listdir(corpus_path)) == 0: + test_list_seedless.append(t) + test_list_seedless.sort() + if test_list_seedless: + logging.info( + "Fuzzing harnesses lacking a seed corpus: {}".format( + " ".join(test_list_seedless) + ) ) - ) - logging.info("Please consider adding a fuzz seed corpus at https://github.com/bitcoin-core/qa-assets") + logging.info("Please consider adding a fuzz seed corpus at https://github.com/bitcoin-core/qa-assets") try: help_output = subprocess.run( @@ -133,6 +142,14 @@ def main(): sys.exit(1) with ThreadPoolExecutor(max_workers=args.par) as fuzz_pool: + if args.generate: + return generate_corpus_seeds( + fuzz_pool=fuzz_pool, + build_dir=config["environment"]["BUILDDIR"], + seed_dir=args.seed_dir, + targets=test_list_selection, + ) + if args.m_dir: merge_inputs( fuzz_pool=fuzz_pool, @@ -152,6 +169,37 @@ def main(): ) +def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets): + """Generates new corpus seeds. + + Run {targets} without input, and outputs the generated corpus seeds to + {seed_dir}. + """ + logging.info("Generating corpus seeds to {}".format(seed_dir)) + + def job(command): + logging.debug("Running '{}'\n".format(" ".join(command))) + logging.debug("Command '{}' output:\n'{}'\n".format( + ' '.join(command), + subprocess.run(command, check=True, stderr=subprocess.PIPE, + universal_newlines=True).stderr + )) + + futures = [] + for target in targets: + target_seed_dir = os.path.join(seed_dir, target) + os.makedirs(target_seed_dir, exist_ok=True) + command = [ + os.path.join(build_dir, "src", "test", "fuzz", target), + "-runs=100000", + target_seed_dir, + ] + futures.append(fuzz_pool.submit(job, command)) + + for future in as_completed(futures): + future.result() + + def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir): logging.info("Merge the inputs in the passed dir into the seed_dir. Passed dir {}".format(merge_dir)) jobs = [] |