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