Refactoring selenium RC and app server boot code

This commit is contained in:
Bryan Helmkamp 2009-04-06 14:00:14 -04:00
parent 979418e303
commit 996484c890
11 changed files with 285 additions and 291 deletions

View File

@ -64,7 +64,7 @@ module Webrat
self.application_environment = :test self.application_environment = :test
self.application_port = 3001 self.application_port = 3001
self.application_address = 'localhost' self.application_address = 'localhost'
self.application_framework = 'rails' self.application_framework = :rails
self.selenium_server_port = 4444 self.selenium_server_port = 4444
self.infinite_redirect_limit = 10 self.infinite_redirect_limit = 10
self.selenium_browser_key = '*firefox' self.selenium_browser_key = '*firefox'

View File

@ -6,139 +6,6 @@ require "webrat/selenium/matchers"
require "webrat/core_extensions/tcp_socket" require "webrat/core_extensions/tcp_socket"
module Webrat module Webrat
def self.with_selenium_server #:nodoc:
start_selenium_server
yield
stop_selenium_server
end
def self.start_selenium_server #:nodoc:
unless Webrat.configuration.selenium_server_address
remote_control = ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0", Webrat.configuration.selenium_server_port, 5)
remote_control.jar_file = File.expand_path(__FILE__ + "../../../../vendor/selenium-server.jar")
silence_stream(STDOUT) do
remote_control.start :background => true
end
end
$stderr.print "==> Started selenium RC server. Waiting for it to boot... "
silence_stream(STDOUT) do
TCPSocket.wait_for_service_with_timeout \
:host => (Webrat.configuration.selenium_server_address || "0.0.0.0"),
:port => Webrat.configuration.selenium_server_port,
:timeout => 15 # seconds
end
$stderr.print "Ready!\n"
at_exit do
silence_stream(STDOUT) do
Webrat.stop_selenium_server
end
end
rescue SocketError
$stderr.puts
$stderr.puts
$stderr.puts "==> Failed to boot the Selenium RC server... exiting!"
exit
end
def self.stop_selenium_server #:nodoc:
::Selenium::RemoteControl::RemoteControl.new("0.0.0.0", Webrat.configuration.selenium_server_port, 5).stop unless Webrat.configuration.selenium_server_address
end
def self.pid_file
if File.exists?('config.ru')
prepare_pid_file(Dir.pwd, 'rack.pid')
else
prepare_pid_file("#{RAILS_ROOT}/tmp/pids", "mongrel_selenium.pid")
end
end
# Start the appserver for the underlying framework to test
#
# Sinatra: requires a config.ru in the root of your sinatra app to use this
# Merb: Attempts to use bin/merb and falls back to the system merb
# Rails: Calls mongrel_rails to startup the appserver
def self.start_app_server
case Webrat.configuration.application_framework
when :sinatra
fork do
File.open('rack.pid', 'w') { |fp| fp.write Process.pid }
exec 'rackup', File.expand_path(Dir.pwd + '/config.ru'), '-p', Webrat.configuration.application_port.to_s
end
when :merb
merb_cmd = 'merb'
if File.exist?('bin/merb')
merb_cmd = 'bin/merb'
end
cmd = "#{merb_cmd} -d -p #{Webrat.configuration.application_port} -e #{Webrat.configuration.application_environment}"
system cmd
else # rails
cmd = "mongrel_rails start -d --chdir='#{RAILS_ROOT}' --port=#{Webrat.configuration.application_port} --environment=#{Webrat.configuration.application_environment} --pid #{pid_file} &"
system cmd
end
$stderr.print "==> Started #{Webrat.configuration.application_framework} application server for Selenium. Waiting for it to boot... "
silence_stream(STDOUT) do
TCPSocket.wait_for_service_with_timeout \
:host => Webrat.configuration.application_address,
:port => Webrat.configuration.application_port.to_i,
:timeout => 30 # seconds
end
$stderr.print "Ready!\n"
at_exit do
silence_stream(STDOUT) do
Webrat.stop_app_server
end
end
rescue SocketError
$stderr.puts
$stderr.puts
$stderr.puts "==> Failed to boot the application server for selenium... exiting!"
case Webrat.configuration.application_framework
when :sinatra
when :merb
$stderr.puts
$stderr.puts "Verify you can start a Merb server with the folliwing command:"
$stderr.puts
$stderr.puts " #{cmd}"
else # rails
$stderr.puts
$stderr.puts "Verify you can start a Rails server with the folliwing command:"
$stderr.puts
$stderr.puts " #{cmd}"
end
exit
end
# Stop the appserver for the underlying framework under test
#
# Sinatra: Reads and kills the pid from the pid file created on startup
# Merb: Reads and kills the pid from the pid file created on startup
# Rails: Calls mongrel_rails stop to kill the appserver
def self.stop_app_server
case Webrat.configuration.application_framework
when :sinatra
pid = File.read('rack.pid')
system("kill -9 #{pid}")
FileUtils.rm_f 'rack.pid'
when :merb
pid = File.read("log/merb.#{Webrat.configuration.application_port}.pid")
system("kill -9 #{pid}")
FileUtils.rm_f "log/merb.#{Webrat.configuration.application_port}.pid"
else # rails
system "mongrel_rails stop -c #{RAILS_ROOT} --pid #{pid_file}"
end
end
def self.prepare_pid_file(file_path, pid_file_name)
FileUtils.mkdir_p File.expand_path(file_path)
File.expand_path("#{file_path}/#{pid_file_name}")
end
# To use Webrat's Selenium support, you'll need the selenium-client gem installed. # To use Webrat's Selenium support, you'll need the selenium-client gem installed.
# Activate it with (for example, in your <tt>env.rb</tt>): # Activate it with (for example, in your <tt>env.rb</tt>):
# #
@ -201,6 +68,7 @@ module Webrat
end end
end end
end end
if defined?(ActionController::IntegrationTest) if defined?(ActionController::IntegrationTest)
module ActionController #:nodoc: module ActionController #:nodoc:
IntegrationTest.class_eval do IntegrationTest.class_eval do

