github.com/trevoraustin/hub@v2.2.0-preview1.0.20141105230840-96d8bfc654cc+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( 89 :message => "expected %p; got %p" % [ 90 expected, auth.credentials 91 ] 92 ) 93 end 94 end 95 96 def generate_patch(subject) 97 <<PATCH 98 From 7eb75a26ee8e402aad79fcf36a4c1461e3ec2592 Mon Sep 17 00:00:00 2001 99 From: Mislav <mislav.marohnic@gmail.com> 100 Date: Tue, 24 Jun 2014 11:07:05 -0700 101 Subject: [PATCH] #{subject} 102 --- 103 diff --git a/README.md b/README.md 104 new file mode 100644 105 index 0000000..ce01362 106 --- /dev/null 107 +++ b/README.md 108 +hello 109 -- 110 1.9.3 111 PATCH 112 end 113 end 114 115 new(klass.new).start 116 end 117 118 attr_reader :app, :host, :port 119 attr_accessor :server 120 121 def initialize(app, host = '127.0.0.1') 122 @app = app 123 @host = host 124 @server = nil 125 @server_thread = nil 126 end 127 128 def responsive? 129 return false if @server_thread && @server_thread.join(0) 130 131 res = Net::HTTP.start(host, port) { |http| http.get('/__identify__') } 132 133 res.is_a?(Net::HTTPSuccess) and res.body == app.object_id.to_s 134 rescue Errno::ECONNREFUSED, Errno::EBADF 135 return false 136 end 137 138 def start 139 @port = self.class.ports[app.object_id] 140 141 if not @port or not responsive? 142 @server_thread = start_handler(Identify.new(app)) do |server, host, port| 143 self.server = server 144 @port = self.class.ports[app.object_id] = port 145 end 146 147 Timeout.timeout(60) { @server_thread.join(0.01) until responsive? } 148 end 149 rescue TimeoutError 150 raise "Rack application timed out during boot" 151 else 152 self 153 end 154 155 def start_handler(app) 156 server = nil 157 thread = Rack::Handler::WEBrick.run(app, server_options) { |s| server = s } 158 addr = server.listeners[0].addr 159 yield server, addr[3], addr[1] 160 return thread 161 end 162 163 def server_options 164 { :Port => 0, 165 :BindAddress => '127.0.0.1', 166 :ShutdownSocketWithoutClose => true, 167 :ServerType => Thread, 168 :AccessLog => [], 169 :Logger => WEBrick::Log::new(nil, 0) 170 } 171 end 172 173 def stop 174 server.shutdown 175 @server_thread.join 176 end 177 end 178 end 179 180 WEBrick::HTTPStatus::StatusMessage[422] = "Unprocessable Entity"