tool_bitcoin.py raw
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()
115