View File

@ -0,0 +1,71 @@
module Webrat
module Selenium
class ApplicationServer
def self.boot
case Webrat.configuration.application_framework
when :sinatra
require "webrat/selenium/sinatra_application_server"
SinatraApplicationServer.new.boot
when :merb
require "webrat/selenium/merb_application_server"
MerbApplicationServer.new.boot
when :rails
require "webrat/selenium/rails_application_server"
RailsApplicationServer.new.boot
else
raise WebratError.new(<<-STR)
Unknown Webrat application_framework: #{Webrat.configuration.application_framework.inspect}
Please ensure you have a Webrat configuration block that specifies an application_framework
in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
For example:
Webrat.configure do |config|
# ...
config.application_framework = :rails
end
STR
end
end
def boot
start
wait
stop_at_exit
end
def stop_at_exit
at_exit do
stop
end
end
def wait
$stderr.print "==> Waiting for #{Webrat.configuration.application_framework} application server on port #{Webrat.configuration.application_port}... "
wait_for_socket
$stderr.print "Ready!\n"
end
def wait_for_socket
silence_stream(STDOUT) do
TCPSocket.wait_for_service_with_timeout \
:host => Webrat.configuration.application_address,
:port => Webrat.configuration.application_port.to_i,
:timeout => 30 # seconds
end
rescue SocketError
fail
end
def prepare_pid_file(file_path, pid_file_name)
FileUtils.mkdir_p File.expand_path(file_path)
File.expand_path("#{file_path}/#{pid_file_name}")
end
end
end
end

View File

