From 8b68287bf9a50016519f7eba9d1a9186b94db516 Mon Sep 17 00:00:00 2001 From: David Gumberg Date: Wed, 15 Apr 2026 10:54:34 -0700 Subject: [PATCH] test: Make torcontrol max line length test stricter and test boundaries. Adds a check that at the boundary of MAX_LINE_LENGTH, no disconnect occurs. Also makes the overlength test message exactly MAX_LINE_LENGTH + 1 to test the boundary. Drops the redundant node liveness check, which is covered by the later check that the node reconnects. --- test/functional/feature_torcontrol.py | 35 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/test/functional/feature_torcontrol.py b/test/functional/feature_torcontrol.py index 5f8cf9f68ee..9693030b8ac 100755 --- a/test/functional/feature_torcontrol.py +++ b/test/functional/feature_torcontrol.py @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test torcontrol functionality with a mock Tor control server.""" +from contextlib import contextmanager import socket import threading from test_framework.test_framework import BitcoinTestFramework @@ -124,6 +125,20 @@ class TorControlTest(BitcoinTestFramework): self.wait_until(lambda: len(mock_tor.received_commands) >= 1, timeout=10) assert_equal(mock_tor.received_commands[0], "PROTOCOLINFO 1") + @contextmanager + def expect_disconnect(self, expect, mock_tor): + initial_len = len(mock_tor.received_commands) + yield + + if expect: + # Expect to receive a PROTOCOLINFO 1 on reconnect, bumping the received + # commands length. + self.wait_until(lambda: len(mock_tor.received_commands) == initial_len + 1) + assert_equal(mock_tor.received_commands[initial_len], "PROTOCOLINFO 1") + else: + # No disconnect, so no reconnect message + ensure_for(duration=2, f=lambda: len(mock_tor.received_commands) == initial_len) + def test_basic(self): self.log.info("Test Tor control basic functionality") @@ -202,19 +217,23 @@ class TorControlTest(BitcoinTestFramework): mock_tor.stop() def test_oversized_line(self): - self.log.info("Test that Tor control disconnects on oversized response lines") - mock_tor = MockTorControlServer(self.next_port(), manual_mode=True) self.restart_with_mock(mock_tor) - # Send a single line longer than MAX_LINE_LENGTH. The node should disconnect. MAX_LINE_LENGTH = 100000 - mock_tor.send_raw("250-" + ("A" * (MAX_LINE_LENGTH + 1)) + "\r\n") - ensure_for(duration=2, f=lambda: self.nodes[0].process.poll() is None) - # Connection should be dropped and retried, causing another PROTOCOLINFO. - self.wait_until(lambda: len(mock_tor.received_commands) >= 2, timeout=10) - assert_equal(mock_tor.received_commands[1], "PROTOCOLINFO 1") + self.log.info("Test that Tor control does not disconnect with a MAX_LINE_LENGTH line.") + with self.expect_disconnect(False, mock_tor): + msg = "250-" + ("A" * (MAX_LINE_LENGTH - 5)) + "\r" + assert_equal(len(msg), MAX_LINE_LENGTH) + # The \n is not counted in line length. + mock_tor.send_raw(msg + "\n") + + self.log.info("Test that Tor control disconnects with a MAX_LINE_LENGTH + 1 line") + with self.expect_disconnect(True, mock_tor): + msg = "250-" + ("A" * (MAX_LINE_LENGTH - 4)) + "\r" + assert_equal(len(msg), MAX_LINE_LENGTH + 1) + mock_tor.send_raw(msg + "\n") mock_tor.stop()