class Selenium::Server

Wraps the remote server jar

Usage:

server = Selenium::Server.new('/path/to/selenium-server-standalone.jar')
server.start

Automatically download the given version:

server = Selenium::Server.get '2.6.0'
server.start

or the latest version:

server = Selenium::Server.get :latest
server.start

Run the server in the background:

server = Selenium::Server.new(jar, :background => true)
server.start

Add additional arguments:

server = Selenium::Server.new(jar)
server << ["--additional", "args"]
server.start

Constants

CL_RESET

Attributes

background[RW]

The Mode of the Server :standalone, hub, node

log[RW]

The Mode of the Server :standalone, hub, node

port[RW]

The Mode of the Server :standalone, hub, node

role[RW]

The Mode of the Server :standalone, hub, node

timeout[RW]

The Mode of the Server :standalone, hub, node

Public Class Methods

available_assets() click to toggle source

@api private

# File lib/selenium/server.rb, line 115
def available_assets
  @available_assets ||= net_http_start('api.github.com') do |http|
    json = http.get('/repos/seleniumhq/selenium/releases').body
    all_assets = JSON.parse(json).map { |release| release['assets'] }.flatten
    server_assets = all_assets.select { |asset| asset['name'].match(/selenium-server-(\d+\.\d+\.\d+)\.jar/) }
    server_assets.each_with_object({}) { |asset, hash| hash[asset.delete('name')] = asset }
  end
end
download(required_version = :latest) click to toggle source

Download the given version of the selenium-server jar and return location

@param [String, Symbol] required_version X.Y.Z defaults to ‘:latest’ @return [String] location of downloaded file

# File lib/selenium/server.rb, line 80
def download(required_version = :latest)
  required_version = latest if required_version == :latest
  download_file_name = "selenium-server-#{required_version}.jar"

  return download_file_name if File.exist? download_file_name

  begin
    download_location = available_assets[download_file_name]['browser_download_url']
    released = Net::HTTP.get_response(URI.parse(download_location))
    redirected = URI.parse released.header['location']

    File.open(download_file_name, 'wb') do |destination|
      download_server(redirected, destination)
    end
  rescue StandardError
    FileUtils.rm_rf download_file_name
    raise
  end

  download_file_name
end
download_server(uri, destination) click to toggle source
# File lib/selenium/server.rb, line 136
def download_server(uri, destination)
  net_http_start('github-releases.githubusercontent.com') do |http|
    request = Net::HTTP::Get.new uri
    resp = http.request(request) do |response|
      total = response.content_length
      progress = 0
      segment_count = 0

      response.read_body do |segment|
        progress += segment.length
        segment_count += 1

        if (segment_count % 15).zero?
          percent = progress.fdiv(total) * 100
          print "#{CL_RESET}Downloading #{destination.path}: #{percent.to_i}% (#{progress} / #{total})"
          segment_count = 0
        end

        destination.write(segment)
      end
    end

    raise Error, "#{resp.code} for #{destination.path}" unless resp.is_a? Net::HTTPSuccess
  end
end
get(required_version = :latest, opts = {}) click to toggle source

Download the given version of the selenium-server jar and return instance

@param [String, Symbol] required_version X.Y.Z defaults to ‘:latest’ @param [Hash] opts @return [Selenium::Server]

# File lib/selenium/server.rb, line 69
def get(required_version = :latest, opts = {})
  new(download(required_version), opts)
end
latest() click to toggle source

Ask GitHub what the latest selenium-server version is.

# File lib/selenium/server.rb, line 106
def latest
  @latest ||= begin
    available = available_assets.keys.map { |key| key[/selenium-server-(\d+\.\d+\.\d+)\.jar/, 1] }
    available.map { |asset| Gem::Version.new(asset) }.max.to_s
  end