@ -0,0 +1,48 @@
module Webrat
module Selenium
class MerbApplicationServer < ApplicationServer
def start
system start_command
end
def stop
silence_stream(STDOUT) do
pid = File.read(pid_file)
system("kill -9 #{pid}")
FileUtils.rm_f pid_file
end
end
def fail
$stderr.puts
$stderr.puts
$stderr.puts "==> Failed to boot the Merb application server... exiting!"
$stderr.puts
$stderr.puts "Verify you can start a Merb server on port #{Webrat.configuration.application_port} with the following command:"
$stderr.puts
$stderr.puts " #{start_command}"
exit
end
def pid_file
"log/merb.#{Webrat.configuration.application_port}.pid"
end
def start_command
"#{merb_command} -d -p #{Webrat.configuration.application_port} -e #{Webrat.configuration.application_environment}"
end
def merb_command
if File.exist?('bin/merb')
merb_cmd = 'bin/merb'
else
merb_cmd = 'merb'
end
end
end
end
end

View File

@ -0,0 +1,42 @@
module Webrat
module Selenium
class RailsApplicationServer < ApplicationServer
def start
system start_command
end
def stop
silence_stream(STDOUT) do
system stop_command
end
end
def fail
$stderr.puts
$stderr.puts
$stderr.puts "==> Failed to boot the Rails application server... exiting!"
$stderr.puts
$stderr.puts "Verify you can start a Rails server on port #{Webrat.configuration.application_port} with the following command:"
$stderr.puts
$stderr.puts " #{start_command}"
exit
end
def pid_file
prepare_pid_file("#{RAILS_ROOT}/tmp/pids", "mongrel_selenium.pid")
end
def start_command
"mongrel_rails start -d --chdir='#{RAILS_ROOT}' --port=#{Webrat.configuration.application_port} --environment=#{Webrat.configuration.application_environment} --pid #{pid_file} &"
end
def stop_command
"mongrel_rails stop -c #{RAILS_ROOT} --pid #{pid_file}"
end
end
end
end

View File

@ -0,0 +1,80 @@
module Webrat
module Selenium
class SeleniumRCServer
def self.boot
new.boot
end
def boot
return if selenium_grid?
start
wait
stop_at_exit
end
def start
silence_stream(STDOUT) do
remote_control.start :background => true
end
end
def stop_at_exit
at_exit do
stop
end
end
def remote_control
return @remote_control if @remote_control
@remote_control = ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0", Webrat.configuration.selenium_server_port, 5)
@remote_control.jar_file = jar_path
return @remote_control
end
def jar_path
File.expand_path(__FILE__ + "../../../../../vendor/selenium-server.jar")
end
def selenium_grid?
Webrat.configuration.selenium_server_address
end
def wait
$stderr.print "==> Waiting for Selenium RC server on port #{Webrat.configuration.selenium_server_port}... "
wait_for_socket
$stderr.print "Ready!\n"
rescue SocketError
fail
end
def wait_for_socket
silence_stream(STDOUT) do
TCPSocket.wait_for_service_with_timeout \
:host => (Webrat.configuration.selenium_server_address || "0.0.0.0"),
:port => Webrat.configuration.selenium_server_port,
:timeout => 15 # seconds
end
end
def fail
$stderr.puts
$stderr.puts
$stderr.puts "==> Failed to boot the Selenium RC server... exiting!"
exit
end
def stop
silence_stream(STDOUT) do
::Selenium::RemoteControl::RemoteControl.new("0.0.0.0", Webrat.configuration.selenium_server_port, 5).stop
end
end
end
end
end

View File

@ -1,4 +1,6 @@
require "webrat/core/save_and_open_page" require "webrat/core/save_and_open_page"
require "webrat/selenium/selenium_rc_server"
require "webrat/selenium/application_server"
module Webrat module Webrat
class TimeoutError < WebratError class TimeoutError < WebratError
@ -179,6 +181,7 @@ module Webrat
end end
protected protected
def silence_stream(stream) def silence_stream(stream)
old_stream = stream.dup old_stream = stream.dup
stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
@ -189,8 +192,8 @@ module Webrat
end end
def setup #:nodoc: def setup #:nodoc:
Webrat.start_selenium_server Webrat::Selenium::SeleniumRCServer.boot
Webrat.start_app_server Webrat::Selenium::ApplicationServer.boot
create_browser create_browser
$browser.start $browser.start

