Skip to content

Return nil on empty response #498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions lib/ruby_lsp/ruby_lsp_rails/runner_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,32 +70,27 @@ def initialize(outgoing_queue)
# https://github.com/Shopify/ruby-lsp-rails/issues/348
end

log_message("Ruby LSP Rails booting server")

stdin, stdout, stderr, wait_thread = Bundler.with_original_env do
Open3.popen3("bundle", "exec", "rails", "runner", "#{__dir__}/server.rb", "start")
end

@stdin = T.let(stdin, IO)
@stdout = T.let(stdout, IO)
@stderr = T.let(stderr, IO)
@stdin.sync = true
@stdout.sync = true
@stderr.sync = true
@wait_thread = T.let(wait_thread, Process::Waiter)

# We set binmode for Windows compatibility
@stdin.binmode
@stdout.binmode
@stderr.binmode

log_message("Ruby LSP Rails booting server")
count = 0

begin
count += 1
initialize_response = T.must(read_response)
@rails_root = T.let(initialize_response[:root], String)
rescue EmptyMessageError
log_message("Ruby LSP Rails is retrying initialize (#{count})")
retry if count < MAX_RETRIES
end

initialize_response = T.must(read_response)
@rails_root = T.let(initialize_response[:root], String)
log_message("Finished booting Ruby LSP Rails server")

unless ENV["RAILS_ENV"] == "test"
Expand Down Expand Up @@ -274,11 +269,9 @@ def send_message(request, **params)
sig { overridable.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
def read_response
raw_response = @mutex.synchronize do
headers = @stdout.gets("\r\n\r\n")
raise IncompleteMessageError unless headers

content_length = headers[/Content-Length: (\d+)/i, 1].to_i
raise EmptyMessageError if content_length.zero?
content_length = read_content_length
content_length = read_content_length unless content_length
raise EmptyMessageError unless content_length

@stdout.read(content_length)
end
Expand Down Expand Up @@ -311,6 +304,17 @@ def log_message(message, type: RubyLsp::Constant::MessageType::LOG)

@outgoing_queue << RubyLsp::Notification.window_log_message(message, type: type)
end

sig { returns(T.nilable(Integer)) }
def read_content_length
headers = @stdout.gets("\r\n\r\n")
return unless headers

length = headers[/Content-Length: (\d+)/i, 1]
return unless length

length.to_i
end
end

class NullClient < RunnerClient
Expand Down
27 changes: 27 additions & 0 deletions test/ruby_lsp_rails/launch_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# typed: true
# frozen_string_literal: true

require "test_helper"

module RubyLsp
module Rails
class LaunchTest < ActiveSupport::TestCase
test "launching the client succeeds" do
outgoing_queue = Thread::Queue.new

client = RunnerClient.create_client(outgoing_queue)
refute_instance_of(NullClient, client)

first = pop_log_notification(outgoing_queue, Constant::MessageType::LOG)
assert_equal("Ruby LSP Rails booting server", first.params.message)

second = pop_log_notification(outgoing_queue, Constant::MessageType::LOG)
assert_match("Finished booting Ruby LSP Rails server", second.params.message)

client.shutdown
assert_predicate(client, :stopped?)
outgoing_queue.close
end
end
end
end
21 changes: 6 additions & 15 deletions test/ruby_lsp_rails/runner_client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,16 @@ class RunnerClientTest < ActiveSupport::TestCase
junk = %{\nputs "1\r\n\r\nhello"}
File.write("test/dummy/config/application.rb", content + junk)

capture_subprocess_io do
outgoing_queue = Thread::Queue.new
client = RunnerClient.create_client(outgoing_queue)
outgoing_queue = Thread::Queue.new
client = RunnerClient.create_client(outgoing_queue)
response = client.model("User")

response = T.must(client.model("User"))
assert(response.key?(:columns))
begin
assert(T.must(response).key?(:columns))
ensure
T.must(outgoing_queue).close
FileUtils.mv("test/dummy/config/application.rb.bak", "test/dummy/config/application.rb")
end
ensure
FileUtils.mv("test/dummy/config/application.rb.bak", "test/dummy/config/application.rb")
end

test "delegate notification" do
Expand Down Expand Up @@ -155,14 +154,6 @@ def execute(request, params)
ensure
FileUtils.rm("server_addon.rb")
end

private

def pop_log_notification(message_queue, type)
log = message_queue.pop
log = message_queue.pop until log.params.type == type
log
end
end

class NullClientTest < ActiveSupport::TestCase
Expand Down
8 changes: 8 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,13 @@ def pop_result(server)
)
T.cast(result, RubyLsp::Result)
end

def pop_log_notification(message_queue, type)
log = message_queue.pop
return log if log.params.type == type

log = message_queue.pop until log.params.type == type
log
end
end
end
Loading