tool_bitcoin.py
1 #!/usr/bin/env python3 2 # Copyright (c) The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test the bitcoin wrapper tool.""" 6 from test_framework.test_framework import ( 7 BitcoinTestFramework, 8 SkipTest, 9 ) 10 from test_framework.util import ( 11 append_config, 12 assert_equal, 13 ) 14 15 import platform 16 import re 17 18 19 class ToolBitcoinTest(BitcoinTestFramework): 20 def set_test_params(self): 21 self.setup_clean_chain = True 22 self.num_nodes = 1 23 24 def skip_test_if_missing_module(self): 25 # Skip test on windows because currently when `bitcoin node -version` is 26 # run on windows, python doesn't capture output from the child 27 # `bitcoind` and `bitcoin-node` process started with _wexecvp, and 28 # stdout/stderr are always empty. See 29 # https://github.com/bitcoin/bitcoin/pull/33229#issuecomment-3265524908 30 if platform.system() == "Windows": 31 raise SkipTest("Test does not currently work on windows") 32 33 def setup_network(self): 34 """Set up nodes normally, but save a copy of their arguments before starting them.""" 35 self.add_nodes(self.num_nodes, self.extra_args) 36 node_argv = self.get_binaries().node_argv() 37 self.node_options = [node.args[len(node_argv):] for node in self.nodes] 38 assert all(node.args[:len(node_argv)] == node_argv for node in self.nodes) 39 40 def set_cmd_args(self, node, args): 41 """Set up node so it will be started through bitcoin wrapper command with specified arguments.""" 42 # Manually construct the `bitcoin node` command, similar to Binaries::node_argv() 43 bitcoin_cmd = node.binaries.valgrind_cmd + [node.binaries.paths.bitcoin_bin] 44 node.args = bitcoin_cmd + args + ["node"] + self.node_options[node.index] 45 46 def test_args(self, cmd_args, node_args, expect_exe=None, expect_error=None): 47 node = self.nodes[0] 48 self.set_cmd_args(node, cmd_args) 49 extra_args = node_args + ["-version"] 50 if expect_error is not None: 51 node.assert_start_raises_init_error(expected_msg=expect_error, extra_args=extra_args) 52 else: 53 assert expect_exe 54 node.start(extra_args=extra_args) 55 ret, out, err = get_node_output(node) 56 try: 57 assert_equal(get_exe_name(out), expect_exe.encode()) 58 assert_equal(err, b"") 59 except Exception as e: 60 raise RuntimeError(f"Unexpected output from {node.args + extra_args}: {out=!r} {err=!r} {ret=!r}") from e 61 62 def run_test(self): 63 node = self.nodes[0] 64 65 self.log.info("Ensure bitcoin node command invokes bitcoind by default") 66 self.test_args([], [], expect_exe="bitcoind") 67 68 self.log.info("Ensure bitcoin -M invokes bitcoind") 69 self.test_args(["-M"], [], expect_exe="bitcoind") 70 71 self.log.info("Ensure bitcoin -M does not accept -ipcbind") 72 self.test_args(["-M"], ["-ipcbind=unix"], expect_error='Error: Error parsing command line arguments: Invalid parameter -ipcbind=unix') 73 74 if self.is_ipc_compiled(): 75 self.log.info("Ensure bitcoin -m invokes bitcoin-node") 76 self.test_args(["-m"], [], expect_exe="bitcoin-node") 77 78 self.log.info("Ensure bitcoin -m does accept -ipcbind") 79 self.test_args(["-m"], ["-ipcbind=unix"], expect_exe="bitcoin-node") 80 81 self.log.info("Ensure bitcoin accepts -ipcbind by default") 82 self.test_args([], ["-ipcbind=unix"], expect_exe="bitcoin-node") 83 84 self.log.info("Ensure bitcoin recognizes -ipcbind in config file") 85 append_config(node.datadir_path, ["ipcbind=unix"]) 86 self.test_args([], [], expect_exe="bitcoin-node") 87 88 89 def get_node_output(node): 90 ret = node.process.wait(timeout=60) 91 node.stdout.seek(0) 92 node.stderr.seek(0) 93 out = node.stdout.read() 94 err = node.stderr.read() 95 node.stdout.close() 96 node.stderr.close() 97 98 # Clean up TestNode state 99 node.running = False 100 node.process = None 101 node.rpc_connected = False 102 node.rpc = None 103 104 return ret, out, err 105 106 107 def get_exe_name(version_str): 108 """Get exe name from last word of first line of version string.""" 109 return re.match(rb".*?(\S+)\s*?(?:\n|$)", version_str.strip()).group(1) 110 111 112 if __name__ == '__main__': 113 ToolBitcoinTest(__file__).main()