end
net_http_start(address, &block) click to toggle source
# File lib/selenium/server.rb, line 124
def net_http_start(address, &block)
  http_proxy = ENV.fetch('http_proxy', nil) || ENV.fetch('HTTP_PROXY', nil)
  if http_proxy
    http_proxy = "http://#{http_proxy}" unless http_proxy.start_with?('http://')
    uri = URI.parse(http_proxy)

    Net::HTTP.start(address, nil, uri.host, uri.port, &block)
  else
    Net::HTTP.start(address, use_ssl: true, &block)
  end
end
new(jar, opts = {}) click to toggle source

@param [String] jar Path to the server jar. @param [Hash] opts the options to create the server process with

@option opts [Integer] :port Port the server should listen on (default: 4444). @option opts [Integer] :timeout Seconds to wait for server launch/shutdown (default: 30) @option opts [true,false] :background Run the server in the background (default: false) @option opts [true,false,String] :log Either a path to a log file,

or true to pass server log to stdout.

@raise [Errno::ENOENT] if the jar file does not exist

# File lib/selenium/server.rb, line 182
def initialize(jar, opts = {})
  raise Errno::ENOENT, jar unless File.exist?(jar)

  @jar = jar
  @host = '127.0.0.1'
  @role = opts.fetch(:role, 'standalone')
  @port = opts.fetch(:port, 4444)
  @timeout = opts.fetch(:timeout, 30)
  @background = opts.fetch(:background, false)
  @additional_args = opts.fetch(:args, [])
  @log = opts[:log]
  if opts[:log_level]
    @log ||= true
    @additional_args << '--log-level'
    @additional_args << opts[:log_level].to_s
  end

  @log_file = nil
end

Public Instance Methods

<<(arg) click to toggle source
# File lib/selenium/server.rb, line 225
def <<(arg)
  if arg.is_a?(Array)
    @additional_args += arg
  else
    @additional_args << arg.to_s
  end
end
start() click to toggle source
# File lib/selenium/server.rb, line 202
def start
  process.start
  poll_for_service

  process.wait unless @background
end
stop() click to toggle source
# File lib/selenium/server.rb, line 209
def stop
  begin
    Net::HTTP.get(@host, '/selenium-server/driver/?cmd=shutDownSeleniumServer', @port)
  rescue Errno::ECONNREFUSED
  end

  stop_process if @process
  poll_for_shutdown

  @log_file&.close
end
webdriver_url() click to toggle source
# File lib/selenium/server.rb, line 221
def webdriver_url
  "http://#{@host}:#{@port}/wd/hub"
end

Private Instance Methods

poll_for_service() click to toggle source
# File lib/selenium/server.rb, line 273
def poll_for_service
  return if socket.connected?

  raise Error, "remote server not launched in #{@timeout} seconds"
end
poll_for_shutdown() click to toggle source
# File lib/selenium/server.rb, line 279
def poll_for_shutdown
  return if socket.closed?

  raise Error, "remote server not stopped in #{@timeout} seconds"
end
process() click to toggle source
# File lib/selenium/server.rb, line 249
def process
  @process ||= begin
    # extract any additional_args that start with -D as options
    properties = @additional_args.dup - @additional_args.delete_if { |arg| arg[/^-D/] }
    args = ['-jar', @jar, @role, '--port', @port.to_s]
    server_command = ['java'] + properties + args + @additional_args
    cp = ChildProcess.build(*server_command)
    WebDriver.logger.debug("Executing Process #{server_command}")

    io = cp.io

    if @log.is_a?(String)
      @log_file = File.open(@log, 'w')
      io.stdout = io.stderr = @log_file
    elsif @log
      io.inherit!
    end

    cp.detach = @background

    cp
  end
end
socket() click to toggle source
# File lib/selenium/server.rb, line 285
def socket
  @socket ||= WebDriver::SocketPoller.new(@host, @port, @timeout)
end
stop_process() click to toggle source
# File lib/selenium/server.rb, line 235
def stop_process
  return unless @process.alive?

  begin
    @process.poll_for_exit(5)
  rescue ChildProcess::TimeoutError
    @process.stop
  end
rescue Errno::ECHILD
  # already dead
ensure
  @process = nil
end