From 996484c890debe583bc3116e97a1d6493b53551d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 6 Apr 2009 14:00:14 -0400 Subject: [PATCH] Refactoring selenium RC and app server boot code --- lib/webrat/core/configuration.rb | 2 +- lib/webrat/selenium.rb | 134 +----------------- lib/webrat/selenium/application_server.rb | 71 ++++++++++ .../selenium/merb_application_server.rb | 48 +++++++ .../selenium/rails_application_server.rb | 42 ++++++ lib/webrat/selenium/selenium_rc_server.rb | 80 +++++++++++ lib/webrat/selenium/selenium_session.rb | 7 +- .../selenium/sinatra_application_server.rb | 35 +++++ spec/private/core/configuration_spec.rb | 4 +- .../private/selenium/selenium_session_spec.rb | 44 ------ spec/private/selenium/selenium_spec.rb | 109 -------------- 11 files changed, 285 insertions(+), 291 deletions(-) create mode 100644 lib/webrat/selenium/application_server.rb create mode 100644 lib/webrat/selenium/merb_application_server.rb create mode 100644 lib/webrat/selenium/rails_application_server.rb create mode 100644 lib/webrat/selenium/selenium_rc_server.rb create mode 100644 lib/webrat/selenium/sinatra_application_server.rb delete mode 100644 spec/private/selenium/selenium_session_spec.rb delete mode 100644 spec/private/selenium/selenium_spec.rb diff --git a/lib/webrat/core/configuration.rb b/lib/webrat/core/configuration.rb index 434d85e..38949fe 100755 --- a/lib/webrat/core/configuration.rb +++ b/lib/webrat/core/configuration.rb @@ -64,7 +64,7 @@ module Webrat self.application_environment = :test self.application_port = 3001 self.application_address = 'localhost' - self.application_framework = 'rails' + self.application_framework = :rails self.selenium_server_port = 4444 self.infinite_redirect_limit = 10 self.selenium_browser_key = '*firefox' diff --git a/lib/webrat/selenium.rb b/lib/webrat/selenium.rb index 4ae678c..b7574fe 100644 --- a/lib/webrat/selenium.rb +++ b/lib/webrat/selenium.rb @@ -6,139 +6,6 @@ require "webrat/selenium/matchers" require "webrat/core_extensions/tcp_socket" 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. # Activate it with (for example, in your env.rb): # @@ -201,6 +68,7 @@ module Webrat end end end + if defined?(ActionController::IntegrationTest) module ActionController #:nodoc: IntegrationTest.class_eval do diff --git a/lib/webrat/selenium/application_server.rb b/lib/webrat/selenium/application_server.rb new file mode 100644 index 0000000..6d40b5d --- /dev/null +++ b/lib/webrat/selenium/application_server.rb @@ -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 \ No newline at end of file diff --git a/lib/webrat/selenium/merb_application_server.rb b/lib/webrat/selenium/merb_application_server.rb new file mode 100644 index 0000000..4c44e08 --- /dev/null +++ b/lib/webrat/selenium/merb_application_server.rb @@ -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 \ No newline at end of file diff --git a/lib/webrat/selenium/rails_application_server.rb b/lib/webrat/selenium/rails_application_server.rb new file mode 100644 index 0000000..fe59314 --- /dev/null +++ b/lib/webrat/selenium/rails_application_server.rb @@ -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 \ No newline at end of file diff --git a/lib/webrat/selenium/selenium_rc_server.rb b/lib/webrat/selenium/selenium_rc_server.rb new file mode 100644 index 0000000..3ffbb26 --- /dev/null +++ b/lib/webrat/selenium/selenium_rc_server.rb @@ -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 diff --git a/lib/webrat/selenium/selenium_session.rb b/lib/webrat/selenium/selenium_session.rb index 596d963..4a506ba 100644 --- a/lib/webrat/selenium/selenium_session.rb +++ b/lib/webrat/selenium/selenium_session.rb @@ -1,4 +1,6 @@ require "webrat/core/save_and_open_page" +require "webrat/selenium/selenium_rc_server" +require "webrat/selenium/application_server" module Webrat class TimeoutError < WebratError @@ -179,6 +181,7 @@ module Webrat end protected + def silence_stream(stream) old_stream = stream.dup stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') @@ -189,8 +192,8 @@ module Webrat end def setup #:nodoc: - Webrat.start_selenium_server - Webrat.start_app_server + Webrat::Selenium::SeleniumRCServer.boot + Webrat::Selenium::ApplicationServer.boot create_browser $browser.start diff --git a/lib/webrat/selenium/sinatra_application_server.rb b/lib/webrat/selenium/sinatra_application_server.rb new file mode 100644 index 0000000..804f034 --- /dev/null +++ b/lib/webrat/selenium/sinatra_application_server.rb @@ -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 \ No newline at end of file diff --git a/spec/private/core/configuration_spec.rb b/spec/private/core/configuration_spec.rb index abc5c86..ed9a35b 100755 --- a/spec/private/core/configuration_spec.rb +++ b/spec/private/core/configuration_spec.rb @@ -76,8 +76,8 @@ describe Webrat::Configuration do @config = Webrat::Configuration.new end - it "should use 'selenium' as the application environment by default" do - @config.application_environment.should == :selenium + it "should use 'test' as the application environment by default" do + @config.application_environment.should == :test end it "should use 3001 as the application port by default" do diff --git a/spec/private/selenium/selenium_session_spec.rb b/spec/private/selenium/selenium_session_spec.rb deleted file mode 100644 index d92e497..0000000 --- a/spec/private/selenium/selenium_session_spec.rb +++ /dev/null @@ -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 \ No newline at end of file diff --git a/spec/private/selenium/selenium_spec.rb b/spec/private/selenium/selenium_spec.rb deleted file mode 100644 index c4fe946..0000000 --- a/spec/private/selenium/selenium_spec.rb +++ /dev/null @@ -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