Merge bitcoin/bitcoin#33633: test: [move-only] binary utils to utils.py

fa75ef4328 test: Move export_env_build_path to util.py (MarcoFalke)
fa9f495308 test: Move get_binary_paths and Binaries to util.py (MarcoFalke)

Pull request description:

  Having the binary related utils sit in the test_framework.py is fine. However, they are mostly stand-alone utils, which may be used externally.

  So move them to utils.py, to allow easier external use. The diff is trivial and can be reviewed via the git options `--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space`.

ACKs for top commit:
  kevkevinpal:
    ACK [fa75ef4](https://github.com/bitcoin/bitcoin/pull/33633/commits/fa75ef4328f638221bcf85fcbefa885122084622)
  Sjors:
    lgtm ACK fa75ef4328
  yuvicc:
    Code review ACK fa75ef4328
  janb84:
    ACK fa75ef4328
  musaHaruna:
    Code Review ACK [fa75ef4](https://github.com/bitcoin/bitcoin/pull/33633/commits/fa75ef4328f638221bcf85fcbefa885122084622)
  enirox001:
    ACK [fa75ef4](https://github.com/bitcoin/bitcoin/commit/fa75ef4328f638221bcf85fcbefa885122084622)

Tree-SHA512: f382118484cb5495e8888214437e72c81727d54f97b3c09dfd996faab6cb6643c4c2d816b89ab82de73fc091c36ed7b8744c7d34a443b6adc415eb06697ef6ea
This commit is contained in:
merge-script committed 2025-10-21 08:39:22 +01:00
commit 689ec28d1d
2 files changed
+99 -92

No files matched your search

@@ -14,13 +14,11 @@ import platform
import pdb import pdb
import random import random
import re import re
import shlex
import shutil import shutil
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import time import time
import types
from .address import create_deterministic_address_bcrt1_p2tr_op_true from .address import create_deterministic_address_bcrt1_p2tr_op_true
from .authproxy import JSONRPCException from .authproxy import JSONRPCException
@@ -28,11 +26,14 @@ from . import coverage
from .p2p import NetworkThread from .p2p import NetworkThread
from .test_node import TestNode from .test_node import TestNode
from .util import ( from .util import (
Binaries,
MAX_NODES, MAX_NODES,
PortSeed, PortSeed,
assert_equal, assert_equal,
check_json_precision, check_json_precision,
export_env_build_path,
find_vout_for_address, find_vout_for_address,
get_binary_paths,
get_datadir_path, get_datadir_path,
initialize_datadir, initialize_datadir,
p2p_port, p2p_port,
@@ -60,63 +61,6 @@ class SkipTest(Exception):
self.message = message self.message = message
class Binaries:
"""Helper class to provide information about bitcoin binaries
Attributes:
paths: Object returned from get_binary_paths() containing information
which binaries and command lines to use from environment variables and
the config file.
bin_dir: An optional string containing a directory path to look for
binaries, which takes precedence over the paths above, if specified.
This is used by tests calling binaries from previous releases.
"""
def __init__(self, paths, bin_dir):
self.paths = paths
self.bin_dir = bin_dir
def node_argv(self, **kwargs):
"Return argv array that should be used to invoke bitcoind"
return self._argv("node", self.paths.bitcoind, **kwargs)
def rpc_argv(self):
"Return argv array that should be used to invoke bitcoin-cli"
# Add -nonamed because "bitcoin rpc" enables -named by default, but bitcoin-cli doesn't
return self._argv("rpc", self.paths.bitcoincli) + ["-nonamed"]
def tx_argv(self):
"Return argv array that should be used to invoke bitcoin-tx"
return self._argv("tx", self.paths.bitcointx)
def util_argv(self):
"Return argv array that should be used to invoke bitcoin-util"
return self._argv("util", self.paths.bitcoinutil)
def wallet_argv(self):
"Return argv array that should be used to invoke bitcoin-wallet"
return self._argv("wallet", self.paths.bitcoinwallet)
def chainstate_argv(self):
"Return argv array that should be used to invoke bitcoin-chainstate"
return self._argv("chainstate", self.paths.bitcoinchainstate)
def _argv(self, command, bin_path, need_ipc=False):
"""Return argv array that should be used to invoke the command. It
either uses the bitcoin wrapper executable (if BITCOIN_CMD is set or
need_ipc is True), or the direct binary path (bitcoind, etc). When
bin_dir is set (by tests calling binaries from previous releases) it
always uses the direct path."""
if self.bin_dir is not None:
return [os.path.join(self.bin_dir, os.path.basename(bin_path))]
elif self.paths.bitcoin_cmd is not None or need_ipc:
# If the current test needs IPC functionality, use the bitcoin
# wrapper binary and append -m so it calls multiprocess binaries.
bitcoin_cmd = self.paths.bitcoin_cmd or [self.paths.bitcoin_bin]
return bitcoin_cmd + (["-m"] if need_ipc else []) + [command]
else:
return [bin_path]
class BitcoinTestMetaClass(type): class BitcoinTestMetaClass(type):
"""Metaclass for BitcoinTestFramework. """Metaclass for BitcoinTestFramework.
@@ -270,39 +214,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.config = configparser.ConfigParser() self.config = configparser.ConfigParser()
self.config.read_file(open(self.options.configfile)) self.config.read_file(open(self.options.configfile))
self.binary_paths = self.get_binary_paths() self.binary_paths = get_binary_paths(self.config)
if self.options.v1transport: if self.options.v1transport:
self.options.v2transport=False self.options.v2transport=False
PortSeed.n = self.options.port_seed PortSeed.n = self.options.port_seed
def get_binary_paths(self):
"""Get paths of all binaries from environment variables or their default values"""
paths = types.SimpleNamespace()
binaries = {
"bitcoin": "BITCOIN_BIN",
"bitcoind": "BITCOIND",
"bitcoin-cli": "BITCOINCLI",
"bitcoin-util": "BITCOINUTIL",
"bitcoin-tx": "BITCOINTX",
"bitcoin-chainstate": "BITCOINCHAINSTATE",
"bitcoin-wallet": "BITCOINWALLET",
}
# Set paths to bitcoin core binaries allowing overrides with environment
# variables.
for binary, env_variable_name in binaries.items():
default_filename = os.path.join(
self.config["environment"]["BUILDDIR"],
"bin",
binary + self.config["environment"]["EXEEXT"],
)
setattr(paths, env_variable_name.lower(), os.getenv(env_variable_name, default=default_filename))
# BITCOIN_CMD environment variable can be specified to invoke bitcoin
# wrapper binary instead of other executables.
paths.bitcoin_cmd = shlex.split(os.getenv("BITCOIN_CMD", "")) or None
return paths
def get_binaries(self, bin_dir=None): def get_binaries(self, bin_dir=None):
return Binaries(self.binary_paths, bin_dir) return Binaries(self.binary_paths, bin_dir)
@@ -310,14 +227,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""Call this method to start up the test framework object with options set.""" """Call this method to start up the test framework object with options set."""
check_json_precision() check_json_precision()
export_env_build_path(self.config)
self.options.cachedir = os.path.abspath(self.options.cachedir) self.options.cachedir = os.path.abspath(self.options.cachedir)
os.environ['PATH'] = os.pathsep.join([
os.path.join(self.config["environment"]["BUILDDIR"], "bin"),
os.environ['PATH']
])
# Set up temp directory and start logging # Set up temp directory and start logging
if self.options.tmpdir: if self.options.tmpdir:
self.options.tmpdir = os.path.abspath(self.options.tmpdir) self.options.tmpdir = os.path.abspath(self.options.tmpdir)
+94
View File
@@ -16,7 +16,9 @@ import pathlib
import platform import platform
import random import random
import re import re
import shlex
import time import time
import types
from . import coverage from . import coverage
from .authproxy import AuthServiceProxy, JSONRPCException from .authproxy import AuthServiceProxy, JSONRPCException
@@ -235,6 +237,98 @@ def check_json_precision():
raise RuntimeError("JSON encode/decode loses precision") raise RuntimeError("JSON encode/decode loses precision")
class Binaries:
"""Helper class to provide information about bitcoin binaries
Attributes:
paths: Object returned from get_binary_paths() containing information
which binaries and command lines to use from environment variables and
the config file.
bin_dir: An optional string containing a directory path to look for
binaries, which takes precedence over the paths above, if specified.
This is used by tests calling binaries from previous releases.
"""
def __init__(self, paths, bin_dir):
self.paths = paths
self.bin_dir = bin_dir
def node_argv(self, **kwargs):
"Return argv array that should be used to invoke bitcoind"
return self._argv("node", self.paths.bitcoind, **kwargs)
def rpc_argv(self):
"Return argv array that should be used to invoke bitcoin-cli"
# Add -nonamed because "bitcoin rpc" enables -named by default, but bitcoin-cli doesn't
return self._argv("rpc", self.paths.bitcoincli) + ["-nonamed"]
def tx_argv(self):
"Return argv array that should be used to invoke bitcoin-tx"
return self._argv("tx", self.paths.bitcointx)
def util_argv(self):
"Return argv array that should be used to invoke bitcoin-util"
return self._argv("util", self.paths.bitcoinutil)
def wallet_argv(self):
"Return argv array that should be used to invoke bitcoin-wallet"
return self._argv("wallet", self.paths.bitcoinwallet)
def chainstate_argv(self):
"Return argv array that should be used to invoke bitcoin-chainstate"
return self._argv("chainstate", self.paths.bitcoinchainstate)
def _argv(self, command, bin_path, need_ipc=False):
"""Return argv array that should be used to invoke the command. It
either uses the bitcoin wrapper executable (if BITCOIN_CMD is set or
need_ipc is True), or the direct binary path (bitcoind, etc). When
bin_dir is set (by tests calling binaries from previous releases) it
always uses the direct path."""
if self.bin_dir is not None:
return [os.path.join(self.bin_dir, os.path.basename(bin_path))]
elif self.paths.bitcoin_cmd is not None or need_ipc:
# If the current test needs IPC functionality, use the bitcoin
# wrapper binary and append -m so it calls multiprocess binaries.
bitcoin_cmd = self.paths.bitcoin_cmd or [self.paths.bitcoin_bin]
return bitcoin_cmd + (["-m"] if need_ipc else []) + [command]
else:
return [bin_path]
def get_binary_paths(config):
"""Get paths of all binaries from environment variables or their default values"""
paths = types.SimpleNamespace()
binaries = {
"bitcoin": "BITCOIN_BIN",
"bitcoind": "BITCOIND",
"bitcoin-cli": "BITCOINCLI",
"bitcoin-util": "BITCOINUTIL",
"bitcoin-tx": "BITCOINTX",
"bitcoin-chainstate": "BITCOINCHAINSTATE",
"bitcoin-wallet": "BITCOINWALLET",
}
# Set paths to bitcoin core binaries allowing overrides with environment
# variables.
for binary, env_variable_name in binaries.items():
default_filename = os.path.join(
config["environment"]["BUILDDIR"],
"bin",
binary + config["environment"]["EXEEXT"],
)
setattr(paths, env_variable_name.lower(), os.getenv(env_variable_name, default=default_filename))
# BITCOIN_CMD environment variable can be specified to invoke bitcoin
# wrapper binary instead of other executables.
paths.bitcoin_cmd = shlex.split(os.getenv("BITCOIN_CMD", "")) or None
return paths
def export_env_build_path(config):
os.environ["PATH"] = os.pathsep.join([
os.path.join(config["environment"]["BUILDDIR"], "bin"),
os.environ["PATH"],
])
def count_bytes(hex_string): def count_bytes(hex_string):
return len(bytearray.fromhex(hex_string)) return len(bytearray.fromhex(hex_string))