github.com/echohead/hub@v2.2.1+incompatible/features/support/local_server.rb (about) 1 # based on <github.com/jnicklas/capybara/blob/ab62b27/lib/capybara/server.rb> 2 require 'net/http' 3 require 'rack/handler/webrick' 4 require 'json' 5 require 'sinatra/base' 6 7 module Hub 8 class LocalServer 9 class Identify < Struct.new(:app) 10 def call(env) 11 if env["PATH_INFO"] == "/__identify__" 12 [200, {}, [app.object_id.to_s]] 13 else 14 app.call(env) 15 end 16 end 17 end 18 19 def self.ports 20 @ports ||= {} 21 end 22 23 class JsonParamsParser < Struct.new(:app) 24 def call(env) 25 if env['rack.input'] and not input_parsed?(env) and type_match?(env) 26 env['rack.request.form_input'] = env['rack.input'] 27 data = env['rack.input'].read 28 env['rack.request.form_hash'] = data.empty?? {} : JSON.parse(data) 29 end 30 app.call(env) 31 end 32 33 def input_parsed? env 34 env['rack.request.form_input'].eql? env['rack.input'] 35 end 36 37 def type_match? env 38 type = env['CONTENT_TYPE'] and 39 type.split(/\s*[;,]\s*/, 2).first.downcase =~ /[\/+]json$/ 40 end 41 end 42 43 class App < Sinatra::Base 44 def invoke 45 res = super 46 content_type :json unless response.content_type 47 response.body = '{}' if blank_response?(response.body) || 48 (response.body.respond_to?(:[]) && blank_response?(response.body[0])) 49 res 50 end 51 52 def blank_response?(obj) 53 obj.nil? || (obj.respond_to?(:empty?) && obj.empty?) 54 end 55 end 56 57 def self.start_sinatra(&block) 58 klass = Class.new(App) 59 klass.use JsonParamsParser 60 klass.set :environment, :test 61 klass.disable :protection 62 klass.error(404, 401) { content_type :json; nil } 63 klass.class_eval(&block) 64 klass.helpers do 65 def json(value) 66 content_type :json 67 JSON.generate value 68 end 69 70 def assert(expected) 71 expected.each do |key, value| 72 if params[key] != value 73 halt 422, json( 74 :message => "expected %s to be %s; got %s" % [ 75 key.inspect, 76 value.inspect, 77 params[key].inspect 78 ] 79 ) 80 end 81 end 82 end 83 84 def assert_basic_auth(*expected) 85 require 'rack/auth/basic' 86 auth = Rack::Auth::Basic::Request.new(env) 87 if auth.credentials != expected 88 halt 401, json(:message => "Bad credentials") 89 end 90 end 91 92 def generate_patch(subject) 93 <<PATCH 94 From 7eb75a26ee8e402aad79fcf36a4c1461e3ec2592 Mon Sep 17 00:00:00 2001 95 From: Mislav <mislav.marohnic@gmail.com> 96 Date: Tue, 24 Jun 2014 11:07:05 -0700 97 Subject: [PATCH] #{subject} 98 --- 99 diff --git a/README.md b/README.md 100 new file mode 100644 101 index 0000000..ce01362 102 --- /dev/null 103 +++ b/README.md 104 +hello 105 -- 106 1.9.3 107 PATCH 108 end 109 end 110 111 new(klass.new).start 112 end 113 114 attr_reader :app, :host, :port 115 attr_accessor :server 116 117 def initialize(app, host = '127.0.0.1') 118 @app = app 119 @host = host 120 @server = nil 121 @server_thread = nil 122 end 123 124 def responsive? 125 return false if @server_thread && @server_thread.join(0) 126 127 res = Net::HTTP.start(host, port) { |http| http.get('/__identify__') } 128 129 res.is_a?(Net::HTTPSuccess) and res.body == app.object_id.to_s 130 rescue Errno::ECONNREFUSED, Errno::EBADF 131 return false 132 end 133 134 def start 135 @port = self.class.ports[app.object_id] 136 137 if not @port or not responsive? 138 @server_thread = start_handler(Identify.new(app)) do |server, host, port| 139 self.server = server 140 @port = self.class.ports[app.object_id] = port 141 end 142 143 Timeout.timeout(60) { @server_thread.join(0.01) until responsive? } 144 end 145 rescue TimeoutError 146 raise "Rack application timed out during boot" 147 else 148 self 149 end 150 151 def start_handler(app) 152 server = nil 153 thread = Rack::Handler::WEBrick.run(app, server_options) { |s| server = s } 154 addr = server.listeners[0].addr 155 yield server, addr[3], addr[1] 156 return thread 157 end 158 159 def server_options 160 { :Port => 0, 161 :BindAddress => '127.0.0.1', 162 :ShutdownSocketWithoutClose => true, 163 :ServerType => Thread, 164 :AccessLog => [], 165 :Logger => WEBrick::Log::new(nil, 0) 166 } 167 end 168 169 def stop 170 server.shutdown 171 @server_thread.join 172 end 173 end 174 end 175 176 WEBrick::HTTPStatus::StatusMessage[422] = "Unprocessable Entity"