davidtrogers-selenium-grid 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Dave Rogers
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,10 @@
1
+ Thank you for using Selenium Grid
2
+
3
+ Have a look at :
4
+
5
+ * Website content : ./doc/website/index.html
6
+ * Developer documentation: ./doc directory
7
+
8
+ If you have any problem contact Philippe Hanrigou:
9
+ http://ph7spot.com/about/contact_me
10
+
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = davidtrogers-selenium-grid
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Dave Rogers. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,243 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ #
4
+ # Rakefile managing Selenium Grid components
5
+ #
6
+ require "net/http"
7
+ require "yaml"
8
+ require File.dirname(__FILE__) + '/lib/ruby/tcp_socket_extensions'
9
+ require File.dirname(__FILE__) + '/lib/ruby/file_extensions'
10
+ require File.dirname(__FILE__) + '/lib/ruby/java/classpath'
11
+ require File.dirname(__FILE__) + '/lib/ruby/java/vm'
12
+ require File.dirname(__FILE__) + '/lib/ruby/s_grid/hub'
13
+ require File.dirname(__FILE__) + '/lib/ruby/s_grid/remote_control'
14
+
15
+ begin
16
+ require 'jeweler'
17
+ Jeweler::Tasks.new do |gem|
18
+ gem.name = "davidtrogers-selenium-grid"
19
+ gem.summary = %Q{selenium grid packaged as a gem}
20
+ gem.description = %Q{}
21
+ gem.email = "david.t.rogers@gmail.com"
22
+ # gem.homepage = "http://github.com/davidtrogers/davidtrogers-selenium-grid"
23
+ gem.authors = ["Dave Rogers"]
24
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
25
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
26
+ end
27
+ Jeweler::GemcutterTasks.new
28
+ rescue LoadError
29
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
30
+ end
31
+
32
+ require 'rake/testtask'
33
+ Rake::TestTask.new(:test) do |test|
34
+ test.libs << 'lib' << 'test'
35
+ test.pattern = 'test/**/test_*.rb'
36
+ test.verbose = true
37
+ end
38
+
39
+ begin
40
+ require 'rcov/rcovtask'
41
+ Rcov::RcovTask.new do |test|
42
+ test.libs << 'test'
43
+ test.pattern = 'test/**/test_*.rb'
44
+ test.verbose = true
45
+ end
46
+ rescue LoadError
47
+ task :rcov do
48
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
49
+ end
50
+ end
51
+
52
+ task :test => :check_dependencies
53
+
54
+ task :default => :test
55
+
56
+ require 'rake/rdoctask'
57
+ Rake::RDocTask.new do |rdoc|
58
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
59
+
60
+ rdoc.rdoc_dir = 'rdoc'
61
+ rdoc.title = "davidtrogers-selenium-grid #{version}"
62
+ rdoc.rdoc_files.include('README*')
63
+ rdoc.rdoc_files.include('lib/**/*.rb')
64
+ end
65
+
66
+ desc "Print help"
67
+ task :help do
68
+ puts <<-EOS
69
+
70
+ Rake tasks to manage a Selenium Grid on a *single* machine.
71
+
72
+ NOTE: To manage a Grid accross *multiple* machines use the
73
+ Capistrano recipes provided with Selenium Grid distribution
74
+
75
+
76
+ Start the Hub and 15 Remote Controls
77
+ ------------------------------------
78
+
79
+ rake all:start
80
+
81
+ Stop the Hub and 15 Remote Controls
82
+ -----------------------------------
83
+
84
+ rake all:stop
85
+
86
+ Restart the Hub and 15 Remote Controls
87
+ --------------------------------------
88
+
89
+ rake all:restart
90
+
91
+ Start the Hub with only 10 Remote Controls, ports 5000 to 5010
92
+ --------------------------------------------------------------
93
+
94
+ rake all:restart PORTS=5000-5010
95
+
96
+ Stop them with
97
+
98
+ rake all:stop PORTS=5000-5010
99
+
100
+ Start 5 Remote Controls with the Hub, ports 6500 to 6505
101
+ --------------------------------------------------------
102
+
103
+ rake rc:start_all PORTS=6500-6505
104
+
105
+ Start a single Remote Control on port 6666
106
+ -------------------------------------------
107
+
108
+ rake rc:start PORT=6666
109
+
110
+
111
+ EOS
112
+ end
113
+
114
+ desc "Restart all services (Hub a Remote Controls"
115
+ task :'all:restart' do
116
+ Rake::Task[:'all:stop'].execute([]) rescue nil
117
+ Rake::Task[:'all:start'].execute []
118
+ end
119
+
120
+ desc "Launch all services (Hub a Remote Controls"
121
+ task :'all:start' do
122
+ ENV['BACKGROUND'] = "true"
123
+ Rake::Task[:'hub:start'].execute []
124
+ puts "Waiting for Hub to come up..."
125
+ hub.wait_until_up_and_running
126
+ Rake::Task[:'rc:start_all'].execute []
127
+ end
128
+
129
+ desc "Stop all services (Hub a Remote Controls"
130
+ task :'all:stop' do
131
+ puts "Stopping all Selenium Grid servers..."
132
+ Rake::Task[:'rc:stop_all'].execute []
133
+ Rake::Task[:'hub:stop'].execute [] rescue nil
134
+ end
135
+
136
+ desc "Launch Hub"
137
+ task :'hub:start' do
138
+ SGrid::Hub.new.start \
139
+ :background => ("true" == ENV['BACKGROUND']),
140
+ :log_file => File.native_path(File.dirname(__FILE__) + "/log/hub.log")
141
+ end
142
+
143
+ desc "Stop Hub"
144
+ task :'hub:stop' do
145
+ puts "Shutting down Selenium Grid hub..."
146
+ hub.shutdown rescue EOFError
147
+ end
148
+
149
+ desc "Launch Remote Control"
150
+ task :'rc:start' do
151
+ port = ENV['PORT'] || 5555
152
+ remote_control(:port => port).start \
153
+ :background => ENV['BACKGROUND'],
154
+ :log_file => File.join(File.dirname(__FILE__), "log", "rc-#{port}.log")
155
+ end
156
+
157
+ desc "Stop Remote Control"
158
+ task :'rc:stop' do
159
+ remote_control.stop rescue EOFError
160
+ end
161
+
162
+ desc "Launch Remote Control"
163
+ task :'rc:start_all' do
164
+ ports = ENV['PORTS'] || "5000-5015"
165
+ port_range = Range.new(*ports.split("-"))
166
+ port_range.each do |port|
167
+ remote_control(:port => port, :background => true).start \
168
+ :background => true,
169
+ :log_file => File.join(File.dirname(__FILE__), "log", "rc-#{port}.log")
170
+ end
171
+ end
172
+
173
+ desc"Stop Remote Controls. Usage rake rc:stop PORTS=5555-5560"
174
+ task :'rc:stop_all' do
175
+ ports = ENV['PORTS'] || "5000-5015"
176
+ port_range = Range.new(*ports.split("-"))
177
+ port_range.each do |port|
178
+ begin
179
+ puts "Stopping Remote Control on port #{port}"
180
+ rc = SGrid::RemoteControl.new :host => ENV['HOST'] || "localhost",
181
+ :port => port
182
+ rc.shutdown
183
+ rescue Exception => e
184
+ STDERR.puts "Could not properly shutdown remote control #{port} : #{e}"
185
+ end
186
+ end
187
+ end
188
+
189
+ desc "Launch a Xvnc server"
190
+ task :'xvnc:start' do
191
+ sh "Xvnc :1 -alwaysshared -geometry 1280x1024 -depth 24 -desktop 'Selenium Grid' 2>&1 >#{File.join(File.dirname(__FILE__), "log", "X.log")} &"
192
+ end
193
+
194
+ desc "Fully Automated Demo (for continuous integration)"
195
+ task :'ci:demo' do
196
+ begin
197
+ Rake::Task["all:restart"].execute []
198
+ sh "ant run-demo-in-parallel" unless running_on_openqa_servers
199
+ sh "ant run-demo-in-sequence"
200
+ ensure
201
+ Rake::Task["all:stop"].execute []
202
+ end
203
+ end
204
+
205
+ desc "Fully Automated Ruby Example (for continuous integration)"
206
+ task :'ci:ruby-example' do
207
+ begin
208
+ Rake::Task["all:restart"].execute []
209
+ sh "(cd examples/ruby; rake tests:run_in_parallel)" unless running_on_openqa_servers
210
+ sh "(cd examples/ruby; rake tests:run_in_sequence)"
211
+ ensure
212
+ Rake::Task["all:stop"].execute []
213
+ end
214
+ end
215
+
216
+ def config
217
+ @config ||= YAML.load(File.read(File.dirname(__FILE__) + "/grid_configuration.yml"))
218
+ end
219
+
220
+ def hub_port
221
+ (ENV["HUB_PORT"] || config["hub"]["port"]).to_i
222
+ end
223
+
224
+ def hub
225
+ SGrid::Hub.new :port => hub_port
226
+ end
227
+
228
+ def remote_control(options={})
229
+ SGrid::RemoteControl.new(
230
+ :host => ENV['HOST'] || "localhost",
231
+ :port => (options[:port] || ENV['PORT'] || 5555),
232
+ :hub_url => (ENV['HUB_URL'] || "http://localhost:#{hub_port}"),
233
+ :shutdown_command => ENV['RC_SHUTDOWN_COMMAND'])
234
+ end
235
+
236
+ # Network is slow as hell on these VMs
237
+ def running_on_openqa_servers
238
+ begin
239
+ not `hostname -s`.grep(/(xserve|osxvm)/).empty?
240
+ rescue Exception
241
+ false
242
+ end
243
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,35 @@
1
+ module SeleniumGrid
2
+ module AWS
3
+
4
+ class Cloud
5
+ FILE = "cloud.yml"
6
+ attr_accessor :hub, :farms
7
+
8
+ def self.load
9
+ begin
10
+ YAML.load(File.read(FILE))
11
+ rescue Errno::ENOENT
12
+ new
13
+ end
14
+ end
15
+
16
+ def self.update
17
+ cloud = self.load
18
+ yield cloud
19
+ ensure
20
+ cloud.write unless cloud.nil?
21
+ end
22
+
23
+ def write
24
+ File.open(FILE, "w") {|file| file.write(self.to_yaml)}
25
+ end
26
+
27
+ def farms
28
+ @farms ||= []
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require "yaml"
3
+ require File.dirname(__FILE__) + '/cloud'
4
+ require File.dirname(__FILE__) + '/ec2_client'
5
+ require File.dirname(__FILE__) + '/server'
6
+ require File.dirname(__FILE__) + '/hub'
7
+ require File.dirname(__FILE__) + '/remote_command'
@@ -0,0 +1,54 @@
1
+ module SeleniumGrid
2
+ module AWS
3
+ module Ec2Client
4
+
5
+ def describe(instance_id)
6
+ output = ec2_shell "ec2-describe-instances #{instance_id}"
7
+ output =~ /INSTANCE\s+(i-.*)$/
8
+ fields = $1.split(/\s+/)
9
+ if output =~ /running/
10
+ {:instance_id => fields[0],
11
+ :ami => fields[1],
12
+ :public_dns => fields[2],
13
+ :private_dns => fields[3],
14
+ :status => fields[4] }
15
+ else
16
+ {:instance_id => fields[0],
17
+ :ami => fields[1],
18
+ :status => fields[2] }
19
+ end
20
+ end
21
+
22
+ def launch(ami, options ={})
23
+ output = ec2_shell "ec2-run-instances #{ami} -k #{options[:keypair]}"
24
+ output =~ /INSTANCE\s+(i-\S+)\s+ami-/
25
+ $1
26
+ end
27
+
28
+ def shutdown(instance_id)
29
+ ec2_shell "ec2-terminate-instances #{instance_id}"
30
+ end
31
+
32
+ def version
33
+ ec2_shell "ec2-version"
34
+ end
35
+
36
+ def authorize_port(port)
37
+ puts "Opening port #{port}..."
38
+ ec2_shell "ec2-authorize default -p #{port}"
39
+ end
40
+
41
+ def ec2_shell(command)
42
+ puts "[EC2] '#{command}'" if tracing?
43
+ output = `${EC2_HOME}/bin/#{command}`
44
+ puts "[EC2] #{output}" if tracing?
45
+ output
46
+ end
47
+
48
+ def tracing?
49
+ ENV['TRACE_EC2_COMMANDS']
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,22 @@
1
+ module SeleniumGrid
2
+ module AWS
3
+
4
+ class Hub < Server
5
+
6
+ def url
7
+ "http://#{public_dns}:4444"
8
+ end
9
+
10
+ def private_url
11
+ "http://#{private_dns}:4444"
12
+ end
13
+
14
+ def console_url
15
+ "#{url}/console"
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+
@@ -0,0 +1,47 @@
1
+ module SeleniumGrid
2
+ module AWS
3
+
4
+ class RemoteCommand
5
+ attr_accessor :options
6
+
7
+ def initialize(command, options={})
8
+ @command, @options = command, options
9
+ end
10
+
11
+ def execute
12
+ puts full_command
13
+ system full_command
14
+ raise "Error with #{full_command}" if 0 != $?
15
+ end
16
+
17
+ def full_command
18
+ cmd = "#{ssh_command} "
19
+ cmd << "\"su -l #{options[:su]} -c " if options[:su]
20
+ cmd << "'#{remote_command}'"
21
+ cmd << '"' if options[:su]
22
+ cmd
23
+ end
24
+
25
+ def ssh_command
26
+ shell_command = [ "ssh" ]
27
+ shell_command << "-i '#{options[:keypair]}'" if options[:keypair]
28
+ shell_command << "root@#{options[:host]}"
29
+
30
+ shell_command.join " "
31
+ end
32
+
33
+ def remote_command
34
+ shell_command = []
35
+ shell_command << "PATH=#{options[:path]}:${PATH}; export PATH;" if options[:path]
36
+ shell_command << "DISPLAY=#{options[:display]}; export DISPLAY;" if options[:display]
37
+ shell_command << "cd '#{options[:pwd]}';" if options[:pwd]
38
+ shell_command << @command
39
+
40
+ shell_command.join " "
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
47
+
@@ -0,0 +1,56 @@
1
+ module SeleniumGrid
2
+ module AWS
3
+
4
+ class Server
5
+ extend Ec2Client
6
+
7
+ attr_accessor :instance_id, :public_dns, :private_dns
8
+
9
+ def initialize(instance_id)
10
+ self.instance_id = instance_id
11
+ end
12
+
13
+ def self.boot(ami, options = {})
14
+ new launch(ami, options)
15
+ end
16
+
17
+ def self.boot_and_acquire_dns(ami, options)
18
+ server = boot(ami, options)
19
+ server.wait_for_dns
20
+ end
21
+
22
+ def wait_for_dns
23
+ puts "Fetching DNS Info..."
24
+ until dns_allocated?
25
+ sleep 2
26
+ putc "."
27
+ refresh_status
28
+ end
29
+ puts
30
+ self
31
+ end
32
+
33
+ def dns_allocated?
34
+ public_dns != nil && public_dns != "" &&
35
+ private_dns != nil && private_dns != ""
36
+ end
37
+
38
+ def refresh_status
39
+ info = self.class.describe instance_id
40
+ @public_dns = info[:public_dns]
41
+ @private_dns = info[:private_dns]
42
+ end
43
+
44
+ def shutdown
45
+ self.class.shutdown instance_id
46
+ end
47
+
48
+ def run(command, options)
49
+ command = RemoteCommand.new command, options.merge(:host => public_dns)
50
+ command.execute
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ Dir['**/*_test.rb'].each {|test_file| require test_file }
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ unit_tests do
4
+
5
+ test "hub is nil on a fresh cloud" do
6
+ assert_nil SeleniumGrid::AWS::Cloud.new.hub
7
+ end
8
+
9
+ test "hub return the latest assigned hub instance" do
10
+ cloud = SeleniumGrid::AWS::Cloud.new
11
+ cloud.hub = :old_hub
12
+ cloud.hub = :new_hub
13
+ assert_equal :new_hub, cloud.hub
14
+ end
15
+
16
+ test "remote_control_farms is empty on a fresh cloud" do
17
+ assert_equal [], SeleniumGrid::AWS::Cloud.new.farms
18
+ end
19
+
20
+ test "remote_control_farms returns all added farms" do
21
+ cloud = SeleniumGrid::AWS::Cloud.new
22
+ cloud.farms << :a_farm
23
+ cloud.farms << :another_farm
24
+ assert_equal [:a_farm, :another_farm], cloud.farms
25
+ end
26
+
27
+ end
@@ -0,0 +1,137 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ unit_tests do
4
+
5
+ test "run_instance launch a new AMI using ec2-run-instances script" do
6
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
7
+ client.expects(:ec2_shell).with("ec2-run-instances TheAMI -k TheKeyPair")
8
+ client.launch "TheAMI", :keypair => "TheKeyPair"
9
+ end
10
+
11
+ test "run_instance returns the instance id when launch is successful" do
12
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
13
+ client.stubs(:ec2_shell).returns(<<-EOS)
14
+ RESERVATION r-ee629587 069216575636 default
15
+ INSTANCE i-6fef1006 ami-d306e3ba pending grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
16
+ EOS
17
+ assert_equal "i-6fef1006", client.launch(:an_ami)
18
+ end
19
+
20
+ test "authorize launch ec2-authorize script for default group" do
21
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
22
+ client.expects(:ec2_shell).with("ec2-authorize default -p ThePort")
23
+ client.authorize_port "ThePort"
24
+ end
25
+
26
+ test "describe launch ec2-describe script for a particular AMI" do
27
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
28
+ client.expects(:ec2_shell).with("ec2-describe-instances TheAMI").returns("INSTANCE i-")
29
+ client.describe "TheAMI"
30
+ end
31
+
32
+ test "describe returns the instance id when running" do
33
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
34
+ client.stubs(:ec2_shell).returns(<<-EOS)
35
+ RESERVATION r-ee629587 069216575636 default
36
+ INSTANCE i-6fef1006 ami-d306e3ba ec2-67-202-19-143.compute-1.amazonaws.com domU-12-31-38-00-3D-E6.compute-1.internal running grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
37
+ EOS
38
+ assert_equal "i-6fef1006", client.describe(:an_ami)[:instance_id]
39
+ end
40
+
41
+ test "describe returns the ami when running" do
42
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
43
+ client.stubs(:ec2_shell).returns(<<-EOS)
44
+ RESERVATION r-ee629587 069216575636 default
45
+ INSTANCE i-6fef1006 ami-d306e3ba ec2-67-202-19-143.compute-1.amazonaws.com domU-12-31-38-00-3D-E6.compute-1.internal running grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
46
+ EOS
47
+ assert_equal "ami-d306e3ba", client.describe(:an_ami)[:ami]
48
+ end
49
+
50
+ test "describe returns the public_dns when running" do
51
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
52
+ client.stubs(:ec2_shell).returns(<<-EOS)
53
+ RESERVATION r-ee629587 069216575636 default
54
+ INSTANCE i-6fef1006 ami-d306e3ba ec2-67-202-19-143.compute-1.amazonaws.com domU-12-31-38-00-3D-E6.compute-1.internal running grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
55
+ EOS
56
+ assert_equal "ec2-67-202-19-143.compute-1.amazonaws.com",
57
+ client.describe(:an_ami)[:public_dns]
58
+ end
59
+
60
+ test "describe returns the private_dns when running" do
61
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
62
+ client.stubs(:ec2_shell).returns(<<-EOS)
63
+ RESERVATION r-ee629587 069216575636 default
64
+ INSTANCE i-6fef1006 ami-d306e3ba ec2-67-202-19-143.compute-1.amazonaws.com domU-12-31-38-00-3D-E6.compute-1.internal running grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
65
+ EOS
66
+ assert_equal "domU-12-31-38-00-3D-E6.compute-1.internal",
67
+ client.describe(:an_ami)[:private_dns]
68
+ end
69
+
70
+ test "describe returns the status when running" do
71
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
72
+ client.stubs(:ec2_shell).returns(<<-EOS)
73
+ RESERVATION r-ee629587 069216575636 default
74
+ INSTANCE i-6fef1006 ami-d306e3ba ec2-67-202-19-143.compute-1.amazonaws.com domU-12-31-38-00-3D-E6.compute-1.internal running grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
75
+ EOS
76
+ assert_equal "running", client.describe(:an_ami)[:status]
77
+ end
78
+
79
+ test "describe returns the instance id when terminated" do
80
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
81
+ client.stubs(:ec2_shell).returns(<<-EOS)
82
+ RESERVATION r-ee629587 069216575636 default
83
+ INSTANCE i-6fef1006 ami-d306e3ba terminated grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
84
+ EOS
85
+ assert_equal "i-6fef1006", client.describe(:an_ami)[:instance_id]
86
+ end
87
+
88
+ test "describe returns the status when pending" do
89
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
90
+ client.stubs(:ec2_shell).returns(<<-EOS)
91
+ RESERVATION r-40609729 069216575636 default
92
+ INSTANCE i-afee11c6 ami-6801e401 pending grid-keypair 0 m1.small 2008-02-17T22:33:38+0000
93
+ EOS
94
+ assert_equal "pending", client.describe(:an_ami)[:status]
95
+ end
96
+
97
+ test "describe returns a nil public dns the status when pending" do
98
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
99
+ client.stubs(:ec2_shell).returns(<<-EOS)
100
+ RESERVATION r-40609729 069216575636 default
101
+ INSTANCE i-afee11c6 ami-6801e401 pending grid-keypair 0 m1.small 2008-02-17T22:33:38+0000
102
+ EOS
103
+ assert_nil client.describe(:an_ami)[:public_dns]
104
+ end
105
+
106
+ test "describe returns a nil private dns the status when pending" do
107
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
108
+ client.stubs(:ec2_shell).returns(<<-EOS)
109
+ RESERVATION r-40609729 069216575636 default
110
+ INSTANCE i-afee11c6 ami-6801e401 pending grid-keypair 0 m1.small 2008-02-17T22:33:38+0000
111
+ EOS
112
+ assert_nil client.describe(:an_ami)[:private_dns]
113
+ end
114
+
115
+ test "describe returns the status when terminated" do
116
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
117
+ client.stubs(:ec2_shell).returns(<<-EOS)
118
+ RESERVATION r-ee629587 069216575636 default
119
+ INSTANCE i-6fef1006 ami-d306e3ba terminated grid-keypair 0 m1.small 2008-02-17T20:49:08+0000
120
+ EOS
121
+ assert_equal "terminated", client.describe(:an_ami)[:status]
122
+ end
123
+
124
+ test "shutdown terminates an instance" do
125
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
126
+ client.expects(:ec2_shell).with("ec2-terminate-instances The-Instance-ID")
127
+ client.shutdown("The-Instance-ID")
128
+ end
129
+
130
+ test "version returns EC2 version using defined keypair" do
131
+ client = Class.new.extend SeleniumGrid::AWS::Ec2Client
132
+ client.expects(:ec2_shell).with("ec2-version").returns(:ec2_version)
133
+ assert_equal :ec2_version, client.version
134
+ end
135
+
136
+ # ec2-version -K "${EC2_PRIVATE_KEY}"
137
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ unit_tests do
4
+
5
+ test "url return the public url where the hub can be contacted" do
6
+ hub = SeleniumGrid::AWS::Hub.new nil
7
+ hub.public_dns = "public.dns"
8
+ assert_equal "http://public.dns:4444", hub.url
9
+ end
10
+
11
+ test "private_url return the private url where the hub can be contacted" do
12
+ hub = SeleniumGrid::AWS::Hub.new nil
13
+ hub.private_dns = "private.dns"
14
+ assert_equal "http://private.dns:4444", hub.private_url
15
+ end
16
+
17
+ test "console_url return the public url of the hub console" do
18
+ hub = SeleniumGrid::AWS::Hub.new nil
19
+ hub.public_dns = "public.dns"
20
+ assert_equal "http://public.dns:4444/console", hub.console_url
21
+ end
22
+
23
+
24
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ unit_tests do
4
+
5
+ test "ssh_command builds ssh based command targetting the host" do
6
+ command = SeleniumGrid::AWS::RemoteCommand.new "ls", :host => "the.host"
7
+ assert_equal "ssh root@the.host", command.ssh_command
8
+ end
9
+
10
+ test "ssh_command use custom key when keypair options is provided" do
11
+ command = SeleniumGrid::AWS::RemoteCommand.new "ls",
12
+ :host => "the.host", :keypair => "/the/key.pair"
13
+ assert_equal "ssh -i '/the/key.pair' root@the.host", command.ssh_command
14
+ end
15
+
16
+ test "remote_command" do
17
+ command = SeleniumGrid::AWS::RemoteCommand.new "ls", :pwd => "/a/directory"
18
+ assert_equal "cd '/a/directory'; ls", command.remote_command
19
+ end
20
+
21
+ test "remote_command set path when path is provided as an option" do
22
+ command = SeleniumGrid::AWS::RemoteCommand.new "ls", :path => "/a/directory:and/another"
23
+ assert_equal "PATH=/a/directory:and/another:${PATH}; export PATH; ls", command.remote_command
24
+ end
25
+
26
+ test "remote_command set display when display is provided as an option" do
27
+ command = SeleniumGrid::AWS::RemoteCommand.new "ls", :display => ":0"
28
+ assert_equal "DISPLAY=:0; export DISPLAY; ls", command.remote_command
29
+ end
30
+
31
+ test "full_command execute the remote command using ssh_command" do
32
+ command = SeleniumGrid::AWS::RemoteCommand.new nil
33
+ command.stubs(:ssh_command).returns("the_ssh_command")
34
+ command.stubs(:remote_command).returns("the remote command")
35
+ assert_equal "the_ssh_command 'the remote command'", command.full_command
36
+ end
37
+
38
+ test "full_command wraps remote_command with 'su user -c' when su option is set" do
39
+ command = SeleniumGrid::AWS::RemoteCommand.new nil, :su => "a-user"
40
+ command.stubs(:ssh_command).returns("the_ssh_command")
41
+ command.stubs(:remote_command).returns("the remote command")
42
+ assert_equal "the_ssh_command \"su -l a-user -c 'the remote command'\"",
43
+ command.full_command
44
+ end
45
+
46
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ unit_tests do
4
+
5
+ test "refresh_status updates public dns" do
6
+ server = SeleniumGrid::AWS::Server.new :an_instance_id
7
+ SeleniumGrid::AWS::Server.expects(:describe).with(:an_instance_id).
8
+ returns(:public_dns => :new_public_dns)
9
+ server.refresh_status
10
+ assert_equal :new_public_dns, server.public_dns
11
+ end
12
+
13
+ test "refresh_status updates private dns" do
14
+ server = SeleniumGrid::AWS::Server.new :an_instance_id
15
+ SeleniumGrid::AWS::Server.expects(:describe).with(:an_instance_id).
16
+ returns(:private_dns => :new_private_dns)
17
+ server.refresh_status
18
+ assert_equal :new_private_dns, server.private_dns
19
+ end
20
+
21
+
22
+ end
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + "/../../lib/selenium_grid/aws/ec2"
2
+ require "rubygems"
3
+ require "dust"
4
+ require "mocha"
@@ -0,0 +1,16 @@
1
+ module FlickrExample
2
+
3
+ def run_flickr_scenario(options)
4
+ browser.open "/"
5
+ page.location.should match(%r{http://images.google.com/})
6
+ page.type "q", options[:search_string]
7
+ page.click "btnG", :wait_for => :page
8
+ page.click "link=Advanced Image Search", :wait_for => :page
9
+ page.click "rimgtype4"
10
+ page.click "sf"
11
+ page.select "imgc", "full color"
12
+ page.click "btnG", :wait_for => :page
13
+ page.text?(options[:search_string].split(/ /).first).should be_true
14
+ end
15
+
16
+ end
@@ -0,0 +1,13 @@
1
+ module ArrayExtension
2
+
3
+ def /(number_of_buckets)
4
+ buckets = (1..number_of_buckets).collect { [] }
5
+ while self.any? do
6
+ buckets.each do |bucket|
7
+ bucket << self.shift if self.any?
8
+ end
9
+ end
10
+ buckets
11
+ end
12
+
13
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/array_extension')
2
+ Array.send :include, ArrayExtension
3
+
4
+ class MultiProcessSpecRunner
5
+
6
+ def initialize(max_concurrent_processes = 10)
7
+ @max_concurrent_processes = max_concurrent_processes
8
+ end
9
+
10
+ def run(spec_files)
11
+ concurrent_processes = [ @max_concurrent_processes, spec_files.size ].min
12
+ spec_files_by_process = spec_files / concurrent_processes
13
+ concurrent_processes.times do |i|
14
+ cmd = "spec #{spec_files_by_process[i].join(' ')}"
15
+ puts "Launching #{cmd}"
16
+ exec(cmd) if fork == nil
17
+ end
18
+ success = true
19
+ concurrent_processes.times do |i|
20
+ pid, status = Process.wait2
21
+ puts "Test process ##{i} with pid #{pid} completed with #{status}"
22
+ success &&= status.exitstatus.zero?
23
+ end
24
+
25
+ raise "Build failed" unless success
26
+ end
27
+
28
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
+
3
+ describe "Paris" do
4
+ include FlickrExample
5
+
6
+ it "Has museums" do
7
+ run_flickr_scenario :search_string => "Louvre"
8
+ end
9
+
10
+ it "Has bridges" do
11
+ run_flickr_scenario :search_string => "Pont Neuf"
12
+ end
13
+
14
+ it "Has magnific cathedrals" do
15
+ run_flickr_scenario :search_string => "Notre Dame de Paris"
16
+ end
17
+
18
+ it "Has magnificent Castles" do
19
+ run_flickr_scenario :search_string => "Versailles"
20
+ end
21
+
22
+ it "Has a gorgeous river" do
23
+ run_flickr_scenario :search_string => "Seine by Night"
24
+ end
25
+
26
+ it "Has weird towers" do
27
+ run_flickr_scenario :search_string => "Tour Eiffel"
28
+ end
29
+
30
+ it "Has avenues" do
31
+ run_flickr_scenario :search_string => "Avenue des Champs Elysees"
32
+ end
33
+
34
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
+
3
+ describe "Perigord" do
4
+ include FlickrExample
5
+
6
+ it "Has magnific cro-magnon paintings" do
7
+ run_flickr_scenario :search_string => "lascaux hall of the bull"
8
+ end
9
+
10
+ it "Has magnific cities" do
11
+ run_flickr_scenario :search_string => "Sarlat"
12
+ end
13
+
14
+ it "Has magnific cathedrals" do
15
+ run_flickr_scenario :search_string => "Cathedral in Périgueux"
16
+ end
17
+
18
+ it "Has great wines" do
19
+ run_flickr_scenario :search_string => "Montbazillac"
20
+ end
21
+
22
+ end
@@ -0,0 +1,59 @@
1
+ $:.unshift
2
+
3
+ require "rubygems"
4
+ gem "rspec", "=1.1.8"
5
+ require 'spec/rake/spectask'
6
+
7
+ require "rake"
8
+
9
+ gem "selenium-client", "=1.2.7"
10
+ require "selenium/rake/tasks"
11
+ require "selenium/client"
12
+ require "selenium/rspec/spec_helper"
13
+
14
+ require File.expand_path(File.dirname(__FILE__) + "/flickr_example")
15
+
16
+ Spec::Runner.configure do |config|
17
+
18
+ config.before(:each) do
19
+ create_selenium_driver
20
+ start_new_browser_session
21
+ end
22
+
23
+ # The system capture need to happen BEFORE the closing the Selenium session
24
+ config.append_after(:each) do
25
+ @selenium_driver.close_current_browser_session
26
+ end
27
+
28
+ def start_new_browser_session
29
+ @selenium_driver.start_new_browser_session
30
+ @selenium_driver.set_context "Starting example '#{self.description}'"
31
+ end
32
+
33
+ def selenium_driver
34
+ @selenium_driver
35
+ end
36
+
37
+ def browser
38
+ @selenium_driver
39
+ end
40
+
41
+ def page
42
+ @selenium_driver
43
+ end
44
+
45
+ def create_selenium_driver
46
+ remote_control_server = ENV['SELENIUM_RC_HOST'] || "localhost"
47
+ port = ENV['SELENIUM_RC_PORT'] || 4444
48
+ browser = ENV['SELENIUM_RC_BROWSER'] || "*firefox"
49
+ timeout = ENV['SELENIUM_RC_TIMEOUT'] || 200
50
+ application_host = ENV['SELENIUM_APPLICATION_HOST'] || "images.google.com"
51
+ application_port = ENV['SELENIUM_APPLICATION_PORT'] || "80"
52
+
53
+ @selenium_driver = Selenium::Client::Driver.new(
54
+ remote_control_server, port, browser,
55
+ "http://#{application_host}:#{application_port}", timeout)
56
+ end
57
+
58
+ end
59
+
File without changes
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'davidtrogers-selenium-grid'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestDavidtrogersSeleniumGrid < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: davidtrogers-selenium-grid
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Dave Rogers
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-02-24 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thoughtbot-shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: ""
33
+ email: david.t.rogers@gmail.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - LICENSE
40
+ - README
41
+ - README.rdoc
42
+ files:
43
+ - .document
44
+ - .gitignore
45
+ - LICENSE
46
+ - README.rdoc
47
+ - Rakefile
48
+ - VERSION
49
+ - lib/davidtrogers-selenium-grid.rb
50
+ - test/helper.rb
51
+ - test/test_davidtrogers-selenium-grid.rb
52
+ - README
53
+ has_rdoc: true
54
+ homepage:
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.6
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: selenium grid packaged as a gem
83
+ test_files:
84
+ - test/helper.rb
85
+ - test/test_davidtrogers-selenium-grid.rb
86
+ - examples/ec2/lib/selenium_grid/aws/cloud.rb
87
+ - examples/ec2/lib/selenium_grid/aws/ec2.rb
88
+ - examples/ec2/lib/selenium_grid/aws/ec2_client.rb
89
+ - examples/ec2/lib/selenium_grid/aws/hub.rb
90
+ - examples/ec2/lib/selenium_grid/aws/remote_command.rb
91
+ - examples/ec2/lib/selenium_grid/aws/server.rb
92
+ - examples/ec2/test/unit/all_test.rb
93
+ - examples/ec2/test/unit/cloud_test.rb
94
+ - examples/ec2/test/unit/ec2_client_test.rb
95
+ - examples/ec2/test/unit/hub_test.rb
96
+ - examples/ec2/test/unit/remote_command_test.rb
97
+ - examples/ec2/test/unit/server_test.rb
98
+ - examples/ec2/test/unit/test_helper.rb
99
+ - examples/ruby/flickr_example.rb
100
+ - examples/ruby/lib/array_extension.rb
101
+ - examples/ruby/lib/multi_process_behaviour_runner.rb
102
+ - examples/ruby/paris_spec.rb
103
+ - examples/ruby/perigord_spec.rb
104
+ - examples/ruby/spec_helper.rb