View File

@ -0,0 +1,35 @@
module Webrat
module Selenium
class SinatraApplicationServer < ApplicationServer
def start
fork do
File.open('rack.pid', 'w') { |fp| fp.write Process.pid }
exec 'rackup', File.expand_path(Dir.pwd + '/config.ru'), '-p', Webrat.configuration.application_port.to_s
end
end
def stop
silence_stream(STDOUT) do
pid = File.read(pid_file)
system("kill -9 #{pid}")
FileUtils.rm_f pid_file
end
end
def fail
$stderr.puts
$stderr.puts
$stderr.puts "==> Failed to boot the Sinatra application server... exiting!"
exit
end
def pid_file
prepare_pid_file(Dir.pwd, 'rack.pid')
end
end
end
end

View File

@ -76,8 +76,8 @@ describe Webrat::Configuration do
@config = Webrat::Configuration.new @config = Webrat::Configuration.new
end end
it "should use 'selenium' as the application environment by default" do it "should use 'test' as the application environment by default" do
@config.application_environment.should == :selenium @config.application_environment.should == :test
end end
it "should use 3001 as the application port by default" do it "should use 3001 as the application port by default" do

View File

@ -1,44 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require "action_controller"
require "action_controller/integration"
require "webrat/selenium"
describe Webrat::SeleniumSession do
describe "create browser" do
it "should start the local selenium client and set speed to 0 when selenium_server_address is nil" do
selenium_session = Webrat::SeleniumSession.new
browser = mock "mock browser"
::Selenium::Client::Driver.should_receive(:new).with("localhost", Webrat.configuration.selenium_server_port, "*firefox", "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port}").and_return browser
browser.should_receive(:set_speed).with(0)
selenium_session.send :create_browser
end
it "should start the remote selenium client when selenium_server_address is set" do
Webrat.configuration.selenium_server_address = 'foo address'
selenium_session = Webrat::SeleniumSession.new
browser = mock "mock browser"
::Selenium::Client::Driver.should_receive(:new).with(Webrat.configuration.selenium_server_address, Webrat.configuration.selenium_server_port, "*firefox", "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port}").and_return browser
browser.should_not_receive(:set_speed)
selenium_session.send :create_browser
end
it "should use the config specifications" do
Webrat.configuration.selenium_server_port = 'selenium port'
Webrat.configuration.selenium_server_address = 'selenium address'
Webrat.configuration.application_port = 'app port'
Webrat.configuration.application_address = 'app address'
Webrat.configuration.selenium_browser_key = 'browser key'
selenium_session = Webrat::SeleniumSession.new
browser = mock "mock browser"
::Selenium::Client::Driver.should_receive(:new).with('selenium address',
'selenium port', 'browser key',
"http://app address:app port").and_return browser
browser.should_not_receive(:set_speed)
selenium_session.send :create_browser
end
end
end

View File

