diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index ed465cc0..a793f16d 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -24,6 +24,15 @@ jobs: continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }} steps: - uses: actions/checkout@v3 + - name: Set up Ruby 3.4 for test server + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4' + - name: Start test server + run: | + ruby spec/support/server.rb & + sleep 5 + curl -f http://localhost:3001/ || (sleep 5 && curl -f http://localhost:3001/) - name: Install libcurl header run: | if ${{ matrix.os == 'macos' }} diff --git a/Gemfile b/Gemfile index 714a8488..c7e009e1 100644 --- a/Gemfile +++ b/Gemfile @@ -6,18 +6,6 @@ gem "rake" group :development, :test do gem "rspec", "~> 3.4" - - if Gem.ruby_version < Gem::Version.new("3.0.0") - gem "sinatra", "~> 2.2" - else - gem "sinatra" - end - - gem "rackup" - gem "json" - gem "mime-types", "~> 1.18" - gem "mustermann" - gem "webrick" end group :perf do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6bf08cc0..06990a7b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,17 +7,6 @@ require "ethon" require 'rspec' -require_relative 'support/localhost_server' -require_relative 'support/server' - # Ethon.logger = Logger.new($stdout).tap do |log| # log.level = Logger::DEBUG # end - -RSpec.configure do |config| - # config.order = :rand - - config.before(:suite) do - LocalhostServer.new(TESTSERVER.new, 3001) - end -end diff --git a/spec/support/localhost_server.rb b/spec/support/localhost_server.rb deleted file mode 100644 index 520a3b14..00000000 --- a/spec/support/localhost_server.rb +++ /dev/null @@ -1,109 +0,0 @@ -# frozen_string_literal: true -require 'rack' -require 'webrick' -require 'net/http' -require 'rackup' -require 'timeout' - -# The code for this is inspired by Capybara's server: -# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb -class LocalhostServer - READY_MESSAGE = "Server ready" - - # Fallback to older Rack handler if rackup is not available - RACKUP_HANDLER = - if defined?(Rackup::Handler) - Rackup::Handler::WEBrick - else - Rack::Handler::WEBrick - end - - class Identify - def initialize(app) - @app = app - end - - def call(env) - if env["PATH_INFO"] == "/__identify__" - [200, {}, [LocalhostServer::READY_MESSAGE]] - else - @app.call(env) - end - end - end - - attr_reader :port - - def initialize(rack_app, port = nil) - @port = port || find_available_port - @rack_app = rack_app - concurrently { boot } - wait_until(10, "Boot failed.") { booted? } - end - - private - - def find_available_port - server = TCPServer.new('127.0.0.1', 0) - server.addr[1] - ensure - server.close if server - end - - def boot - options = { :Port => port, :Host => 'localhost' } - # Use WEBrick for tests since it supports all HTTP methods including custom ones like PURGE - # Puma is stricter about HTTP methods and rejects custom methods with 501 "method not supported" - app = Identify.new(@rack_app) - - options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER'] - - RACKUP_HANDLER.run(app, **options) - end - - def booted? - res = ::Net::HTTP.get_response("127.0.0.1", '/__identify__', port) - if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection) - return res.body == READY_MESSAGE - end - rescue Errno::ECONNREFUSED, Errno::EBADF - return false - end - - def concurrently - if should_use_subprocess? - pid = Process.fork do - trap(:INT) { RACKUP_HANDLER.shutdown } - yield - exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet. - end - - at_exit do - Process.kill('INT', pid) - begin - Process.wait(pid) - rescue Errno::ECHILD - # ignore this error...I think it means the child process has already exited. - end - end - else - Thread.new { yield } - end - end - - def should_use_subprocess? - # !ENV['THREADED'] - false - end - - def wait_until(timeout, error_message, &block) - start_time = Time.now - - while true - return if yield - raise Timeout::Error.new(error_message) if (Time.now - start_time) > timeout - sleep(0.05) - end - end -end - diff --git a/spec/support/server.rb b/spec/support/server.rb index 94874067..d08e4927 100644 --- a/spec/support/server.rb +++ b/spec/support/server.rb @@ -1,8 +1,20 @@ #!/usr/bin/env ruby # frozen_string_literal: true + +require 'bundler/inline' + +gemfile do + source 'https://rubygems.org' + gem 'sinatra' + gem 'rackup' + gem 'webrick' +end + require 'json' require 'zlib' require 'sinatra/base' +require 'webrick' +require 'rackup' TESTSERVER = Sinatra.new do use Rack::RewindableInput::Middleware if defined?(Rack::RewindableInput::Middleware) @@ -115,3 +127,14 @@ request.env.merge!(:body => request.body.tap {|b| b.rewind }.read).to_json end end + +puts "Starting test server on port 3001..." + +options = { + :Port => 3001, + :Host => 'localhost', + :AccessLog => [], + :Logger => WEBrick::BasicLog.new(StringIO.new) +} + +Rackup::Handler::WEBrick.run(TESTSERVER, **options)