22# frozen_string_literal: true
33
44require "test_helper"
5+ require "timeout"
56
67class IntegrationTest < Minitest ::Test
78 def setup
@@ -376,9 +377,12 @@ def test_launch_mode_update_does_not_modify_main_lockfile
376377 def test_launch_mode_retries_if_setup_failed_after_successful_install
377378 # RubyGems asks for confirmation when uninstalling a gem, so we need to be able to write the `y` to stdin
378379 uninstall_rails = -> ( ) {
379- stdin , _stdout , _stderr , wait_thread = Open3 . popen3 ( "gem" , "uninstall" , "rails" )
380+ stdin , stdout , stderr , wait_thread = Open3 . popen3 ( "gem" , "uninstall" , "rails" )
380381 stdin . write ( "y\n " )
381382 wait_thread . join
383+ stdin . close
384+ stdout . close
385+ stderr . close
382386 }
383387
384388 in_temp_dir do |dir |
@@ -400,14 +404,19 @@ def test_launch_mode_retries_if_setup_failed_after_successful_install
400404 FileUtils . touch ( bundle_env_path )
401405
402406 thread = Thread . new do
403- File . open ( bundle_env_path ) do | f |
404- f . flock ( File :: LOCK_EX )
405-
407+ file = File . open ( bundle_env_path )
408+ begin
409+ file . flock ( File :: LOCK_EX )
406410 # Give the bundle compose enough time to finish and get stuck on the lock
407411 sleep ( 2 )
408412 # Uninstall Rails after successfully bundle installing and before invoking Bundler.setup, which will cause
409413 # it to fail with `Bundler::GemNotFound`. This triggers our retry mechanism
410414 uninstall_rails . call
415+ rescue => e
416+ flunk ( e . full_message )
417+ ensure
418+ file . flock ( File ::LOCK_UN )
419+ file . close
411420 end
412421 end
413422
@@ -437,49 +446,59 @@ def test_launching_an_older_server_version
437446 private
438447
439448 def launch ( workspace_path , exec = "ruby-lsp-launcher" , extra_env = { } )
440- stdin , stdout , stderr , wait_thr = Open3 #: as untyped
441- . popen3 (
442- extra_env ,
443- Gem . ruby ,
444- File . join ( __dir__ , ".." , "exe" , exec ) ,
445- )
446- stdin . sync = true
447- stdin . binmode
448- stdout . sync = true
449- stdout . binmode
450- stderr . sync = true
451- stderr . binmode
452-
453- send_message ( stdin , {
454- id : 1 ,
455- method : "initialize" ,
456- params : {
457- initializationOptions : { } ,
458- capabilities : { general : { positionEncodings : [ "utf-8" ] } } ,
459- workspaceFolders : [ { uri : URI ::Generic . from_path ( path : workspace_path ) . to_s } ] ,
460- } ,
461- } )
462-
463- # First message is the log of initializing Ruby LSP
464- read_message ( stdout , stderr )
465- # Verify that initialization didn't fail
466- initialize_response = read_message ( stdout , stderr )
467- refute ( initialize_response [ :error ] , initialize_response . dig ( :error , :message ) )
468-
469- send_message ( stdin , { id : 2 , method : "shutdown" } )
470- send_message ( stdin , { method : "exit" } )
471-
472- # Wait until the process exits
473- wait_thr . join
474-
475- # If the child process failed, it is really difficult to diagnose what's happening unless we read what was printed
476- # to stderr
477- unless wait_thr . value . success?
478- require "timeout"
479-
480- Timeout . timeout ( 5 ) do
481- flunk ( "Process failed\n #{ stderr . read } " )
449+ stdin = nil #: IO?
450+ stdout = nil #: IO?
451+ stderr = nil #: IO?
452+
453+ begin
454+ Timeout . timeout ( 180 ) do
455+ stdin , stdout , stderr , wait_thr = Open3 #: as untyped
456+ . popen3 (
457+ extra_env ,
458+ Gem . ruby ,
459+ File . join ( __dir__ , ".." , "exe" , exec ) ,
460+ )
461+ stdin . sync = true
462+ stdin . binmode
463+ stdout . sync = true
464+ stdout . binmode
465+ stderr . sync = true
466+ stderr . binmode
467+
468+ send_message ( stdin , {
469+ id : 1 ,
470+ method : "initialize" ,
471+ params : {
472+ initializationOptions : { } ,
473+ capabilities : { general : { positionEncodings : [ "utf-8" ] } } ,
474+ workspaceFolders : [ { uri : URI ::Generic . from_path ( path : workspace_path ) . to_s } ] ,
475+ } ,
476+ } )
477+
478+ # First message is the log of initializing Ruby LSP
479+ read_message ( stdout , stderr )
480+ # Verify that initialization didn't fail
481+ initialize_response = read_message ( stdout , stderr )
482+ refute ( initialize_response [ :error ] , initialize_response . dig ( :error , :message ) )
483+
484+ send_message ( stdin , { id : 2 , method : "shutdown" } )
485+ send_message ( stdin , { method : "exit" } )
486+
487+ # Wait until the process exits
488+ wait_thr . join
489+ end
490+ rescue Timeout ::Error
491+ if stderr
492+ Timeout . timeout ( 5 ) { flunk ( "Launching the server timed out\n #{ stderr . read } " ) }
493+ end
494+
495+ if stdout
496+ Timeout . timeout ( 5 ) { flunk ( "Launching the server timed out\n #{ stdout . read } " ) }
482497 end
498+ ensure
499+ stdin &.close
500+ stdout &.close
501+ stderr &.close
483502 end
484503
485504 assert_path_exists ( File . join ( workspace_path , ".ruby-lsp" , "Gemfile" ) )
0 commit comments