From 324302d27b2d818c65c89267104b8719bdf6b489 Mon Sep 17 00:00:00 2001
From: Matt Whitlock <c-lightning@mattwhitlock.name>
Date: Sat, 23 Aug 2025 02:24:25 -0400
Subject: [PATCH] tests: work around socket path name too long on Linux

When running the integration test suite in a deeply nested directory
tree, the path name of the Unix domain socket might be longer than can
fit in a struct sockaddr_un. On Linux, we can use the /proc/self/cwd
trick to shorten the path name.

Changelog-Fixed: Integration tests no longer fail when run in a deeply nested directory on Linux.
---
 tests/fixtures.py    |  5 +++++
 tests/test_cln_rs.py |  2 ++
 tests/test_misc.py   | 29 ++++++++++++++++++++---------
 3 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/tests/fixtures.py b/tests/fixtures.py
index 6cc91c12ffef20ef2cf69c582a9ea2ea3e4f3240..ec937b6840076a1b538a93981f8d4ec9eae95cc4 100644
--- a/tests/fixtures.py
+++ b/tests/fixtures.py
@@ -21,6 +21,11 @@ def __init__(self, *args, **kwargs):
         kwargs["executable"] = "lightningd/lightningd"
         utils.LightningNode.__init__(self, *args, **kwargs)
 
+        # Avoid socket path name too long on Linux
+        if os.uname()[0] == 'Linux' and \
+                len(str(self.lightning_dir / TEST_NETWORK / 'lightning-rpc')) >= 108:
+            self.daemon.opts['rpc-file'] = '/proc/self/cwd/lightning-rpc'
+
         # This is a recent innovation, and we don't want to nail pyln-testing to this version.
         self.daemon.opts['dev-crash-after'] = 3600
 
diff --git a/tests/test_cln_rs.py b/tests/test_cln_rs.py
index 6363e78304582b3415239af85c5aaea9d0419472..d8dd5717fd9581e6177105bbecad7a278b323618 100644
--- a/tests/test_cln_rs.py
+++ b/tests/test_cln_rs.py
@@ -27,6 +27,8 @@ def test_rpc_client(node_factory):
     l1 = node_factory.get_node()
     bin_path = Path.cwd() / "target" / RUST_PROFILE / "examples" / "cln-rpc-getinfo"
     rpc_path = Path(l1.daemon.lightning_dir) / TEST_NETWORK / "lightning-rpc"
+    if len(str(rpc_path)) >= 108 and os.uname()[0] == 'Linux':
+        rpc_path = Path('/proc/self/cwd') / os.path.relpath(rpc_path)
     out = subprocess.check_output([bin_path, rpc_path], stderr=subprocess.STDOUT)
     assert(b'0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518' in out)
 
diff --git a/tests/test_misc.py b/tests/test_misc.py
index 5832787aff204e600754a88b3b2d5d26a5e33128..59217b8641db241b6c5a0aeb6298b1bbf6b5a133 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -818,7 +818,12 @@ def test_address(node_factory):
 
     # Now test UNIX domain binding
     l1.stop()
-    l1.daemon.opts['bind-addr'] = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "sock")
+    bind_addr = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "sock")
+    if len(bind_addr) >= 108 and os.uname()[0] == "Linux":
+        bind_addr = os.path.join('/proc/self/cwd',
+                os.path.relpath(node_factory.directory, os.path.dirname(bind_addr)),
+                os.path.relpath(bind_addr, node_factory.directory))
+    l1.daemon.opts['bind-addr'] = bind_addr
     l1.start()
 
     # Test dev-allow-localhost
@@ -874,12 +879,21 @@ def test_listconfigs_plugins(node_factory, bitcoind, chainparams):
     assert [p['active'] for p in plugins if p['name'].endswith('offers')] == [True]
 
 
+def connect_unix(socket_path: str):
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    try:
+        sock.connect(socket_path)
+    except OSError as err:
+        if err.args[0] == 'AF_UNIX path too long' and os.uname()[0] == 'Linux':
+            sock.connect(os.path.join('/proc/self/cwd', os.path.relpath(socket_path)))
+    return sock
+
+
 def test_multirpc(node_factory):
     """Test that we can do multiple RPC without waiting for response"""
     l1 = node_factory.get_node()
 
-    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-    sock.connect(l1.rpc.socket_path)
+    sock = connect_unix(l1.rpc.socket_path)
 
     commands = [
         b'{"id":1,"jsonrpc":"2.0","method":"listpeers","params":[]}',
@@ -905,8 +919,7 @@ def test_multiplexed_rpc(node_factory):
     """Test that we can do multiple RPCs which exit in different orders"""
     l1 = node_factory.get_node()
 
-    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-    sock.connect(l1.rpc.socket_path)
+    sock = connect_unix(l1.rpc.socket_path)
 
     # Neighbouring ones may be in or out of order.
     commands = [
@@ -936,8 +949,7 @@ def test_malformed_rpc(node_factory):
     """Test that we get a correct response to malformed RPC commands"""
     l1 = node_factory.get_node()
 
-    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-    sock.connect(l1.rpc.socket_path)
+    sock = connect_unix(l1.rpc.socket_path)
 
     # No ID
     sock.sendall(b'{"jsonrpc":"2.0","method":"getinfo","params":[]}')
@@ -2023,8 +2035,7 @@ def test_check_command(node_factory):
                      host='x', port="abcd")
 
     # FIXME: python wrapper doesn't let us test array params.
-    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-    sock.connect(l1.rpc.socket_path)
+    sock = connect_unix(l1.rpc.socket_path)
 
     sock.sendall(b'{"id":1, "jsonrpc":"2.0","method":"check","params":["help"]}')
     obj, _ = l1.rpc._readobj(sock, b'')
