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 for node in self.nodes: 39 assert_equal(node.args[:len(node_argv)], node_argv) 40 41 def set_cmd_args(self, node, args): 42 """Set up node so it will be started through bitcoin wrapper command with specified arguments.""" 43 # Manually construct the `bitcoin node` command, similar to Binaries::node_argv() 44 bitcoin_cmd = node.binaries.valgrind_cmd + [node.binaries.paths.bitcoin_bin] 45 node.args = bitcoin_cmd + args + ["node"] + self.node_options[node.index] 46 47 def test_args(self, cmd_args, node_args, expect_exe=None, expect_error=None): 48 node = self.nodes[0] 49 self.set_cmd_args(node, cmd_args) 50 extra_args = node_args + ["-version"] 51 if expect_error is not None: 52 node.assert_start_raises_init_error(expected_msg=expect_error, extra_args=extra_args) 53 else: 54 assert expect_exe 55 node.start(extra_args=extra_args) 56 ret, out, err = get_node_output(node) 57 try: 58 assert_equal(get_exe_name(out), expect_exe.encode()) 59 assert_equal(err, b"") 60 except Exception as e: 61 raise RuntimeError(f"Unexpected output from {node.args + extra_args}: {out=!r} {err=!r} {ret=!r}") from e 62 63 def run_test(self): 64 node = self.nodes[0] 65 66 self.log.info("Ensure bitcoin node command invokes bitcoind by default") 67 self.test_args([], [], expect_exe="bitcoind") 68 69 self.log.info("Ensure bitcoin -M invokes bitcoind") 70 self.test_args(["-M"], [], expect_exe="bitcoind") 71 72 self.log.info("Ensure bitcoin -M does not accept -ipcbind") 73 self.test_args(["-M"], ["-ipcbind=unix"], expect_error='Error: Error parsing command line arguments: Invalid parameter -ipcbind=unix') 74 75 if self.is_ipc_compiled(): 76 self.log.info("Ensure bitcoin -m invokes bitcoin-node") 77 self.test_args(["-m"], [], expect_exe="bitcoin-node") 78 79 self.log.info("Ensure bitcoin -m does accept -ipcbind") 80 self.test_args(["-m"], ["-ipcbind=unix"], expect_exe="bitcoin-node") 81 82 self.log.info("Ensure bitcoin accepts -ipcbind by default") 83 self.test_args([], ["-ipcbind=unix"], expect_exe="bitcoin-node") 84 85 self.log.info("Ensure bitcoin recognizes -ipcbind in config file") 86 append_config(node.datadir_path, ["ipcbind=unix"]) 87 self.test_args([], [], expect_exe="bitcoin-node") 88 89 90 def get_node_output(node): 91 ret = node.process.wait(timeout=60) 92 node.stdout.seek(0) 93 node.stderr.seek(0) 94 out = node.stdout.read() 95 err = node.stderr.read() 96 node.stdout.close() 97 node.stderr.close() 98 99 # Clean up TestNode state 100 node.running = False 101 node.process = None 102 node.rpc_connected = False 103 node.rpc = None 104 105 return ret, out, err 106 107 108 def get_exe_name(version_str): 109 """Get exe name from last word of first line of version string.""" 110 return re.match(rb".*?(\S+)\s*?(?:\n|$)", version_str.strip()).group(1) 111 112 113 if __name__ == '__main__': 114 ToolBitcoinTest(__file__).main()