1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
# frozen_string_literal: true
require 'open-uri'
require 'net/http'
require 'timeout'
module Sinatra
# NOTE: This feature is experimental, and missing tests!
#
# 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", __dir__)
# end
# end
#
# Override Runner#app_file, #command, #port, #protocol and #ping_path for customization.
#
# **Don't forget to override #app_file specific to your application!**
#
# Wherever 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/integration/runner.rb
class Runner
def app_file
File.expand_path('server.rb', __dir__)
end
def run
@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 get_stream(url = '/stream', &block)
Net::HTTP.start '127.0.0.1', port do |http|
request = Net::HTTP::Get.new url
http.request request do |response|
response.read_body(&block)
end
end
end
def get_response(url)
Net::HTTP.start '127.0.0.1', port do |http|
request = Net::HTTP::Get.new url
http.request request do |response|
response
end
end
end
def log
@log ||= +''
loop { @log << pipe.read_nonblock(1) }
rescue Exception
@log
end
private
attr_accessor :pipe
def start
IO.popen(command)
end
# to be overwritten
def command
"bundle exec ruby #{app_file} -p #{port} -e production"
end
def ping(timeout = 30)
loop do
return if alive?
if Time.now - @started > timeout
warn command, log
raise "timeout starting server with command '#{command}'"
else
sleep 0.1
end
end
end
def alive?
3.times { get(ping_path) }
true
rescue EOFError, SystemCallError, OpenURI::HTTPError, Timeout::Error
false
end
# to be overwritten
def ping_path
'/ping'
end
# to be overwritten
def port
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
|