Skip to content
Browse files

Extract a Connection class for booting the server

  • Loading branch information...
1 parent 4ca10d2 commit 665e0fc729e3028acb58324e0c6350c13e4854af @jferris jferris committed May 4, 2012
View
3 lib/capybara/driver/webkit.rb
@@ -1,6 +1,7 @@
require "capybara"
require "capybara/driver/webkit/version"
require "capybara/driver/webkit/node"
+require "capybara/driver/webkit/connection"
require "capybara/driver/webkit/browser"
require "capybara/driver/webkit/socket_debugger"
require "capybara/driver/webkit/cookie_jar"
@@ -22,7 +23,7 @@ def initialize(app, options={})
@options = options
@rack_server = Capybara::Server.new(@app)
@rack_server.boot if Capybara.run_server
- @browser = options[:browser] || Browser.new
+ @browser = options[:browser] || Browser.new(Connection.new(options))
@browser.ignore_ssl_errors if options[:ignore_ssl_errors]
end
View
110 lib/capybara/driver/webkit/browser.rb
@@ -1,19 +1,9 @@
-require 'socket'
-require 'thread'
-require 'timeout'
require 'json'
class Capybara::Driver::Webkit
class Browser
- attr :server_port
-
- def initialize(options = {})
- @socket_class = options[:socket_class] || TCPSocket
- @stdout = options.has_key?(:stdout) ?
- options[:stdout] :
- $stdout
- start_server
- connect
+ def initialize(connection)
+ @connection = connection
end
def visit(url)
@@ -88,11 +78,11 @@ def ignore_ssl_errors
end
def command(name, *args)
- @socket.puts name
- @socket.puts args.size
+ @connection.puts name
+ @connection.puts args.size
args.each do |arg|
- @socket.puts arg.to_s.bytesize
- @socket.print arg.to_s
+ @connection.puts arg.to_s.bytesize
+ @connection.print arg.to_s
end
check
read_response
@@ -138,90 +128,8 @@ def resize_window(width, height)
private
- def start_server
- pipe = fork_server
- @server_port = discover_server_port(pipe)
- @stdout_thread = Thread.new do
- Thread.current.abort_on_exception = true
- forward_stdout(pipe)
- end
- end
-
- def fork_server
- server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
- pipe, @pid = server_pipe_and_pid(server_path)
- register_shutdown_hook
- pipe
- end
-
- def kill_process(pid)
- if RUBY_PLATFORM =~ /mingw32/
- Process.kill(9, pid)
- else
- Process.kill("INT", pid)
- end
- end
-
- def register_shutdown_hook
- @owner_pid = Process.pid
- at_exit do
- if Process.pid == @owner_pid
- kill_process(@pid)
- end
- end
- end
-
- def server_pipe_and_pid(server_path)
- cmdline = [server_path]
- pipe = IO.popen(cmdline.join(" "))
- [pipe, pipe.pid]
- end
-
- def discover_server_port(read_pipe)
- return unless IO.select([read_pipe], nil, nil, 10)
- ((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
- end
-
- def forward_stdout(pipe)
- while pipe_readable?(pipe)
- line = pipe.readline
- if @stdout
- @stdout.write(line)
- @stdout.flush
- end
- end
- rescue EOFError
- end
-
- if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
- # please note the use of IO::select() here, as it is used specifically to
- # preserve correct signal handling behavior in ruby 1.8.
- # https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
- # https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
- def pipe_readable?(pipe)
- IO.select([pipe])
- end
- else
- def pipe_readable?(pipe)
- !pipe.eof?
- end
- end
-
- def connect
- Timeout.timeout(5) do
- while @socket.nil?
- attempt_connect
- end
- end
- end
-
- def attempt_connect
- @socket = @socket_class.open("127.0.0.1", @server_port)
- rescue Errno::ECONNREFUSED
- end
-
def check
- result = @socket.gets
+ result = @connection.gets
result.strip! if result
if result.nil?
@@ -234,8 +142,8 @@ def check
end
def read_response
- response_length = @socket.gets.to_i
- response = @socket.read(response_length)
+ response_length = @connection.gets.to_i
+ response = @connection.read(response_length)
response.force_encoding("UTF-8") if response.respond_to?(:force_encoding)
response
end
View
118 lib/capybara/driver/webkit/connection.rb
@@ -0,0 +1,118 @@
+require 'socket'
+require 'timeout'
+require 'thread'
+
+class Capybara::Driver::Webkit
+ class Connection
+ attr_reader :port
+
+ def initialize(options = {})
+ @socket_class = options[:socket_class] || TCPSocket
+ @stdout = options.has_key?(:stdout) ?
+ options[:stdout] :
+ $stdout
+ start_server
+ connect
+ end
+
+ def puts(string)
+ @socket.puts string
+ end
+
+ def print(string)
+ @socket.print string
+ end
+
+ def gets
+ @socket.gets
+ end
+
+ def read(length)
+ @socket.read(length)
+ end
+
+ private
+
+ def start_server
+ pipe = fork_server
+ @port = discover_port(pipe)
+ @stdout_thread = Thread.new do
+ Thread.current.abort_on_exception = true
+ forward_stdout(pipe)
+ end
+ end
+
+ def fork_server
+ server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
+ pipe, @pid = server_pipe_and_pid(server_path)
+ register_shutdown_hook
+ pipe
+ end
+
+ def kill_process(pid)
+ if RUBY_PLATFORM =~ /mingw32/
+ Process.kill(9, pid)
+ else
+ Process.kill("INT", pid)
+ end
+ end
+
+ def register_shutdown_hook
+ @owner_pid = Process.pid
+ at_exit do
+ if Process.pid == @owner_pid
+ kill_process(@pid)
+ end
+ end
+ end
+
+ def server_pipe_and_pid(server_path)
+ cmdline = [server_path]
+ pipe = IO.popen(cmdline.join(" "))
+ [pipe, pipe.pid]
+ end
+
+ def discover_port(read_pipe)
+ return unless IO.select([read_pipe], nil, nil, 10)
+ ((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
+ end
+
+ def forward_stdout(pipe)
+ while pipe_readable?(pipe)
+ line = pipe.readline
+ if @stdout
+ @stdout.write(line)
+ @stdout.flush
+ end
+ end
+ rescue EOFError
+ end
+
+ def connect
+ Timeout.timeout(5) do
+ while @socket.nil?
+ attempt_connect
+ end
+ end
+ end
+
+ def attempt_connect
+ @socket = @socket_class.open("127.0.0.1", @port)
+ rescue Errno::ECONNREFUSED
+ end
+
+ if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
+ # please note the use of IO::select() here, as it is used specifically to
+ # preserve correct signal handling behavior in ruby 1.8.
+ # https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
+ # https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
+ def pipe_readable?(pipe)
+ IO.select([pipe])
+ end
+ else
+ def pipe_readable?(pipe)
+ !pipe.eof?
+ end
+ end
+ end
+end
View
33 spec/browser_spec.rb
@@ -2,42 +2,19 @@
require 'self_signed_ssl_cert'
require 'stringio'
require 'capybara/driver/webkit/browser'
+require 'capybara/driver/webkit/connection'
require 'socket'
require 'base64'
describe Capybara::Driver::Webkit::Browser do
- let(:browser) { Capybara::Driver::Webkit::Browser.new }
- let(:browser_ignore_ssl_err) {
- Capybara::Driver::Webkit::Browser.new.tap { |browser| browser.ignore_ssl_errors }
- }
-
- describe '#server_port' do
- subject { browser.server_port }
- it 'returns a valid port number' do
- should be_a(Integer)
- end
-
- it 'returns a port in the allowed range' do
- should be_between 0x400, 0xffff
- end
- end
-
- context 'random port' do
- it 'chooses a new port number for a new browser instance' do
- new_browser = Capybara::Driver::Webkit::Browser.new
- new_browser.server_port.should_not == browser.server_port
+ let(:browser) { Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new) }
+ let(:browser_ignore_ssl_err) do
+ Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
+ browser.ignore_ssl_errors
end
end
- it 'forwards stdout to the given IO object' do
- io = StringIO.new
- new_browser = Capybara::Driver::Webkit::Browser.new(:stdout => io)
- new_browser.execute_script('console.log("hello world")')
- sleep(0.5)
- io.string.should include "hello world\n"
- end
-
context 'handling of SSL validation errors' do
before do
# set up minimal HTTPS server
View
54 spec/connection_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+require 'capybara/driver/webkit/connection'
+
+describe Capybara::Driver::Webkit::Connection do
+ it "boots a server to talk to" do
+ url = @rack_server.url("/")
+ connection.puts "Visit"
+ connection.puts 1
+ connection.puts url.to_s.bytesize
+ connection.print url
+ connection.gets.should == "ok\n"
+ connection.gets.should == "0\n"
+ connection.puts "Body"
+ connection.puts 0
+ connection.gets.should == "ok\n"
+ response_length = connection.gets.to_i
+ response = connection.read(response_length)
+ response.should include("Hey there")
+ end
+
+ it 'forwards stdout to the given IO object' do
+ io = StringIO.new
+ redirected_connection = Capybara::Driver::Webkit::Connection.new(:stdout => io)
+ script = 'console.log("hello world")'
+ redirected_connection.puts "Execute"
+ redirected_connection.puts 1
+ redirected_connection.puts script.to_s.bytesize
+ redirected_connection.print script
+ sleep(0.5)
+ io.string.should include "hello world\n"
+ end
+
+ it "returns the server port" do
+ connection.port.should be_between 0x400, 0xffff
+ end
+
+ it "chooses a new port number for a new connection" do
+ new_connection = Capybara::Driver::Webkit::Connection.new
+ new_connection.port.should_not == connection.port
+ end
+
+ let(:connection) { Capybara::Driver::Webkit::Connection.new }
+
+ before(:all) do
+ @app = lambda do |env|
+ body = "<html><body>Hey there</body></html>"
+ [200,
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s },
+ [body]]
+ end
+ @rack_server = Capybara::Server.new(@app)
+ @rack_server.boot
+ end
+end
View
15 spec/driver_spec.rb
@@ -988,15 +988,15 @@ def wait_for_error_to_complete
end
def make_the_server_come_back
- subject.browser.instance_variable_get(:@socket).unstub!(:gets)
- subject.browser.instance_variable_get(:@socket).unstub!(:puts)
- subject.browser.instance_variable_get(:@socket).unstub!(:print)
+ subject.browser.instance_variable_get(:@connection).unstub!(:gets)
+ subject.browser.instance_variable_get(:@connection).unstub!(:puts)
+ subject.browser.instance_variable_get(:@connection).unstub!(:print)
end
def make_the_server_go_away
- subject.browser.instance_variable_get(:@socket).stub!(:gets).and_return(nil)
- subject.browser.instance_variable_get(:@socket).stub!(:puts)
- subject.browser.instance_variable_get(:@socket).stub!(:print)
+ subject.browser.instance_variable_get(:@connection).stub!(:gets).and_return(nil)
+ subject.browser.instance_variable_get(:@connection).stub!(:puts)
+ subject.browser.instance_variable_get(:@connection).stub!(:print)
end
end
@@ -1091,7 +1091,8 @@ def echoed_cookie
context "with socket debugger" do
let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger }
let(:browser_with_debugger){
- Capybara::Driver::Webkit::Browser.new(:socket_class => socket_debugger_class)
+ connection = Capybara::Driver::Webkit::Connection.new(:socket_class => socket_debugger_class)
+ Capybara::Driver::Webkit::Browser.new(connection)
}
let(:driver_with_debugger){ Capybara::Driver::Webkit.new(@app, :browser => browser_with_debugger) }
View
4 spec/spec_helper.rb
@@ -22,8 +22,10 @@
require File.join(spec_dir, "spec_helper")
+require 'capybara/driver/webkit/connection'
require 'capybara/driver/webkit/browser'
-$webkit_browser = Capybara::Driver::Webkit::Browser.new(:socket_class => TCPSocket, :stdout => nil)
+connection = Capybara::Driver::Webkit::Connection.new(:socket_class => TCPSocket, :stdout => nil)
+$webkit_browser = Capybara::Driver::Webkit::Browser.new(connection)
Capybara.register_driver :reusable_webkit do |app|
Capybara::Driver::Webkit.new(app, :browser => $webkit_browser)

0 comments on commit 665e0fc

Please sign in to comment.
Something went wrong with that request. Please try again.