require 'net/http' # Starts a Rails application server in a fork and waits for it to be responsive class RailsServer HOST = 'localhost'.freeze class << self attr_accessor :instance end def self.start(port = nil, debug = nil) self.instance = new(port, debug) self.instance.start self.instance end def self.stop self.instance.stop if instance self.instance = nil end def self.get(path) self.instance.get(path) end def self.post(path, data) self.instance.post(path, data) end def self.run(port, silent) if silent require 'stringio' $stdout = StringIO.new $stderr = StringIO.new end require './config/environment' require 'thin' if Rails::VERSION::MAJOR == 3 rails = Rails.application else rails = ActionController::Dispatcher.new end app = Identify.new(rails) Thin::Logging.silent = silent Rack::Handler::Thin.run(app, :Port => port, :AccessLog => []) end def self.app_host self.instance.app_host end def initialize(port, debug) @port = (port || 3001).to_i @debug = debug end def start @pid = fork do command = "ruby -r#{__FILE__} -e 'RailsServer.run(#{@port}, #{(!@debug).inspect})'" puts command if @debug exec(command) end wait_until_responsive end def stop if @pid Process.kill('INT', @pid) Process.wait(@pid) @pid = nil end end def get(path) puts "GET #{path}" if @debug Net::HTTP.start(HOST, @port) { |http| http.get(path) } end def post(path, data) puts "POST #{path}\n#{data}" if @debug Net::HTTP.start(HOST, @port) { |http| http.post(path, data) } end def wait_until_responsive 20.times do if responsive? return true else sleep(0.5) end end raise "Couldn't connect to Rails application server at #{HOST}:#{@port}" end def responsive? response = Net::HTTP.start(HOST, @port) { |http| http.get('/__identify__') } response.is_a?(Net::HTTPSuccess) rescue Errno::ECONNREFUSED, Errno::EBADF return false end def app_host "http://#{HOST}:#{@port}" end # From Capybara::Server class Identify def initialize(app) @app = app end def call(env) if env["PATH_INFO"] == "/__identify__" [200, {}, 'OK'] else @app.call(env) end end end end