Skip to content

Commit

Permalink
add integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rkh committed Mar 13, 2012
1 parent 163a60e commit cc681c7
Show file tree
Hide file tree
Showing 3 changed files with 301 additions and 0 deletions.
62 changes: 62 additions & 0 deletions test/integration/app.rb
@@ -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"
208 changes: 208 additions & 0 deletions test/integration_helper.rb
@@ -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
31 changes: 31 additions & 0 deletions test/integration_test.rb
@@ -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

0 comments on commit cc681c7

Please sign in to comment.