selenium-grid 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +12 -0
- data/Manifest.txt +35 -0
- data/README.txt +32 -0
- data/Rakefile +8 -0
- data/bin/selenium-grid +112 -0
- data/config/hoe.rb +66 -0
- data/config/requirements.rb +27 -0
- data/lib/extensions.rb +1 -0
- data/lib/extensions/file.rb +7 -0
- data/lib/extensions/rake.rb +14 -0
- data/lib/extensions/string.rb +18 -0
- data/lib/java.rb +1 -0
- data/lib/java/classpath.rb +26 -0
- data/lib/java/vm.rb +60 -0
- data/lib/openqa/selenium-grid-hub-standalone-1.0.1.jar +0 -0
- data/lib/openqa/selenium-grid-remote-control-standalone-1.0.1.jar +0 -0
- data/lib/openqa/selenium-server-1.0-SNAPSHOT.jar +0 -0
- data/lib/selenium-grid.rb +1 -0
- data/lib/selenium-grid/hub.rb +28 -0
- data/lib/selenium-grid/remote.rb +46 -0
- data/lib/selenium-grid/version.rb +8 -0
- data/lib/tasks/hoe.rake +6 -0
- data/lib/tasks/hub.rake +15 -0
- data/lib/tasks/rc.rake +15 -0
- data/lib/tasks/rspec.rake +20 -0
- data/spec/extensions/string_spec.rb +45 -0
- data/spec/extensions_spec_suite.rb +13 -0
- data/spec/java/vm_spec.rb +75 -0
- data/spec/java_spec_suite.rb +13 -0
- data/spec/selenium-grid/hub_spec.rb +67 -0
- data/spec/selenium-grid/remote_spec.rb +143 -0
- data/spec/selenium-grid_spec_suite.rb +13 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/spec_suite.rb +49 -0
- metadata +133 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/selenium-grid
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/extensions.rb
|
9
|
+
lib/extensions/file.rb
|
10
|
+
lib/extensions/rake.rb
|
11
|
+
lib/extensions/string.rb
|
12
|
+
lib/java.rb
|
13
|
+
lib/java/classpath.rb
|
14
|
+
lib/java/vm.rb
|
15
|
+
lib/openqa/selenium-grid-hub-standalone-1.0.1.jar
|
16
|
+
lib/openqa/selenium-grid-remote-control-standalone-1.0.1.jar
|
17
|
+
lib/openqa/selenium-server-1.0-SNAPSHOT.jar
|
18
|
+
lib/selenium-grid.rb
|
19
|
+
lib/selenium-grid/hub.rb
|
20
|
+
lib/selenium-grid/remote.rb
|
21
|
+
lib/selenium-grid/version.rb
|
22
|
+
lib/tasks/hoe.rake
|
23
|
+
lib/tasks/hub.rake
|
24
|
+
lib/tasks/rc.rake
|
25
|
+
lib/tasks/rspec.rake
|
26
|
+
spec/extensions/string_spec.rb
|
27
|
+
spec/extensions_spec_suite.rb
|
28
|
+
spec/java/vm_spec.rb
|
29
|
+
spec/java_spec_suite.rb
|
30
|
+
spec/selenium-grid/hub_spec.rb
|
31
|
+
spec/selenium-grid/remote_spec.rb
|
32
|
+
spec/selenium-grid_spec_suite.rb
|
33
|
+
spec/spec.opts
|
34
|
+
spec/spec_helper.rb
|
35
|
+
spec/spec_suite.rb
|
data/README.txt
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
= selenium-grid
|
2
|
+
|
3
|
+
* http://github.com/pivotal/selenium-grid/
|
4
|
+
|
5
|
+
== Selenium Grid Ruby
|
6
|
+
|
7
|
+
Selenium Grid Ruby packages Selenium Grid as a RubyGem.
|
8
|
+
|
9
|
+
== About Selenium Grid
|
10
|
+
|
11
|
+
From the website (http://selenium-grid.openqa.org/):
|
12
|
+
|
13
|
+
Selenium Grid is a tool that dramatically speeds up functional testing of
|
14
|
+
web-apps by leveraging your existing computing infrastructure. It allows you
|
15
|
+
to easily run multiple tests in parallel, on multiple machines, in an
|
16
|
+
heterogeneous enviroment.
|
17
|
+
|
18
|
+
== Usage:
|
19
|
+
|
20
|
+
rake hub:start [options]
|
21
|
+
rake hub:stop
|
22
|
+
rake rc:start [options]
|
23
|
+
rake rc:stop [options]
|
24
|
+
|
25
|
+
== Installation:
|
26
|
+
|
27
|
+
* sudo gem install selenium-grid
|
28
|
+
|
29
|
+
== Thanks:
|
30
|
+
|
31
|
+
* Philippe Hanrigou (http://github.com/ph7/)
|
32
|
+
* Brian Takita (http://github.com/btakita/)
|
data/Rakefile
ADDED
data/bin/selenium-grid
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'pp'
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'config', 'requirements')
|
7
|
+
|
8
|
+
include SeleniumGrid
|
9
|
+
|
10
|
+
class SeleniumGridOptions
|
11
|
+
def initialize
|
12
|
+
@options = {}
|
13
|
+
@opts = initialize_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(args)
|
17
|
+
begin
|
18
|
+
@opts.parse!(args)
|
19
|
+
rescue
|
20
|
+
summarize
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
@options
|
24
|
+
end
|
25
|
+
|
26
|
+
def summarize
|
27
|
+
puts @opts.banner
|
28
|
+
puts @opts.summarize
|
29
|
+
puts ""
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class HubStartOptions < SeleniumGridOptions
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def initialize_options
|
38
|
+
return OptionParser.new do |opts|
|
39
|
+
opts.banner = "hub:start"
|
40
|
+
|
41
|
+
opts.on('-b', '--background', 'send the process to the background') do
|
42
|
+
@options[:background] = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class RcStartOptions < SeleniumGridOptions
|
49
|
+
ENVIRONMENTS = %w(*chrome *firefox *safari *ie)
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def initialize_options
|
54
|
+
return OptionParser.new do |opts|
|
55
|
+
opts.banner = "rc:start"
|
56
|
+
|
57
|
+
opts.on('-b', '--background', 'send the process to the background') do
|
58
|
+
@options[:background] = true
|
59
|
+
end
|
60
|
+
opts.on('-e', '--environment <browser>', ENVIRONMENTS, "browser environment to launch", "\tbrowsers:\t#{ENVIRONMENTS.join(', ')}", "\tdefault:\t#{Remote::DEFAULT_BROWSER}") do |env|
|
61
|
+
@options[:env] = env
|
62
|
+
end
|
63
|
+
opts.on('-p', '--port <port>', "port to launch the remote control on", "\tdefault:\t#{Remote::DEFAULT_PORT}") do |port|
|
64
|
+
@options[:port] = port
|
65
|
+
end
|
66
|
+
opts.on('-h', '--host <name>', "hostname to launch the remote control on", "\tdefault:\t#{Remote::DEFAULT_HOST}") do |host|
|
67
|
+
@options[:host] = host
|
68
|
+
end
|
69
|
+
opts.on('-u', '--hub_url <url>', "hub url where the remote control points", "\tdefault:\t#{Remote::DEFAULT_HUB_URL}") do |hub_url|
|
70
|
+
@options[:hub_url] = hub_url
|
71
|
+
end
|
72
|
+
opts.on('-s', '--selenium_args "<args>"', "selenium arguments to pass through") do |selenium_args|
|
73
|
+
@options[:selenium_args] = selenium_args
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class RcStopOptions < SeleniumGridOptions
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def initialize_options
|
84
|
+
return OptionParser.new do |opts|
|
85
|
+
opts.banner = "rc:stop"
|
86
|
+
|
87
|
+
opts.on('-p', '--port <port>', "port where the remote control is listening", "\tdefault:\t#{Remote::DEFAULT_PORT}") do |port|
|
88
|
+
@options[:port] = port
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
case ARGV.first
|
95
|
+
when 'hub:start':
|
96
|
+
options = HubStartOptions.new.parse(ARGV)
|
97
|
+
Hub.instance.start(options)
|
98
|
+
when 'hub:stop':
|
99
|
+
Hub.instance.stop
|
100
|
+
when 'rc:start':
|
101
|
+
options = RcStartOptions.new.parse(ARGV)
|
102
|
+
Remote.instance.start(options)
|
103
|
+
when 'rc:stop':
|
104
|
+
options = RcStopOptions.new.parse(ARGV)
|
105
|
+
Remote.instance.stop(options)
|
106
|
+
else
|
107
|
+
puts "Usage: selenium-grid <hub:start|hub:stop|rc:start|rc:stop> [options]"
|
108
|
+
puts ""
|
109
|
+
HubStartOptions.new.summarize
|
110
|
+
RcStartOptions.new.summarize
|
111
|
+
RcStopOptions.new.summarize
|
112
|
+
end
|
data/config/hoe.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
AUTHOR = ['Ryan Dy', 'Corey Innis']
|
2
|
+
EMAIL = "ops+rubyforge@pivotallabs.com"
|
3
|
+
DESCRIPTION = "Selenium Grid Ruby packages Selenium Grid as a gem"
|
4
|
+
GEM_NAME = 'selenium-grid'
|
5
|
+
|
6
|
+
RUBYFORGE_PROJECT = 'selenium-grid'
|
7
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
8
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
9
|
+
|
10
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
11
|
+
@config = nil
|
12
|
+
RUBYFORGE_USERNAME = "unknown"
|
13
|
+
def rubyforge_username
|
14
|
+
unless @config
|
15
|
+
begin
|
16
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
17
|
+
rescue
|
18
|
+
puts <<-EOS
|
19
|
+
ERROR: No rubyforge config file found: #{@config_file}"
|
20
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
21
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
22
|
+
EOS
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
end
|
26
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
27
|
+
end
|
28
|
+
|
29
|
+
RDOC_OPTS = ['--quiet', '--title', 'selenium-grid documentation',
|
30
|
+
"--opname", "index.html",
|
31
|
+
"--line-numbers",
|
32
|
+
"--main", "README",
|
33
|
+
"--inline-source"]
|
34
|
+
|
35
|
+
class Hoe
|
36
|
+
def extra_deps
|
37
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
38
|
+
@extra_deps
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Generate all the Rake tasks
|
43
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
44
|
+
hoe = Hoe.new(GEM_NAME, SeleniumGrid::VERSION::STRING) do |p|
|
45
|
+
p.author = AUTHOR
|
46
|
+
p.email = EMAIL
|
47
|
+
p.description = DESCRIPTION
|
48
|
+
p.summary = DESCRIPTION
|
49
|
+
p.url = HOMEPATH
|
50
|
+
p.rubyforge_name = RUBYFORGE_PROJECT
|
51
|
+
p.test_globs = ["spec/**/*_spec.rb"]
|
52
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
|
53
|
+
p.extra_deps = [
|
54
|
+
["rake", ">=0.8.1"],
|
55
|
+
["hoe", ">=1.7.0"],
|
56
|
+
["newgem", ">=0.23.1"],
|
57
|
+
["lsof", ">=0.3.0"]
|
58
|
+
]
|
59
|
+
|
60
|
+
# == Optional
|
61
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
|
62
|
+
end
|
63
|
+
|
64
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
65
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
66
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w(rake hoe newgem lsof).each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w(.. lib)))
|
16
|
+
|
17
|
+
def require_path(path_from_base)
|
18
|
+
basedir = File.join(File.dirname(__FILE__), '..')
|
19
|
+
|
20
|
+
Dir[File.join(basedir, path_from_base)].each do |file|
|
21
|
+
require file
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'extensions'
|
26
|
+
require 'java'
|
27
|
+
require 'selenium-grid'
|
data/lib/extensions.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_path '/lib/extensions/**/*.rb'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def camelize(first_letter_in_uppercase = true)
|
4
|
+
first_letter_in_uppercase = false if first_letter_in_uppercase == :lower
|
5
|
+
if first_letter_in_uppercase
|
6
|
+
self.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
7
|
+
else
|
8
|
+
self.first + self.camelize[1..-1]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def first
|
15
|
+
self[0, 1]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/java.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_path '/lib/java/**/*.rb'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_path "/lib/extensions/file.rb"
|
2
|
+
|
3
|
+
module Java
|
4
|
+
class Classpath
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
def initialize(root_dir)
|
8
|
+
@root = root_dir
|
9
|
+
@locations = []
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(paths)
|
14
|
+
@locations = (@locations << Dir[@root + '/' + paths]).flatten
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def definition
|
19
|
+
@locations.map {|path| File.native_path(path)}.join(self.separator)
|
20
|
+
end
|
21
|
+
|
22
|
+
def separator
|
23
|
+
PLATFORM['win32'] ? ";" : ":"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/java/vm.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require_path "/lib/extensions/file.rb"
|
2
|
+
|
3
|
+
module Java
|
4
|
+
class VM
|
5
|
+
def run(classname, options = {})
|
6
|
+
command = [ "java" ]
|
7
|
+
include_classpath(command, options)
|
8
|
+
command << classname
|
9
|
+
include_settings(command, options)
|
10
|
+
include_arguments(command, options)
|
11
|
+
include_background(command, options)
|
12
|
+
include_log(command, options)
|
13
|
+
|
14
|
+
sh command.compact.join(' ')
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def include_arguments(command, options)
|
20
|
+
if options[:arguments]
|
21
|
+
command << options[:arguments].collect do |key, value|
|
22
|
+
if key == :selenium_args
|
23
|
+
value.to_s
|
24
|
+
else
|
25
|
+
"-#{key.to_s.camelize(:lower)} #{value}".sort.join(' ')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def include_background(command, options)
|
32
|
+
if options[:background]
|
33
|
+
if RUBY_PLATFORM['win32']
|
34
|
+
command.unshift('start')
|
35
|
+
else
|
36
|
+
command << '&'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def include_classpath(command, options)
|
42
|
+
if options[:classpath]
|
43
|
+
command << "-cp '#{options[:classpath]}'"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def include_log(command, options)
|
48
|
+
if options[:log]
|
49
|
+
command << "> '#{options[:log]}' 2>&1"
|
50
|
+
mkdir_p File.dirname(options[:log])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def include_settings(command, options)
|
55
|
+
if options[:settings]
|
56
|
+
command << options[:settings].collect { |key, value| "-D#{key}=#{value}" }.join(' ')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
require_path '/lib/selenium-grid/**/*.rb'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module SeleniumGrid
|
4
|
+
class Hub
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
HUB_PORT=4444
|
8
|
+
|
9
|
+
def start(overrides = {})
|
10
|
+
classpath = Java::Classpath.new(File.join(File.dirname(__FILE__), %w(.. ..)))
|
11
|
+
classpath = classpath << "." << "lib/openqa/selenium-grid-hub-standalone-*.jar"
|
12
|
+
|
13
|
+
requirements = {
|
14
|
+
:classpath => classpath.definition,
|
15
|
+
:log => File.join(File.dirname(__FILE__), "..", "..", "log", "hub.log")
|
16
|
+
}
|
17
|
+
options = {
|
18
|
+
:background => ENV['BACKGROUND'] || false,
|
19
|
+
}.merge(overrides).merge(requirements)
|
20
|
+
|
21
|
+
Java::VM.new.run "com.thoughtworks.selenium.grid.hub.HubServer", options
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
Lsof.kill(HUB_PORT)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module SeleniumGrid
|
4
|
+
class Remote
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
DEFAULT_BROWSER = "*chrome"
|
8
|
+
DEFAULT_PORT = 5555
|
9
|
+
DEFAULT_HOST = "localhost"
|
10
|
+
DEFAULT_HUB_URL = "http://#{DEFAULT_HOST}:#{Hub::HUB_PORT}",
|
11
|
+
|
12
|
+
def start(overrides = {})
|
13
|
+
classpath = Java::Classpath.new(File.join(File.dirname(__FILE__), %w(.. ..)))
|
14
|
+
classpath = classpath << "." << "lib/openqa/selenium-server-*.jar" << "lib/openqa/selenium-grid-remote-control-standalone-*.jar"
|
15
|
+
args = arguments(overrides.reject { |key, value| key == :background })
|
16
|
+
|
17
|
+
options = {
|
18
|
+
:classpath => classpath.definition,
|
19
|
+
:log => File.join(File.dirname(__FILE__), "..", "..", "log", "rc-#{args[:port]}.log"),
|
20
|
+
:arguments => args,
|
21
|
+
:background => overrides[:background] || ENV['BACKGROUND'] || false,
|
22
|
+
}
|
23
|
+
|
24
|
+
Java::VM.new.run "com.thoughtworks.selenium.grid.remotecontrol.SelfRegisteringRemoteControlLauncher", options
|
25
|
+
end
|
26
|
+
|
27
|
+
def stop(overrides = {})
|
28
|
+
options = {
|
29
|
+
:port => ENV['PORT'] || DEFAULT_PORT
|
30
|
+
}.merge(overrides)
|
31
|
+
Lsof.kill(options[:port].to_i)
|
32
|
+
end
|
33
|
+
|
34
|
+
def arguments(overrides = {})
|
35
|
+
options = {
|
36
|
+
:host => ENV['HOST'] || DEFAULT_HOST,
|
37
|
+
:port => ENV['PORT'] || DEFAULT_PORT,
|
38
|
+
:hub_url => ENV['HUB_URL'] || DEFAULT_HUB_URL,
|
39
|
+
:env => ENV['ENV'] || DEFAULT_BROWSER,
|
40
|
+
:selenium_args => ENV['SELENIUM_ARGS'] || ""
|
41
|
+
}.merge(overrides)
|
42
|
+
options[:env] = "'#{options[:env].gsub(/["']/, '')}'"
|
43
|
+
options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/tasks/hoe.rake
ADDED
data/lib/tasks/hub.rake
ADDED
data/lib/tasks/rc.rake
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
namespace :rc do
|
4
|
+
include SeleniumGrid
|
5
|
+
|
6
|
+
desc "Launch Remote Control. Usage rake rc:start [PORT=#{Remote::DEFAULT_PORT}]"
|
7
|
+
task(:start) do
|
8
|
+
Remote.instance.start
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Stop Remote Control. Usage rake rc:stop [PORT=#{Remote::DEFAULT_PORT}]"
|
12
|
+
task(:stop) do
|
13
|
+
Remote.instance.stop
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "rake"
|
2
|
+
|
3
|
+
desc "Runs the RSpec suite"
|
4
|
+
task :spec => 'spec:all'
|
5
|
+
|
6
|
+
namespace :spec do
|
7
|
+
desc "Runs the RSpec suite"
|
8
|
+
task :all do
|
9
|
+
require_path '/spec/spec_suite.rb'
|
10
|
+
SpecSuite.send('all')
|
11
|
+
end
|
12
|
+
|
13
|
+
%W(extensions java selenium-grid).each do |suite_name|
|
14
|
+
desc "Runs the #{suite_name} spec suite"
|
15
|
+
task suite_name.to_sym do
|
16
|
+
require_path '/spec/spec_suite.rb'
|
17
|
+
SpecSuite.send(suite_name.gsub('-', "_"))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe String do
|
4
|
+
describe "#camelize" do
|
5
|
+
context "when passed a string with no underscores" do
|
6
|
+
context "with no options" do
|
7
|
+
it "returns the string as camelcase with the first character converted to uppercase" do
|
8
|
+
"runonstring".camelize.should == "Runonstring"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with the :upper option" do
|
13
|
+
it "returns the string as camelcase with the first character converted to uppercase" do
|
14
|
+
"runonstring".camelize(:upper).should == "Runonstring"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "with the :lower option" do
|
19
|
+
it "returns the original string" do
|
20
|
+
"runonstring".camelize(:lower).should == "runonstring"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when passed a string with underscores" do
|
26
|
+
context "with no options" do
|
27
|
+
it "returns the string as camelcase" do
|
28
|
+
"underscored_string".camelize.should == "UnderscoredString"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with the :upper option" do
|
33
|
+
it "returns the string as camelcase" do
|
34
|
+
"underscored_string".camelize(:upper).should == "UnderscoredString"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "with the :lower option" do
|
39
|
+
it "returns the string as camelcase" do
|
40
|
+
"underscored_string".camelize(:lower).should == "underscoredString"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/spec_suite"
|
3
|
+
require "#{dir}/spec_helper"
|
4
|
+
|
5
|
+
class ExtensionsSpecSuite < SpecSuite
|
6
|
+
def files
|
7
|
+
Dir["#{dir}/extensions/**/*_spec.rb"]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
if $0 == __FILE__
|
12
|
+
ExtensionsSpecSuite.new.run
|
13
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
module Java
|
4
|
+
describe VM do
|
5
|
+
describe "#run" do
|
6
|
+
attr_reader :vm
|
7
|
+
before do
|
8
|
+
@vm = VM.new
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when passed a classname" do
|
12
|
+
it "shells out to java with the classname as the sole argument" do
|
13
|
+
mock(vm).sh('java test.ClassName')
|
14
|
+
vm.run "test.ClassName"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when passed a classname and options" do
|
19
|
+
context "when the options include :arguments" do
|
20
|
+
it "shells out to java with the arguments" do
|
21
|
+
mock(vm).sh('java test.ClassName -one uno -two dos')
|
22
|
+
vm.run "test.ClassName", { :arguments => { :one => 'uno', :two => 'dos' } }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "converts argument keys to camelCase" do
|
26
|
+
mock(vm).sh('java test.ClassName -oneTwo after')
|
27
|
+
vm.run "test.ClassName", { :arguments => { :one_two => 'after' } }
|
28
|
+
end
|
29
|
+
|
30
|
+
it "passes selenium_args to java as the value only" do
|
31
|
+
mock(vm).sh("java test.ClassName foo")
|
32
|
+
vm.run "test.ClassName", { :arguments => { :selenium_args => "foo"} }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when the options include :background" do
|
37
|
+
it "shells out to java and sends the process to the background" do
|
38
|
+
mock(vm).sh('java test.ClassName &')
|
39
|
+
vm.run "test.ClassName", { :background => true }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when the options include :classpath" do
|
44
|
+
it "shells out to java with the classpath" do
|
45
|
+
mock(vm).sh("java -cp 'lib/one.jar:lib/two.jar' test.ClassName")
|
46
|
+
vm.run "test.ClassName", { :classpath => 'lib/one.jar:lib/two.jar' }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the options include :log" do
|
51
|
+
before do
|
52
|
+
mock(vm).mkdir_p("/var/log")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "shells out to java and redirects output to the specified log file" do
|
56
|
+
mock(vm).sh("java test.ClassName > '/var/log/test.log' 2>&1")
|
57
|
+
vm.run "test.ClassName", { :log => '/var/log/test.log' }
|
58
|
+
end
|
59
|
+
|
60
|
+
it "creates the log directory" do
|
61
|
+
mock(vm).sh("java test.ClassName > '/var/log/test.log' 2>&1")
|
62
|
+
vm.run "test.ClassName", { :log => '/var/log/test.log' }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when the options include :settings for the JVM" do
|
67
|
+
it "shells out to java with the settings flags" do
|
68
|
+
mock(vm).sh("java test.ClassName -Done=uno")
|
69
|
+
vm.run "test.ClassName", { :settings => { :one, 'uno' } }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
module SeleniumGrid
|
4
|
+
describe Hub do
|
5
|
+
attr_reader :hub
|
6
|
+
|
7
|
+
before do
|
8
|
+
@hub = Hub.instance
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#start" do
|
12
|
+
describe "the call to Java::VM#run" do
|
13
|
+
it "includes the expected parameters" do
|
14
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
15
|
+
class_name.should == "com.thoughtworks.selenium.grid.hub.HubServer"
|
16
|
+
options.should include(:classpath)
|
17
|
+
options.should include(:log)
|
18
|
+
options.should include(:background)
|
19
|
+
end
|
20
|
+
hub.start
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when called without options or environment settings" do
|
24
|
+
it "includes the default parameters" do
|
25
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
26
|
+
options[:background].should be_false
|
27
|
+
end
|
28
|
+
hub.start
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when called with environment settings" do
|
33
|
+
before do
|
34
|
+
ENV['BACKGROUND'] = "true"
|
35
|
+
end
|
36
|
+
|
37
|
+
after do
|
38
|
+
ENV.delete('BACKGROUND')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "includes the environment settings as parameters" do
|
42
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
43
|
+
options[:background].should == "true"
|
44
|
+
end
|
45
|
+
hub.start
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when called with options" do
|
50
|
+
it "includes the options as parameters" do
|
51
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
52
|
+
options[:background].should be_true
|
53
|
+
end
|
54
|
+
hub.start(:background => true)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#stop" do
|
61
|
+
it "calls Lsof.kill" do
|
62
|
+
mock(Lsof).kill(Hub::HUB_PORT)
|
63
|
+
hub.stop
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
module SeleniumGrid
|
4
|
+
describe Remote do
|
5
|
+
attr_reader :remote
|
6
|
+
|
7
|
+
before do
|
8
|
+
@remote = Remote.instance
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
%w(port host hub_url env selenium_args background).each do |env|
|
13
|
+
ENV.delete(env.upcase)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#start" do
|
18
|
+
describe "the call to Java::VM#run" do
|
19
|
+
it "includes the expected parameters" do
|
20
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
21
|
+
class_name.should == "com.thoughtworks.selenium.grid.remotecontrol.SelfRegisteringRemoteControlLauncher"
|
22
|
+
options.should include(:classpath)
|
23
|
+
options.should include(:arguments)
|
24
|
+
options.should include(:log)
|
25
|
+
options.should include(:background)
|
26
|
+
end
|
27
|
+
remote.start
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when called without options or environment settings" do
|
31
|
+
it "includes the default parameters" do
|
32
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
33
|
+
options[:background].should be_false
|
34
|
+
options[:arguments][:host].should == Remote::DEFAULT_HOST
|
35
|
+
options[:arguments][:port].should == Remote::DEFAULT_PORT
|
36
|
+
options[:arguments][:hub_url].should == Remote::DEFAULT_HUB_URL
|
37
|
+
options[:arguments][:env].should == "'#{Remote::DEFAULT_BROWSER}'"
|
38
|
+
options[:arguments][:selenium_args].should == ""
|
39
|
+
end
|
40
|
+
remote.start
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when called with environment settings" do
|
45
|
+
before do
|
46
|
+
ENV['BACKGROUND'] = 'true'
|
47
|
+
ENV['PORT'] = "1234"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "includes the environment settings as parameters" do
|
51
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
52
|
+
options[:background].should == "true"
|
53
|
+
options[:arguments][:port].should == "1234"
|
54
|
+
end
|
55
|
+
remote.start
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when called with options" do
|
60
|
+
it "includes the options as parameters" do
|
61
|
+
mock.instance_of(Java::VM).run(anything, anything) do |class_name, options|
|
62
|
+
options[:background].should be_true
|
63
|
+
options[:arguments][:port].should == 1234
|
64
|
+
end
|
65
|
+
remote.start(:background => true, :port => 1234)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#stop" do
|
72
|
+
describe "the call to Lsof.kill" do
|
73
|
+
context "when called without options of environment settings" do
|
74
|
+
it "uses the defaults" do
|
75
|
+
mock(Lsof).kill(Remote::DEFAULT_PORT)
|
76
|
+
remote.stop
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when called with environment settings" do
|
81
|
+
before do
|
82
|
+
ENV['PORT'] = "1234"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "uses the environment settings" do
|
86
|
+
mock(Lsof).kill(ENV['PORT'].to_i)
|
87
|
+
remote.stop
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when called with options" do
|
92
|
+
it "uses the options" do
|
93
|
+
mock(Lsof).kill(1234)
|
94
|
+
remote.stop(:port => 1234)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#args" do
|
101
|
+
attr_reader :args, :defaults
|
102
|
+
before do
|
103
|
+
@defaults = {
|
104
|
+
:host => Remote::DEFAULT_HOST,
|
105
|
+
:port => Remote::DEFAULT_PORT,
|
106
|
+
:hub_url => Remote::DEFAULT_HUB_URL,
|
107
|
+
:env => "'*chrome'",
|
108
|
+
:selenium_args => ''
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when ENV does not contain any relevant options" do
|
113
|
+
before do
|
114
|
+
@args = remote.arguments
|
115
|
+
end
|
116
|
+
|
117
|
+
it "returns a hash of default arguments" do
|
118
|
+
args.should == defaults
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
{
|
123
|
+
:host => 'foobar',
|
124
|
+
:port => 6000,
|
125
|
+
:hub_url => 'http://foobar:7777',
|
126
|
+
:env => "'*safari'",
|
127
|
+
:selenium_args => 'foo'
|
128
|
+
}.each do |key, override|
|
129
|
+
arg_name = key.to_s.upcase
|
130
|
+
context "when ENV includes #{arg_name}" do
|
131
|
+
before do
|
132
|
+
ENV[arg_name] = override.to_s
|
133
|
+
@args = remote.arguments()
|
134
|
+
end
|
135
|
+
|
136
|
+
it "returns a hash with defaults and #{arg_name}" do
|
137
|
+
args.should == defaults.merge(key => override.to_s)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/spec_suite"
|
3
|
+
require "#{dir}/spec_helper"
|
4
|
+
|
5
|
+
class SeleniumGridSpecSuite < SpecSuite
|
6
|
+
def files
|
7
|
+
Dir["#{dir}/selenium-grid/**/*_spec.rb"]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
if $0 == __FILE__
|
12
|
+
SeleniumGridSpecSuite.new.run
|
13
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
data/spec/spec_suite.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
class SpecSuite
|
2
|
+
class << self
|
3
|
+
SUITE_NAMES = %w(extensions java selenium-grid)
|
4
|
+
|
5
|
+
def all
|
6
|
+
SUITE_NAMES.each do |suite_name|
|
7
|
+
send(suite_name.gsub('-', '_'))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
SUITE_NAMES.each do |suite_name|
|
12
|
+
self.send(:define_method, suite_name.gsub('-', '_')) do
|
13
|
+
raise "Failure" unless system(%Q|ruby #{dir}/#{suite_name}_spec_suite.rb|)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def dir
|
18
|
+
@dir ||= File.dirname(__FILE__)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
spec_opts = "#{dir}/spec.opts"
|
24
|
+
ARGV.concat ["--options", spec_opts] if File.exists? spec_opts
|
25
|
+
|
26
|
+
header
|
27
|
+
files.each do |file|
|
28
|
+
require file
|
29
|
+
end
|
30
|
+
|
31
|
+
::Spec::Runner::CommandLine.run
|
32
|
+
end
|
33
|
+
|
34
|
+
def header
|
35
|
+
puts "\nRunning #{self.class}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def files
|
39
|
+
raise NotImplementedError
|
40
|
+
end
|
41
|
+
|
42
|
+
def dir
|
43
|
+
@dir ||= File.dirname(__FILE__)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if $0 == __FILE__
|
48
|
+
SpecSuite.all
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: selenium-grid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Dy
|
8
|
+
- Corey Innis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-10-06 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rake
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.8.1
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: newgem
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.23.1
|
35
|
+
version:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: lsof
|
38
|
+
type: :runtime
|
39
|
+
version_requirement:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 0.3.0
|
45
|
+
version:
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: hoe
|
48
|
+
type: :development
|
49
|
+
version_requirement:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.7.0
|
55
|
+
version:
|
56
|
+
description: Selenium Grid Ruby packages Selenium Grid as a gem
|
57
|
+
email: ops+rubyforge@pivotallabs.com
|
58
|
+
executables:
|
59
|
+
- selenium-grid
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
extra_rdoc_files:
|
63
|
+
- History.txt
|
64
|
+
- Manifest.txt
|
65
|
+
- README.txt
|
66
|
+
files:
|
67
|
+
- History.txt
|
68
|
+
- Manifest.txt
|
69
|
+
- README.txt
|
70
|
+
- Rakefile
|
71
|
+
- bin/selenium-grid
|
72
|
+
- config/hoe.rb
|
73
|
+
- config/requirements.rb
|
74
|
+
- lib/extensions.rb
|
75
|
+
- lib/extensions/file.rb
|
76
|
+
- lib/extensions/rake.rb
|
77
|
+
- lib/extensions/string.rb
|
78
|
+
- lib/java.rb
|
79
|
+
- lib/java/classpath.rb
|
80
|
+
- lib/java/vm.rb
|
81
|
+
- lib/openqa/selenium-grid-hub-standalone-1.0.1.jar
|
82
|
+
- lib/openqa/selenium-grid-remote-control-standalone-1.0.1.jar
|
83
|
+
- lib/openqa/selenium-server-1.0-SNAPSHOT.jar
|
84
|
+
- lib/selenium-grid.rb
|
85
|
+
- lib/selenium-grid/hub.rb
|
86
|
+
- lib/selenium-grid/remote.rb
|
87
|
+
- lib/selenium-grid/version.rb
|
88
|
+
- lib/tasks/hoe.rake
|
89
|
+
- lib/tasks/hub.rake
|
90
|
+
- lib/tasks/rc.rake
|
91
|
+
- lib/tasks/rspec.rake
|
92
|
+
- spec/extensions/string_spec.rb
|
93
|
+
- spec/extensions_spec_suite.rb
|
94
|
+
- spec/java/vm_spec.rb
|
95
|
+
- spec/java_spec_suite.rb
|
96
|
+
- spec/selenium-grid/hub_spec.rb
|
97
|
+
- spec/selenium-grid/remote_spec.rb
|
98
|
+
- spec/selenium-grid_spec_suite.rb
|
99
|
+
- spec/spec.opts
|
100
|
+
- spec/spec_helper.rb
|
101
|
+
- spec/spec_suite.rb
|
102
|
+
has_rdoc: true
|
103
|
+
homepage: http://selenium-grid.rubyforge.org
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options:
|
106
|
+
- --main
|
107
|
+
- README.txt
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
version:
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: "0"
|
121
|
+
version:
|
122
|
+
requirements: []
|
123
|
+
|
124
|
+
rubyforge_project: selenium-grid
|
125
|
+
rubygems_version: 1.2.0
|
126
|
+
signing_key:
|
127
|
+
specification_version: 2
|
128
|
+
summary: Selenium Grid Ruby packages Selenium Grid as a gem
|
129
|
+
test_files:
|
130
|
+
- spec/extensions/string_spec.rb
|
131
|
+
- spec/java/vm_spec.rb
|
132
|
+
- spec/selenium-grid/hub_spec.rb
|
133
|
+
- spec/selenium-grid/remote_spec.rb
|