davidtrogers-selenium-grid 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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