From 667bc2e2b7d1f762c8446464d484e47339f708e4 Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Wed, 18 Feb 2026 14:57:22 -0500 Subject: [PATCH] Support IPv4 and IPv6 for LSP reporter connection --- lib/ruby_lsp/test_reporters/lsp_reporter.rb | 7 +--- test/test_reporters/lsp_reporter_test.rb | 37 +++++++++++-------- test/test_reporters/minitest_reporter_test.rb | 2 +- .../test_reporters/test_unit_reporter_test.rb | 2 +- vscode/src/streamingRunner.ts | 2 +- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/lib/ruby_lsp/test_reporters/lsp_reporter.rb b/lib/ruby_lsp/test_reporters/lsp_reporter.rb index 613ddbd4c..dde2e5a33 100644 --- a/lib/ruby_lsp/test_reporters/lsp_reporter.rb +++ b/lib/ruby_lsp/test_reporters/lsp_reporter.rb @@ -213,12 +213,9 @@ def at_exit private - #: (String) -> TCPSocket + #: (String) -> Socket def socket(port) - # Connect to 127.0.0.1 (IPv4) explicitly since the extension listens on IPv4 only - # Using "localhost" hostname can cause connection failures on systems where it resolves - # to IPv6 first, but the server is only listening on IPv4 - socket = TCPSocket.new("127.0.0.1", port) + socket = Socket.tcp("localhost", port) socket.binmode socket.sync = true socket diff --git a/test/test_reporters/lsp_reporter_test.rb b/test/test_reporters/lsp_reporter_test.rb index 5c263bec1..354574012 100644 --- a/test/test_reporters/lsp_reporter_test.rb +++ b/test/test_reporters/lsp_reporter_test.rb @@ -26,33 +26,40 @@ def test_socket_connection_failure_fallbacks_to_stringio assert_kind_of(StringIO, io) end - def test_socket_uses_ipv4_address_not_localhost + def test_socket_connects_to_ipv4_server server = TCPServer.new("127.0.0.1", 0) port = server.addr[1].to_s - peer_info = nil #: [String, String]? - thread = Thread.new do - socket = server.accept - peer_addr = socket.peeraddr - # Store the values to assert outside the thread - peer_info = [peer_addr[0], peer_addr[3]] #: [String, String] - socket.close - end + thread = Thread.new { server.accept } ENV["RUBY_LSP_REPORTER_PORT"] = port reporter = LspReporter.new io = reporter.instance_variable_get(:@io) - assert_kind_of(TCPSocket, io) + assert_kind_of(Socket, io) - thread.join(1) + accepted = thread.join(1)&.value #: untyped + accepted&.close io.close server.close + end + + def test_socket_connects_to_ipv6_server + server = TCPServer.new("::1", 0) + port = server.addr[1].to_s - assert(peer_info, "Thread did not complete successfully") - family, address = peer_info - assert_equal("AF_INET", family) - assert_equal("127.0.0.1", address) + thread = Thread.new { server.accept } + + ENV["RUBY_LSP_REPORTER_PORT"] = port + reporter = LspReporter.new + io = reporter.instance_variable_get(:@io) + + assert_kind_of(Socket, io) + + accepted = thread.join(1)&.value #: untyped + accepted&.close + io.close + server.close end def test_coverage_results_are_formatted_as_vscode_expects diff --git a/test/test_reporters/minitest_reporter_test.rb b/test/test_reporters/minitest_reporter_test.rb index 6a8882b73..8eab2da4b 100644 --- a/test/test_reporters/minitest_reporter_test.rb +++ b/test/test_reporters/minitest_reporter_test.rb @@ -173,7 +173,7 @@ def test_minitest_spec_output def gather_events(uri, output: :stdout) plugin_path = File.expand_path("lib/ruby_lsp/test_reporters/minitest_reporter.rb") - server = TCPServer.new("127.0.0.1", 0) + server = TCPServer.new("localhost", 0) port = server.addr[1].to_s events = [] socket = nil #: Socket? diff --git a/test/test_reporters/test_unit_reporter_test.rb b/test/test_reporters/test_unit_reporter_test.rb index 7b58f3c8b..36eccbc79 100644 --- a/test/test_reporters/test_unit_reporter_test.rb +++ b/test/test_reporters/test_unit_reporter_test.rb @@ -97,7 +97,7 @@ def test_crashing_example def gather_events(uri, output: :stdout) reporter_path = File.expand_path(File.join("lib", "ruby_lsp", "test_reporters", "test_unit_reporter.rb")) - server = TCPServer.new("127.0.0.1", 0) + server = TCPServer.new("localhost", 0) port = server.addr[1].to_s events = [] socket = nil #: Socket? diff --git a/vscode/src/streamingRunner.ts b/vscode/src/streamingRunner.ts index 71f39bae4..f63222065 100644 --- a/vscode/src/streamingRunner.ts +++ b/vscode/src/streamingRunner.ts @@ -188,7 +188,7 @@ export class StreamingRunner implements vscode.Disposable { server.unref(); // eslint-disable-next-line @typescript-eslint/no-misused-promises - server.listen(0, "127.0.0.1", async () => { + server.listen(0, "localhost", async () => { const address = server.address(); if (!address) {