@ -1,109 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require "action_controller"
require "action_controller/integration"
require "webrat/selenium"
RAILS_ROOT = "/"
describe Webrat, "Selenium" do
describe "start_app_server" do
after(:each) { Webrat.configuration.application_framework = :rails }
describe "ruby on rails" do
it "should start the app server with correct config options" do
pid_file = "file"
Webrat.should_receive(:prepare_pid_file).with("#{RAILS_ROOT}/tmp/pids","mongrel_selenium.pid").and_return pid_file
Webrat.should_receive(:system).with("mongrel_rails start -d --chdir='#{RAILS_ROOT}' --port=#{Webrat.configuration.application_port} --environment=#{Webrat.configuration.application_environment} --pid #{pid_file} &")
TCPSocket.should_receive(:wait_for_service).with(:host => Webrat.configuration.application_address, :port => Webrat.configuration.application_port.to_i)
Webrat.start_app_server
end
end
describe "merb" do
it "should start the app server with correct config options" do
Webrat.configuration.application_framework = :merb
Webrat.should_receive(:system).with("merb -d -p #{Webrat.configuration.application_port} -e #{Webrat.configuration.application_environment}")
TCPSocket.should_receive(:wait_for_service).with(:host => Webrat.configuration.application_address, :port => Webrat.configuration.application_port.to_i)
Webrat.start_app_server
end
end
describe "sinatra" do
it "should start the app server with correct config options" do
rackup_file = File.expand_path(Dir.pwd + '/config.ru')
Webrat.configuration.application_framework = :sinatra
Webrat.should_receive(:fork)
# Kernel.should_receive(:exec).with(['rackup', rackup_file, '-p', Webrat.configuration.application_port])
TCPSocket.should_receive(:wait_for_service).with(:host => Webrat.configuration.application_address, :port => Webrat.configuration.application_port.to_i)
Webrat.start_app_server
FileUtils.rm_f 'rack.pid'
end
end
end
describe "stop_app_server" do
after(:each) { Webrat.configuration.application_framework = :rails }
describe "ruby on rails" do
it "should stop the app server with correct config options" do
pid_file = RAILS_ROOT+'/tmp/pids/mongrel_selenium.pid'
Webrat.should_receive(:system).with("mongrel_rails stop -c #{RAILS_ROOT} --pid #{pid_file}")
Webrat.stop_app_server
end
end
describe "merb" do
it "should stop the app server with correct config options" do
Webrat.configuration.application_framework = :merb
File.should_receive(:read).with('log/merb.3001.pid').and_return('666')
Webrat.should_receive(:system).with("kill -9 666")
Webrat.stop_app_server
end
end
describe "sinatra" do
it "should stop the app server with correct config options" do
Webrat.configuration.application_framework = :sinatra
File.should_receive(:read).with('rack.pid').and_return('666')
Webrat.should_receive(:system).with("kill -9 666")
Webrat.stop_app_server
FileUtils.rm_f 'rack.pid'
end
end
end
it 'prepare_pid_file' do
File.should_receive(:expand_path).with('path').and_return('full_path')
FileUtils.should_receive(:mkdir_p).with 'full_path'
File.should_receive(:expand_path).with('path/name')
Webrat.prepare_pid_file 'path', 'name'
end
describe "start_selenium_server" do
it "should not start the local selenium server if the selenium_server_address is set" do
Webrat.configuration.selenium_server_address = 'foo address'
::Selenium::RemoteControl::RemoteControl.should_not_receive(:new)
TCPSocket.should_receive(:wait_for_service).with(:host => Webrat.configuration.selenium_server_address, :port => Webrat.configuration.selenium_server_port)
Webrat.start_selenium_server
end
it "should start the local selenium server if the selenium_server_address is set" do
remote_control = mock "selenium remote control"
::Selenium::RemoteControl::RemoteControl.should_receive(:new).with("0.0.0.0", Webrat.configuration.selenium_server_port, 5).and_return remote_control
remote_control.should_receive(:jar_file=).with(/selenium-server\.jar/)
remote_control.should_receive(:start).with(:background => true)
TCPSocket.should_receive(:wait_for_service).with(:host => "0.0.0.0", :port => Webrat.configuration.selenium_server_port)
Webrat.start_selenium_server
end
end
describe "stop_selenium_server" do
it "should not attempt to stop the server if the selenium_server_address is set" do
Webrat.configuration.selenium_server_address = 'foo address'
::Selenium::RemoteControl::RemoteControl.should_not_receive(:new)
Webrat.stop_selenium_server
end
it "should stop the local server is the selenium_server_address is nil" do
remote_control = mock "selenium remote control"
::Selenium::RemoteControl::RemoteControl.should_receive(:new).with("0.0.0.0", Webrat.configuration.selenium_server_port, 5).and_return remote_control
remote_control.should_receive(:stop)
Webrat.stop_selenium_server
end
end
end