From 8a982eea85406a85dc53d864409c4dc143a1c55a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 27 Jun 2026 09:54:38 +0100 Subject: [PATCH 1/7] qa: Add `skip_if_no_lsof_on_nonlinux` helper and use it where needed Some functional tests on non-Linux platforms rely on the `lsof` utility. However, we treat all other functional test dependencies, such as additional Python modules, as optional, and skip dependent tests if those are unavailable. This change makes `lsof` optional as well. --- test/functional/feature_bind_extra.py | 1 + test/functional/rpc_bind.py | 1 + test/functional/test_framework/test_framework.py | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py index 91f846d6f69..2b81e9210e0 100755 --- a/test/functional/feature_bind_extra.py +++ b/test/functional/feature_bind_extra.py @@ -33,6 +33,7 @@ class BindExtraTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_platform_not_posix() + self.skip_if_no_lsof_on_nonlinux() def setup_network(self): loopback_ipv4 = addr_to_hex("127.0.0.1") diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py index 517df5d9c3f..3caf23dd118 100755 --- a/test/functional/rpc_bind.py +++ b/test/functional/rpc_bind.py @@ -17,6 +17,7 @@ class RPCBindTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_platform_not_posix() + self.skip_if_no_lsof_on_nonlinux() def setup_network(self): self.add_nodes(self.num_nodes, None) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 64dcbfd7ec5..a145614b860 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1027,6 +1027,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): if platform.system() != "Linux": raise SkipTest("not on a Linux system") + def skip_if_no_lsof_on_nonlinux(self): + """Skip the running test if the lsof utility is not available on non-Linux platforms.""" + if sys.platform != "linux" and shutil.which("lsof") is None: + raise SkipTest("lsof not available") + def skip_if_platform_not_posix(self): """Skip the running test if we are not on a POSIX platform""" if os.name != 'posix': From 4cb7f39c2ceb9a27950eb4e9d02874905d11a46c Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:33:51 +0100 Subject: [PATCH 2/7] qa: Drop OpenBSD from supported platforms in `get_bind_addrs` function --- test/functional/test_framework/netutil.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index 85209322196..034d0ff3d34 100644 --- a/test/functional/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py @@ -95,7 +95,8 @@ def get_bind_addrs(pid): if conn[3] == STATE_LISTEN and conn[4] in inodes: bind_addrs.append(conn[1]) return bind_addrs - elif sys.platform.startswith(("darwin", "freebsd", "netbsd", "openbsd")): + # OpenBSD is not included, as it does not ship the lsof utility. + elif sys.platform.startswith(("darwin", "freebsd", "netbsd")): import re import subprocess output = subprocess.check_output(["lsof", From 1c1735567e2a030ebf7e6a0b49b1db0ad18f2f44 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:36:32 +0100 Subject: [PATCH 3/7] doc: Add `lsof` to Test Suite Dependencies on FreeBSD --- doc/build-freebsd.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index 436b57c99d6..a7045bae7c1 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -74,7 +74,7 @@ There is an included test suite that is useful for testing code changes when dev To run the test suite (recommended), you will need to have Python 3 installed: ```bash -pkg install python3 databases/py-sqlite3 net/py-pyzmq +pkg install python3 databases/py-sqlite3 net/py-pyzmq lsof ``` --- From 70352fda038545f46641dc75c89b3aa6523b39dd Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:37:46 +0100 Subject: [PATCH 4/7] qa: Strip prefix length from NetBSD `ifconfig` output Modern NetBSD `ifconfig` prints interface addresses in CIDR notation (e.g. `inet 127.0.0.1/8`), unlike the other supported platforms which print the netmask as a separate field. The trailing prefix length breaks functional tests that expect a plain IP address. This change is a no-op on other platforms. --- test/functional/test_framework/netutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index 034d0ff3d34..2cbcc7a0b4a 100644 --- a/test/functional/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py @@ -149,7 +149,7 @@ def all_interfaces(): return [ (m["iface"].encode(), ip) for m in re.finditer(r"(?m)^(?P\S+):(?P[^\n]*(?:\n[ \t]+[^\n]*)*)", output) - for ip in re.findall(r"inet (\S+)", m["block"]) + for ip in re.findall(r"inet ([^\s/]+)", m["block"]) ] else: raise NotImplementedError(f"all_interfaces is not supported on {sys.platform}") From 5d01aa4772a446d28dd914dd099bd0440f10a2dd Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:57:05 +0100 Subject: [PATCH 5/7] qa: Ignore `lsof` warnings on NetBSD On NetBSD, `lsof` can produce the following warnings: 1. "created device cache file: ..." - usually happens in a CI environment. 2. "compiled for NetBSD release 10.0; this is 10.1." or similar - when the `lsof` binary package is installed on a point release. This change suppresses both warnings printed to stderr and fixes the affected tests. --- test/functional/test_framework/netutil.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index 2cbcc7a0b4a..748fb0491af 100644 --- a/test/functional/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py @@ -100,7 +100,8 @@ def get_bind_addrs(pid): import re import subprocess output = subprocess.check_output(["lsof", - *(["-Di"] if sys.platform.startswith("freebsd") else []), # Ignore device cache to avoid stderr warnings. + *(["-Di"] if sys.platform.startswith(("freebsd", "netbsd")) else []), # Ignore device cache to avoid stderr warnings. + *(["-w"] if sys.platform.startswith("netbsd") else []), # Ignore point release mismatch warnings. "-nP", # Keep hosts and ports numeric. "-a", # Require all filters to match. "-p", str(pid), # Limit results to the target pid. From 5e96a8fd5acf778290f84985d25c66b87b70675a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:19:17 +0100 Subject: [PATCH 6/7] doc: Add `lsof` to Test Suite Dependencies on NetBSD --- doc/build-netbsd.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index c269d2a18da..b3da96175b1 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -93,7 +93,14 @@ There is an included test suite that is useful for testing code changes when dev To run the test suite (recommended), you will need to have Python 3 installed: ```bash -pkgin install python313 py313-zmq +pkgin install python313 py313-zmq lsof +``` + +When the `lsof` binary package was built for a different point release, it might be necessary to force its installation as follows: + +```bash +echo "CHECK_OSABI=no" >> /etc/pkg_install.conf +pkgin install lsof ``` ## Building Bitcoin Core From f4a6d079c42bb921dd753fab44ec7c819a9f2307 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:20:12 +0100 Subject: [PATCH 7/7] qa: Support `get_bind_addrs` and `feature_bind_extra` on illumos This extends support for `get_bind_addrs` and `feature_bind_extra` to illumos-based OSes. --- test/functional/test_framework/netutil.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index 748fb0491af..352efac852c 100644 --- a/test/functional/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py @@ -2,7 +2,7 @@ # Copyright (c) 2014-present The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Linux, macOS, and BSD network utilities. +"""Linux, macOS, BSD and illumos network utilities. Roughly based on https://web.archive.org/web/20190424172231/http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal """ @@ -96,11 +96,11 @@ def get_bind_addrs(pid): bind_addrs.append(conn[1]) return bind_addrs # OpenBSD is not included, as it does not ship the lsof utility. - elif sys.platform.startswith(("darwin", "freebsd", "netbsd")): + elif sys.platform.startswith(("darwin", "freebsd", "netbsd", "sunos5")): import re import subprocess output = subprocess.check_output(["lsof", - *(["-Di"] if sys.platform.startswith(("freebsd", "netbsd")) else []), # Ignore device cache to avoid stderr warnings. + *(["-Di"] if sys.platform.startswith(("freebsd", "netbsd", "sunos5")) else []), # Ignore device cache to avoid stderr warnings. *(["-w"] if sys.platform.startswith("netbsd") else []), # Ignore point release mismatch warnings. "-nP", # Keep hosts and ports numeric. "-a", # Require all filters to match. @@ -143,7 +143,7 @@ def all_interfaces(): return [(namestr[i:i+16].split(b'\0', 1)[0], socket.inet_ntoa(namestr[i+20:i+24])) for i in range(0, outbytes, struct_size)] - elif sys.platform.startswith(("darwin", "freebsd", "netbsd", "openbsd")): + elif sys.platform.startswith(("darwin", "freebsd", "netbsd", "openbsd", "sunos5")): import re import subprocess output = subprocess.check_output(["ifconfig", "-au"], text=True)