forked from sinatra/sinatra
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request sinatra#122 from apotonick/runner
Add Sinatra::Runner For Managing Sinatra Servers
- Loading branch information
Showing
1 changed file
with
134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
require 'open-uri' | ||
require 'net/http' | ||
require 'timeout' | ||
|
||
# Helps you spinning up and shutting down your own sinatra app. This is especially helpful for running | ||
# real network tests against a sinatra backend. | ||
# | ||
# The backend server could look like the following (in test/server.rb). | ||
# | ||
# require "sinatra" | ||
# | ||
# get "/" do | ||
# "Cheers from test server" | ||
# end | ||
# | ||
# get "/ping" do | ||
# "1" | ||
# end | ||
# | ||
# Note that you need to implement a ping action for internal use. | ||
# | ||
# Next, you need to write your runner. | ||
# | ||
# require 'sinatra/runner' | ||
# | ||
# class Runner < Sinatra::Runner | ||
# def app_file | ||
# File.expand_path("../server.rb", __FILE__) | ||
# end | ||
# end | ||
# | ||
# Override Runner#app_file, #command, #port, #protocol and #ping_path for customization. | ||
# | ||
# Whereever you need this test backend, here's how you manage it. The following example assumes you | ||
# have a test in your app that needs to be run against your test backend. | ||
# | ||
# runner = ServerRunner.new | ||
# runner.run | ||
# | ||
# # ..tests against localhost:4567 here.. | ||
# | ||
# runner.kill | ||
# | ||
# For an example, check https://github.com/apotonick/roar/blob/master/test/test_helper.rb | ||
module Sinatra | ||
class Runner | ||
def app_file | ||
File.expand_path("../server.rb", __FILE__) | ||
end | ||
|
||
def run | ||
#puts command | ||
@pipe = start | ||
@started = Time.now | ||
warn "#{server} up and running on port #{port}" if ping | ||
end | ||
|
||
def kill | ||
return unless pipe | ||
Process.kill("KILL", pipe.pid) | ||
rescue NotImplementedError | ||
system "kill -9 #{pipe.pid}" | ||
rescue Errno::ESRCH | ||
end | ||
|
||
def get(url) | ||
Timeout.timeout(1) { get_url("#{protocol}://127.0.0.1:#{port}#{url}") } | ||
end | ||
|
||
def log | ||
@log ||= "" | ||
loop { @log << pipe.read_nonblock(1) } | ||
rescue Exception | ||
@log | ||
end | ||
|
||
private | ||
attr_accessor :pipe | ||
|
||
def start | ||
IO.popen(command) | ||
end | ||
|
||
def command # to be overwritten | ||
"bundle exec ruby #{app_file} -p #{port} -e production" | ||
end | ||
|
||
def ping(timeout=30) | ||
loop do | ||
return if alive? | ||
if Time.now - @started > timeout | ||
$stderr.puts command, log | ||
fail "timeout" | ||
else | ||
sleep 0.1 | ||
end | ||
end | ||
end | ||
|
||
def alive? | ||
3.times { get(ping_path) } | ||
true | ||
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError, SystemCallError, OpenURI::HTTPError, Timeout::Error | ||
false | ||
end | ||
|
||
def ping_path # to be overwritten | ||
'/ping' | ||
end | ||
|
||
def port # to be overwritten | ||
4567 | ||
end | ||
|
||
def protocol | ||
"http" | ||
end | ||
|
||
def get_url(url) | ||
uri = URI.parse(url) | ||
|
||
return uri.read unless protocol == "https" | ||
get_https_url(uri) | ||
end | ||
|
||
def get_https_url(uri) | ||
http = Net::HTTP.new(uri.host, uri.port) | ||
http.use_ssl = true | ||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
request = Net::HTTP::Get.new(uri.request_uri) | ||
http.request(request).body | ||
end | ||
end | ||
end |