class Selenium::WebDriver::Service

Base class implementing default behavior of service object, responsible for starting and stopping driver implementations.

Constants

SOCKET_LOCK_TIMEOUT
START_TIMEOUT
STOP_TIMEOUT

Attributes

default_port[R]
driver_path[R]
executable[R]
missing_text[R]
shutdown_supported[R]
executable_path[R]
host[RW]

Public Class Methods

chrome(**opts) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 40
def chrome(**opts)
  Chrome::Service.new(**opts)
end
driver_path=(path) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 74
def driver_path=(path)
  Platform.assert_executable path if path.is_a?(String)
  @driver_path = path
end
edge(**opts) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 66
def edge(**opts)
  Edge::Service.new(**opts)
end
firefox(**opts) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 44
def firefox(**opts)
  binary_path = Firefox::Binary.path
  args = opts.delete(:args)
  case args
  when Hash
    args[:binary] ||= binary_path
    opts[:args] = args
  when Array
    opts[:args] = ["--binary=#{binary_path}"]
    opts[:args] += args
  else
    opts[:args] = ["--binary=#{binary_path}"]
  end

  Firefox::Service.new(**opts)
end
ie(**opts) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 61
def ie(**opts)
  IE::Service.new(**opts)
end
Also aliased as: internet_explorer
internet_explorer(**opts)
Alias for: ie
new(path: nil, port: nil, args: nil) click to toggle source

End users should use a class method for the desired driver, rather than using this directly.

@api private

# File lib/selenium/webdriver/common/service.rb, line 89
def initialize(path: nil, port: nil, args: nil)
  path ||= self.class.driver_path
  port ||= self.class.default_port
  args ||= []

  @executable_path = binary_path(path)
  @host = Platform.localhost
  @port = Integer(port)

  @extra_args = args.is_a?(Hash) ? extract_service_args(args) : args

  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
end
safari(**opts) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 70
def safari(**opts)
  Safari::Service.new(**opts)
end

Public Instance Methods

start() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 103
def start
  raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?

  Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running

  socket_lock.locked do
    find_free_port
    start_process
    connect_until_stable
  end
end
stop() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 115
def stop
  return unless self.class.shutdown_supported

  stop_server
  @process.poll_for_exit STOP_TIMEOUT
rescue ChildProcess::TimeoutError
  nil # noop
ensure
  stop_process
end
uri() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 126
def uri
  @uri ||= URI.parse("http://#{@host}:#{@port}")
end

Protected Instance Methods

extract_service_args(driver_opts) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 213
def extract_service_args(driver_opts)
  driver_opts.key?(:args) ? driver_opts.delete(:args) : []
end

Private Instance Methods

binary_path(path = nil) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 132
def binary_path(path = nil)
  path = path.call if path.is_a?(Proc)
  path ||= Platform.find_binary(self.class.executable)

  raise Error::WebDriverError, self.class.missing_text unless path

  Platform.assert_executable path
  path
end
build_process(*command) click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 142
def build_process(*command)
  WebDriver.logger.debug("Executing Process #{command}")
  @process = ChildProcess.build(*command)
  if WebDriver.logger.debug?
    @process.io.stdout = @process.io.stderr = WebDriver.logger.io
  elsif Platform.jruby?
    # Apparently we need to read the output of drivers on JRuby.
    @process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
  end

  @process
end
cannot_connect_error_text() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 203
def cannot_connect_error_text
  "unable to connect to #{self.class.executable} #{@host}:#{@port}"
end
connect_to_server() { |http| ... } click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 155
def connect_to_server
  Net::HTTP.start(@host, @port) do |http|
    http.open_timeout = STOP_TIMEOUT / 2
    http.read_timeout = STOP_TIMEOUT / 2

    yield http
  end
end
connect_until_stable() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 196
def connect_until_stable
  socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
  return if socket_poller.connected?

  raise Error::WebDriverError, cannot_connect_error_text
end
find_free_port() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 164
def find_free_port
  @port = PortProber.above(@port)
end
process_exited?() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 192
def process_exited?
  @process.nil? || @process.exited?
end
process_running?() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 188
def process_running?
  defined?(@process) && @process&.alive?
end
socket_lock() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 207
def socket_lock
  @socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
end
start_process() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 168
def start_process
  @process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
  # Note: this is a bug only in Windows 7
  @process.leader = true unless Platform.windows?
  @process.start
end
stop_process() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 175
def stop_process
  return if process_exited?

  @process.stop STOP_TIMEOUT
  @process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
end
stop_server() click to toggle source
# File lib/selenium/webdriver/common/service.rb, line 182
def stop_server
  return if process_exited?

  connect_to_server { |http| http.get('/shutdown') }
end