Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
301 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,62 @@ | ||
$stderr.puts "loading" | ||
require 'sinatra' | ||
|
||
configure do | ||
set :foo, :bar | ||
end | ||
|
||
get '/app_file' do | ||
content_type :txt | ||
settings.app_file | ||
end | ||
|
||
get '/ping' do | ||
'pong' | ||
end | ||
|
||
get '/stream' do | ||
stream do |out| | ||
sleep 0.1 | ||
out << "a" | ||
sleep 1.2 | ||
out << "b" | ||
end | ||
end | ||
|
||
get '/mainonly' do | ||
object = Object.new | ||
begin | ||
object.send(:get, '/foo') { } | ||
'false' | ||
rescue NameError | ||
'true' | ||
end | ||
end | ||
|
||
set :out, nil | ||
get '/async' do | ||
stream(:keep_open) { |o| (settings.out = o) << "hi!" } | ||
end | ||
|
||
get '/send' do | ||
settings.out << params[:msg] if params[:msg] | ||
settings.out.close if params[:close] | ||
"ok" | ||
end | ||
|
||
class Subclass < Sinatra::Base | ||
set :out, nil | ||
get '/subclass/async' do | ||
stream(:keep_open) { |o| (settings.out = o) << "hi!" } | ||
end | ||
|
||
get '/subclass/send' do | ||
settings.out << params[:msg] if params[:msg] | ||
settings.out.close if params[:close] | ||
"ok" | ||
end | ||
end | ||
|
||
use Subclass | ||
|
||
$stderr.puts "starting" |
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,208 @@ | ||
require 'sinatra/base' | ||
require 'rbconfig' | ||
require 'open-uri' | ||
require 'net/http' | ||
|
||
module IntegrationHelper | ||
class BaseServer | ||
extend Enumerable | ||
attr_accessor :server, :port, :pipe | ||
alias name server | ||
|
||
def self.all | ||
@all ||= [] | ||
end | ||
|
||
def self.each(&block) | ||
all.each(&block) | ||
end | ||
|
||
def self.run(server, port) | ||
new(server, port).run | ||
end | ||
|
||
def app_file | ||
File.expand_path('../integration/app.rb', __FILE__) | ||
end | ||
|
||
def environment | ||
"development" | ||
end | ||
|
||
def initialize(server, port) | ||
@installed, @pipe, @server, @port = nil, nil, server, port | ||
Server.all << self | ||
end | ||
|
||
def run | ||
return unless installed? | ||
kill | ||
@log = "" | ||
@pipe = IO.popen(command) | ||
@started = Time.now | ||
warn "#{server} up and running on port #{port}" if ping | ||
at_exit { kill } | ||
end | ||
|
||
def expect(str) | ||
return if log.size < str.size or log[0, str.size] == str | ||
raise "Server did not start properly:\n\n#{log}" | ||
end | ||
|
||
def ping(timeout = 30) | ||
loop do | ||
return if alive? | ||
if Time.now - @started > timeout | ||
$stderr.puts command, log | ||
fail "timeout" | ||
else | ||
expect "loading" | ||
sleep 0.1 | ||
end | ||
end | ||
end | ||
|
||
def alive? | ||
3.times { get('/ping') } | ||
true | ||
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError, SystemCallError, OpenURI::HTTPError => error | ||
false | ||
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(url) | ||
open("http://127.0.0.1:#{port}#{url}").read | ||
end | ||
|
||
def log | ||
@log ||= "" | ||
loop { @log << @pipe.read_nonblock(1) } | ||
rescue Exception | ||
@log | ||
end | ||
|
||
def installed? | ||
return @installed unless @installed.nil? | ||
require server | ||
@installed = true | ||
rescue LoadError | ||
warn "#{server} is not installed, skipping integration tests" | ||
@installed = false | ||
end | ||
|
||
def command | ||
@command ||= begin | ||
cmd = ["RACK_ENV=#{environment}", "exec"] | ||
if RbConfig.respond_to? :ruby | ||
cmd << RbConfig.ruby.inspect | ||
else | ||
file, dir = RbConfig::CONFIG.values_at('ruby_install_name', 'bindir') | ||
cmd << File.expand_path(file, dir).inspect | ||
end | ||
cmd << "-I" << File.expand_path('../../lib', __FILE__).inspect | ||
cmd << app_file.inspect << '-s' << server << '-o' << '127.0.0.1' << '-p' << port | ||
cmd << "-e" << environment.to_s << '2>&1' | ||
cmd.join " " | ||
end | ||
end | ||
|
||
def kill | ||
return unless pipe | ||
Process.kill("KILL", pipe.pid) | ||
rescue NotImplementedError | ||
system "kill -9 #{pipe.pid}" | ||
rescue Errno::ESRCH | ||
end | ||
|
||
def webrick? | ||
name.to_s == "webrick" | ||
end | ||
end | ||
|
||
if RUBY_ENGINE == "jruby" | ||
class JRubyServer < BaseServer | ||
def start_vm | ||
require 'java' | ||
# Create a new container, set load paths and env | ||
# SINGLETHREAD means create a new runtime | ||
vm = org.jruby.embed.ScriptingContainer.new(org.jruby.embed.LocalContextScope::SINGLETHREAD) | ||
vm.load_paths = [File.expand_path('../../lib', __FILE__)] | ||
vm.environment = ENV.merge('RACK_ENV' => environment.to_s) | ||
|
||
# This ensures processing of RUBYOPT which activates Bundler | ||
vm.provider.ruby_instance_config.process_arguments [] | ||
vm.argv = ['-s', server.to_s, '-o', '127.0.0.1', '-p', port.to_s, '-e', environment.to_s] | ||
|
||
# Set stdout/stderr so we can retrieve log | ||
@pipe = java.io.ByteArrayOutputStream.new | ||
vm.output = java.io.PrintStream.new(@pipe) | ||
vm.error = java.io.PrintStream.new(@pipe) | ||
|
||
Thread.new do | ||
# Hack to ensure that Kernel#caller has the same info as | ||
# when run from command-line, for Sintra::Application.app_file. | ||
# Also, line numbers are zero-based in JRuby's parser | ||
vm.provider.runtime.current_context.set_file_and_line(app_file, 0) | ||
# Run the app | ||
vm.run_scriptlet org.jruby.embed.PathType::ABSOLUTE, app_file | ||
# terminate launches at_exit hooks which start server | ||
vm.terminate | ||
end | ||
end | ||
|
||
def run | ||
return unless installed? | ||
kill | ||
@thread = start_vm | ||
@started = Time.now | ||
warn "#{server} up and running on port #{port}" if ping | ||
at_exit { kill } | ||
end | ||
|
||
def log | ||
String.from_java_bytes @pipe.to_byte_array | ||
end | ||
|
||
def kill | ||
@thread.kill if @thread | ||
@thread = nil | ||
end | ||
end | ||
Server = JRubyServer | ||
else | ||
Server = BaseServer | ||
end | ||
|
||
def it(message, &block) | ||
Server.each do |server| | ||
next unless server.installed? | ||
super "with #{server.name}: #{message}" do | ||
self.server = server | ||
server.run unless server.alive? | ||
begin | ||
instance_eval(&block) | ||
rescue Exception => error | ||
server.kill | ||
raise error | ||
end | ||
end | ||
end | ||
end | ||
|
||
def self.extend_object(obj) | ||
super | ||
|
||
base_port = 5000 + Process.pid % 100 | ||
Sinatra::Base.server.each_with_index do |server, index| | ||
Server.run(server, 5000+index) | ||
end | ||
end | ||
end |
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,31 @@ | ||
require File.expand_path('../helper', __FILE__) | ||
require File.expand_path('../integration_helper', __FILE__) | ||
require 'timeout' | ||
|
||
# These tests start a real server and talk to it over TCP. | ||
# Every test runs with every detected server. | ||
# | ||
# See test/integration/app.rb for the code of the app we test against. | ||
class IntegrationTest < Test::Unit::TestCase | ||
extend IntegrationHelper | ||
attr_accessor :server | ||
|
||
it('sets the app_file') { assert_equal server.app_file, server.get("/app_file") } | ||
|
||
it 'logs once in development mode' do | ||
random = "%064x" % Kernel.rand(2**256-1) | ||
server.get "/ping?x=#{random}" | ||
count = server.log.scan("GET /ping?x=#{random}").count | ||
server.webrick? ? assert(count > 0) : assert_equal(1, count) | ||
end | ||
|
||
it 'starts the correct server' do | ||
exp = %r{ | ||
==\sSinatra/#{Sinatra::VERSION}\s | ||
has\staken\sthe\sstage\son\s\d+\sfor\sdevelopment\s | ||
with\sbackup\sfrom\s#{server} | ||
}ix | ||
|
||
assert_match exp, server.log | ||
end | ||
end |