saucelabs-adapter 0.8.22 → 0.8.24
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/README.markdown +44 -0
- data/Rakefile +7 -31
- data/VERSION +1 -1
- data/generators/saucelabs_adapter/templates/jsunit.rake +1 -1
- data/generators/saucelabs_adapter/templates/jsunit_suite_example.rb +2 -1
- data/generators/saucelabs_adapter/templates/selenium.yml +8 -4
- data/generators/saucelabs_adapter/templates/selenium_suite.rb +2 -1
- data/lib/saucelabs_adapter.rb +0 -3
- data/lib/saucelabs_adapter/jsunit_selenium_support.rb +1 -1
- data/lib/saucelabs_adapter/rspec_adapter.rb +29 -9
- data/lib/saucelabs_adapter/selenium_config.rb +12 -7
- data/lib/saucelabs_adapter/test_unit_adapter.rb +16 -23
- data/lib/saucelabs_adapter/utilities.rb +30 -1
- data/lib/saucerest-ruby/README.md +46 -0
- data/lib/saucerest-ruby/listtunnels.rb +9 -0
- data/lib/saucerest-ruby/tunnel.rb +191 -0
- metadata +12 -9
data/README.markdown
CHANGED
@@ -78,6 +78,50 @@ Getting Started - JsUnit test suite
|
|
78
78
|
|
79
79
|
rake jsunit:selenium_rc:sauce
|
80
80
|
|
81
|
+
RSpec + Rails
|
82
|
+
-------------
|
83
|
+
|
84
|
+
Testing with RSpec + Rails? No problem. Add the following to your spec_helper.rb
|
85
|
+
|
86
|
+
ENV['SELENIUM_ENV'] ||= 'saucelabs'
|
87
|
+
require 'selenium/client'
|
88
|
+
require 'saucelabs_adapter'
|
89
|
+
require 'saucelabs_adapter/rspec_adapter'
|
90
|
+
|
91
|
+
Note the environment variable must be set before the requiring of saucelabs_adapter.
|
92
|
+
This can be set to `'local'` to use a local selenium server.
|
93
|
+
|
94
|
+
Example Test
|
95
|
+
------------
|
96
|
+
|
97
|
+
*spec/views/index_spec.rb*
|
98
|
+
|
99
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
100
|
+
|
101
|
+
describe 'Google Search' do
|
102
|
+
it 'can find Google' do
|
103
|
+
@browser.open '/'
|
104
|
+
@browser.title.should eql('Google')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
Tests are run as normal through `rake spec`. A tunnel is launched at the beginning of
|
109
|
+
each test, if those settings are not commented out.
|
110
|
+
|
111
|
+
Parallel Testing
|
112
|
+
----------------
|
113
|
+
|
114
|
+
Once you have `rake spec` set up to run your selenium tests by following instructions
|
115
|
+
above, you can parallelize them installing the `parallel_tests` plugin from
|
116
|
+
[http://github.com/grosser/parallel_tests][parallel]
|
117
|
+
|
118
|
+
From there, `rake parallel:spec[4]` runs your tests. One known issue is if
|
119
|
+
tunnels are being used, one tunnel is spawned up for each process, which may
|
120
|
+
be more lengthy.
|
121
|
+
|
122
|
+
[parallel]: http://github.com/grosser/parallel_tests
|
123
|
+
|
124
|
+
|
81
125
|
What You Should See
|
82
126
|
-------------------
|
83
127
|
|
data/Rakefile
CHANGED
@@ -25,37 +25,13 @@ begin
|
|
25
25
|
gem.homepage = "http://github.com/pivotal/saucelabs-adapter"
|
26
26
|
gem.authors = ["Kelly Felkins, Chad Woolley, Sam Pierson, Nate Clark"]
|
27
27
|
gem.files = [
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
"lib/saucelabs_adapter/run_utils.rb",
|
36
|
-
"lib/saucelabs_adapter/tunnel.rb",
|
37
|
-
"lib/saucelabs_adapter/tunnels/sauce_tunnel.rb",
|
38
|
-
"lib/saucelabs_adapter/tunnels/ssh_tunnel.rb",
|
39
|
-
"lib/saucelabs_adapter/tunnels/other_tunnel.rb",
|
40
|
-
"lib/saucelabs_adapter/selenium_config.rb",
|
41
|
-
"lib/saucelabs_adapter/test_unit_adapter.rb",
|
42
|
-
"lib/saucelabs_adapter/rspec_adapter.rb",
|
43
|
-
"lib/saucelabs_adapter/jsunit_selenium_support.rb",
|
44
|
-
"lib/saucerest-ruby/saucerest.rb",
|
45
|
-
"lib/saucerest-ruby/gateway.rb",
|
46
|
-
"lib/saucerest-python/tunnel.py",
|
47
|
-
"lib/saucerest-python/daemon.py",
|
48
|
-
"lib/saucerest-python/saucerest.py",
|
49
|
-
"lib/saucerest-python/sshtunnel.py",
|
50
|
-
"lib/tasks/jsunit.rake",
|
51
|
-
"generators/saucelabs_adapter/saucelabs_adapter_generator.rb",
|
52
|
-
"generators/saucelabs_adapter/templates/sample_webrat_test.rb",
|
53
|
-
"generators/saucelabs_adapter/templates/selenium.yml",
|
54
|
-
"generators/saucelabs_adapter/templates/selenium_suite.rb",
|
55
|
-
"generators/saucelabs_adapter/templates/saucelabs_adapter.rake",
|
56
|
-
"generators/saucelabs_adapter/templates/jsunit.rake",
|
57
|
-
"generators/saucelabs_adapter/templates/jsunit_suite_example.rb"
|
58
|
-
]
|
28
|
+
"LICENSE",
|
29
|
+
"README.rdoc",
|
30
|
+
"Rakefile",
|
31
|
+
"VERSION",
|
32
|
+
Dir['lib/**/*.*'],
|
33
|
+
Dir['generators/**/*.*'],
|
34
|
+
].flatten
|
59
35
|
gem.add_dependency 'rest-client', '>= 1.5.0'
|
60
36
|
gem.add_dependency 'net-ssh', '>= 2.0.12'
|
61
37
|
gem.add_dependency 'net-ssh-gateway', '>= 1.0.1'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.24
|
@@ -1,8 +1,9 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../test_helper"
|
2
2
|
require "saucelabs_adapter"
|
3
|
+
require "saucelabs_adapter/jsunit_selenium_support"
|
3
4
|
|
4
5
|
class JsunitTest < ActiveSupport::TestCase
|
5
|
-
include ::JsunitSeleniumSupport
|
6
|
+
include SaucelabsAdapter::JsunitSeleniumSupport
|
6
7
|
|
7
8
|
def setup
|
8
9
|
setup_jsunit_selenium # :timeout_in_seconds => 60, :app_server_logfile_path => "#{RAILS_ROOT}/log/jsunit_jetty_app_server.log"
|
@@ -2,6 +2,9 @@ common: &common
|
|
2
2
|
# Try to kill mongrel after suite if tmp/pids/mongrel_selenium.pid exists
|
3
3
|
# kill_mongrel_after_suite: true
|
4
4
|
|
5
|
+
# This only applies if the test_framework is not :webrat. Webrat starts its own mongrel.
|
6
|
+
start_server: :true
|
7
|
+
|
5
8
|
local: &local
|
6
9
|
<<: *common
|
7
10
|
selenium_server_address: "127.0.0.1"
|
@@ -40,13 +43,14 @@ saucelabs: &saucelabs
|
|
40
43
|
saucelabs_max_duration_seconds: 1800
|
41
44
|
# Selenium RC browser connects to and tests the app at this URL:
|
42
45
|
application_address: "testhost.com" # this will be ovewritten if tunnel_method == :saucetunnel
|
43
|
-
application_port:
|
46
|
+
application_port: 4000
|
47
|
+
|
44
48
|
# App host can actually be a tunnel that tunnels from <application_address>:<application_port> to localhost:<tunnel_to_localhost_port>
|
45
49
|
# There are 3 kinds of tunnels:
|
46
50
|
#
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
tunnel_method: :saucetunnel
|
52
|
+
tunnel_to_localhost_port: 4000 # Warning: application_port and tunnel_to_localhost_port must be identical if you are using Webrat
|
53
|
+
tunnel_startup_timeout: 240
|
50
54
|
#
|
51
55
|
# tunnel_method: :sshtunnel # WARNING: if other projects use the same port on the same machine at the same time, you can get intermittent errors.
|
52
56
|
# application_address: proxy.mycompany.com
|
@@ -2,9 +2,10 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper'))
|
|
2
2
|
require 'test/unit/ui/console/testrunner'
|
3
3
|
require 'webrat'
|
4
4
|
require 'saucelabs_adapter'
|
5
|
+
require 'saucelabs_adapter/test_unit_adapter'
|
5
6
|
|
6
7
|
Webrat.configure do |config|
|
7
8
|
config.mode = :selenium
|
8
9
|
end
|
9
10
|
|
10
|
-
require File.join(File.dirname(__FILE__), 'sample_webrat_test')
|
11
|
+
require File.join(File.dirname(__FILE__), 'sample_webrat_test')
|
data/lib/saucelabs_adapter.rb
CHANGED
@@ -4,8 +4,5 @@ require 'saucelabs_adapter/tunnels/sauce_tunnel'
|
|
4
4
|
require 'saucelabs_adapter/tunnels/ssh_tunnel'
|
5
5
|
require 'saucelabs_adapter/tunnels/other_tunnel'
|
6
6
|
require 'saucelabs_adapter/selenium_config'
|
7
|
-
require 'saucelabs_adapter/test_unit_adapter'
|
8
|
-
require 'saucelabs_adapter/rspec_adapter'
|
9
|
-
require 'saucelabs_adapter/jsunit_selenium_support'
|
10
7
|
module SaucelabsAdapter
|
11
8
|
end
|
@@ -15,7 +15,7 @@ module SaucelabsAdapter
|
|
15
15
|
start_app_server(options)
|
16
16
|
@selenium_driver = @selenium_config.create_driver(options)
|
17
17
|
debug "calling @selenium_driver.start"
|
18
|
-
@selenium_driver.
|
18
|
+
@selenium_driver.start_new_browser_session :trustAllSSLCertificates => false
|
19
19
|
debug "@selenium_driver.start done"
|
20
20
|
end
|
21
21
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
if defined?(Spec::Runner)
|
2
|
+
include SaucelabsAdapter::Utilities
|
2
3
|
|
3
4
|
module Spec
|
4
5
|
module Runner
|
@@ -9,20 +10,39 @@ if defined?(Spec::Runner)
|
|
9
10
|
end
|
10
11
|
|
11
12
|
selenium_config = SaucelabsAdapter::SeleniumConfig.new(ENV['SELENIUM_ENV'])
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
Spec::Runner.configure do |config|
|
14
|
+
config.before :suite do
|
15
|
+
start_mongrel(:port => selenium_config.application_port) if selenium_config.start_server && selenium_config.start_server.to_sym == :true
|
16
|
+
|
17
|
+
if selenium_config.start_tunnel? and config.saucelabs_tunnel.nil?
|
18
|
+
config.saucelabs_tunnel = SaucelabsAdapter::Tunnel.factory(selenium_config)
|
19
|
+
config.saucelabs_tunnel.start_tunnel
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
config.before :each do |suite|
|
24
|
+
ENV['SAUCELABS_JOB_NAME'] = "#{suite.class.description} #{suite.description}"
|
25
|
+
|
26
|
+
if defined?(Webrat)
|
19
27
|
webrat_config = Webrat.configuration
|
20
28
|
selenium_config.configure_webrat(webrat_config)
|
29
|
+
else
|
30
|
+
puts "[saucelabs-adapter] Starting browser session" if ENV['SAUCELABS_ADAPTER_DEBUG']
|
31
|
+
@browser = selenium_config.create_driver
|
32
|
+
@browser.start_new_browser_session
|
21
33
|
end
|
34
|
+
end
|
22
35
|
|
23
|
-
|
24
|
-
|
36
|
+
config.after :each do
|
37
|
+
if defined?(@browser)
|
38
|
+
puts "[saucelabs-adapter] Ending browser session" if ENV['SAUCELABS_ADAPTER_DEBUG']
|
39
|
+
@browser.close_current_browser_session
|
25
40
|
end
|
26
41
|
end
|
42
|
+
|
43
|
+
at_exit do
|
44
|
+
config.saucelabs_tunnel.shutdown if config.saucelabs_tunnel
|
45
|
+
kill_mongrel_if_needed if selenium_config.start_server && selenium_config.start_server.to_sym == :true
|
46
|
+
end
|
27
47
|
end
|
28
48
|
end
|
@@ -15,7 +15,7 @@ module SaucelabsAdapter
|
|
15
15
|
@configuration[attribute.to_s] = value
|
16
16
|
end
|
17
17
|
|
18
|
-
[ :test_framework,
|
18
|
+
[ :test_framework, :start_server,
|
19
19
|
:selenium_server_address, :selenium_server_port,
|
20
20
|
:application_address, :application_port,
|
21
21
|
:saucelabs_username, :saucelabs_access_key,
|
@@ -86,8 +86,8 @@ module SaucelabsAdapter
|
|
86
86
|
|
87
87
|
def create_driver(selenium_args = {})
|
88
88
|
args = selenium_client_driver_args.merge(selenium_args)
|
89
|
-
say "Connecting to Selenium RC server at #{args[:host]}:#{args[:port]} (testing app at #{args[:url]})"
|
90
|
-
say "args = #{display_safely(args)}"
|
89
|
+
say "Connecting to Selenium RC server at #{args[:host]}:#{args[:port]} (testing app at #{args[:url]})" if ENV['SAUCELABS_ADAPTER_DEBUG']
|
90
|
+
say "args = #{display_safely(args)}" if ENV['SAUCELABS_ADAPTER_DEBUG']
|
91
91
|
driver = ::Selenium::Client::Driver.new(args)
|
92
92
|
debug "done"
|
93
93
|
driver
|
@@ -114,9 +114,14 @@ module SaucelabsAdapter
|
|
114
114
|
|
115
115
|
def display_safely(selenium_args)
|
116
116
|
safe = selenium_args.dup
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
begin
|
118
|
+
safe[:browser] = JSON.parse( safe[:browser])
|
119
|
+
safe[:browser]['access-key'] = safe[:browser]['access-key'][0..4] + '...'
|
120
|
+
safe[:browser] = safe[:browser].to_json
|
121
|
+
rescue
|
122
|
+
# args are not always json, e.g. when running locally
|
123
|
+
# for now, just ignore any exceptions when trying to parse args with json
|
124
|
+
end
|
120
125
|
safe.inspect
|
121
126
|
end
|
122
127
|
|
@@ -168,7 +173,7 @@ module SaucelabsAdapter
|
|
168
173
|
end
|
169
174
|
else
|
170
175
|
errors << require_attributes([:selenium_browser_key, :application_address ],
|
171
|
-
:when => "unless server is
|
176
|
+
:when => "unless server is saucelabs.com")
|
172
177
|
end
|
173
178
|
|
174
179
|
errors.flatten!.compact!
|
@@ -14,8 +14,20 @@ if defined?(ActiveSupport::TestCase) && ActiveSupport::TestCase.respond_to?(:set
|
|
14
14
|
elsif defined?(Webrat)
|
15
15
|
webrat_config = Webrat.configuration
|
16
16
|
selenium_config.configure_webrat(webrat_config)
|
17
|
+
else
|
18
|
+
puts "[saucelabs-adapter] Starting browser session"
|
19
|
+
@browser = selenium_config.create_driver
|
20
|
+
@browser.start_new_browser_session
|
17
21
|
end
|
18
22
|
end
|
23
|
+
|
24
|
+
def teardown
|
25
|
+
if defined?(@browser)
|
26
|
+
puts "[saucelabs-adapter] Ending browser session"
|
27
|
+
@browser.close_current_browser_session
|
28
|
+
end
|
29
|
+
super
|
30
|
+
end
|
19
31
|
end
|
20
32
|
end
|
21
33
|
end
|
@@ -35,32 +47,13 @@ if defined?(Test::Unit::UI::Console::TestRunner)
|
|
35
47
|
@mediator.add_listener(Test::Unit::UI::TestRunnerMediator::STARTED, &method(:setup_tunnel))
|
36
48
|
@mediator.add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED, &method(:teardown_tunnel))
|
37
49
|
end
|
38
|
-
|
50
|
+
|
51
|
+
if @selenium_config.start_server && @selenium_config.start_server.to_sym == :true
|
52
|
+
@mediator.add_listener(Test::Unit::UI::TestRunnerMediator::STARTED, &method(:start_mongrel))
|
39
53
|
@mediator.add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED, &method(:kill_mongrel_if_needed))
|
40
54
|
end
|
41
55
|
end
|
42
56
|
|
43
57
|
alias_method_chain :attach_to_mediator, :sauce_tunnel unless private_method_defined?(:attach_to_mediator_without_sauce_tunnel)
|
44
|
-
|
45
|
-
def setup_tunnel(suite_name)
|
46
|
-
@tunnel = SaucelabsAdapter::Tunnel.factory(@selenium_config)
|
47
|
-
@tunnel.start_tunnel
|
48
|
-
end
|
49
|
-
|
50
|
-
def teardown_tunnel(suite_name)
|
51
|
-
@tunnel.shutdown
|
52
|
-
end
|
53
|
-
|
54
|
-
def kill_mongrel_if_needed(suite_name)
|
55
|
-
mongrel_pid_file = File.join(RAILS_ROOT, "tmp", "pids", "mongrel_selenium.pid")
|
56
|
-
if File.exists?(mongrel_pid_file)
|
57
|
-
pid = File.read(mongrel_pid_file).to_i
|
58
|
-
say "Killing mongrel at #{pid}"
|
59
|
-
Process.kill("KILL", pid)
|
60
|
-
end
|
61
|
-
if File.exists?(mongrel_pid_file)
|
62
|
-
FileUtils.rm(mongrel_pid_file)
|
63
|
-
end
|
64
|
-
end
|
65
58
|
end
|
66
|
-
end
|
59
|
+
end
|
@@ -34,5 +34,34 @@ module SaucelabsAdapter
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
# parameters required when invoked by test_unit
|
39
|
+
def start_mongrel(suite_name = {})
|
40
|
+
pid_file = File.join(RAILS_ROOT, "tmp", "pids", "mongrel_selenium.pid")
|
41
|
+
port = suite_name[:port] rescue @selenium_config.application_port
|
42
|
+
say "Starting mongrel at #{pid_file}, port #{port}"
|
43
|
+
system "mongrel_rails start -d --chdir='#{RAILS_ROOT}' --port=#{port} --environment=test --pid #{pid_file} %"
|
44
|
+
end
|
45
|
+
|
46
|
+
def kill_mongrel_if_needed(suite_name = {})
|
47
|
+
mongrel_pid_file = File.join(RAILS_ROOT, "tmp", "pids", "mongrel_selenium.pid")
|
48
|
+
if File.exists?(mongrel_pid_file)
|
49
|
+
pid = File.read(mongrel_pid_file).to_i
|
50
|
+
say "Killing mongrel at #{pid}"
|
51
|
+
Process.kill("KILL", pid)
|
52
|
+
end
|
53
|
+
if File.exists?(mongrel_pid_file)
|
54
|
+
FileUtils.rm(mongrel_pid_file)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def setup_tunnel(suite_name = {})
|
59
|
+
@tunnel = SaucelabsAdapter::Tunnel.factory(@selenium_config)
|
60
|
+
@tunnel.start_tunnel
|
61
|
+
end
|
62
|
+
|
63
|
+
def teardown_tunnel(suite_name = {})
|
64
|
+
@tunnel.shutdown
|
65
|
+
end
|
37
66
|
end
|
38
|
-
end
|
67
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
SauceREST for Ruby
|
2
|
+
==================
|
3
|
+
|
4
|
+
This is a Ruby library and some command line tools for interacting
|
5
|
+
with the SauceREST API.
|
6
|
+
|
7
|
+
Requirements
|
8
|
+
------------
|
9
|
+
|
10
|
+
For the scripts to run, you need to first install:
|
11
|
+
|
12
|
+
* net-ssh
|
13
|
+
* net-ssh-gateway
|
14
|
+
* rest-client
|
15
|
+
|
16
|
+
|
17
|
+
Here are some useful command line tools:
|
18
|
+
|
19
|
+
tunnel.rb
|
20
|
+
---------
|
21
|
+
|
22
|
+
This script is used to set up tunnel machines and open the tunnel from
|
23
|
+
your side. Run it with "-h" to get the parameters required. Example
|
24
|
+
run:
|
25
|
+
|
26
|
+
$ ruby tunnel.rb username api-key localhost 5000:80 exampleurl.com
|
27
|
+
|
28
|
+
This will make our computers masquerade exampleurl.com on port 80
|
29
|
+
through the tunnel you're about to open.
|
30
|
+
|
31
|
+
|
32
|
+
list_tunnels.rb
|
33
|
+
---------------
|
34
|
+
|
35
|
+
Lists all the available tunnels for the user account given. Example
|
36
|
+
run:
|
37
|
+
|
38
|
+
$ ruby list_tunnels.rb username api-key
|
39
|
+
|
40
|
+
|
41
|
+
saucerest.rb
|
42
|
+
------------
|
43
|
+
|
44
|
+
This is a basic library for working with the SauceREST API. If you
|
45
|
+
plan to write scripts that work with SauceREST in Ruby, `saucerest.rb`
|
46
|
+
might be a good place to start.
|
@@ -0,0 +1,191 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009 Sauce Labs Inc
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# 'Software'), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
21
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
22
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
23
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
require 'rubygems'
|
26
|
+
require 'net/ssh'
|
27
|
+
require 'net/ssh/gateway'
|
28
|
+
require 'gateway'
|
29
|
+
require 'saucerest'
|
30
|
+
require 'optparse'
|
31
|
+
|
32
|
+
options = {}
|
33
|
+
op = OptionParser.new do |opts|
|
34
|
+
opts.banner = "Usage: tunnel.rb [options] <username> <access key> <local host> <local port>:<remote port>[,<local port>:<remote port>] <remote domain>,[<remote domain>...]"
|
35
|
+
opts.separator ""
|
36
|
+
opts.separator "Specific options:"
|
37
|
+
|
38
|
+
# opts.on("-d", "--daemonize", "background the process once the tunnel is established") do |d|
|
39
|
+
# options[:daemonize] = d
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# opts.on("-p", "--pidfile FILE", "when used with --daemonize, write backgrounded Process ID to FILE [default: %default]") do |p|
|
43
|
+
# options[:pidfile] = p
|
44
|
+
# end
|
45
|
+
|
46
|
+
opts.on("-r", "--readyfile FILE", "create FILE when the tunnel is ready") do |r|
|
47
|
+
options[:readyfile] = r
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on("-s", "--shutdown", "shutdown any existing tunnel machines using one or more requested domain names") do |s|
|
51
|
+
options[:shutdown] = s
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on("--diagnostic", "using this option, we will run a set of tests to make sure the arguments given are correct. If all works, will open the tunnels in debug mode") do |d|
|
55
|
+
options[:diagnostic] = d
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
opts = op.parse!
|
60
|
+
|
61
|
+
# TODO: Analize the options inserted and do something with them
|
62
|
+
# p options
|
63
|
+
|
64
|
+
num_missing = 5 - opts.length
|
65
|
+
if num_missing > 0
|
66
|
+
puts 'Missing %d required argument(s)' % [num_missing]
|
67
|
+
puts
|
68
|
+
puts op
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
|
72
|
+
username = opts[0]
|
73
|
+
access_key = opts[1]
|
74
|
+
local_host = opts[2]
|
75
|
+
ports = Array.new
|
76
|
+
for pair in opts[3].split(",")
|
77
|
+
if not pair.include? ":"
|
78
|
+
puts 'Incorrect port syntax: %s' % [pair]
|
79
|
+
puts
|
80
|
+
puts op
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
pair = pair.split(":").collect {|i| Integer(i)}
|
84
|
+
ports << pair
|
85
|
+
end
|
86
|
+
domains = opts[4..-1].join(",").split(",")
|
87
|
+
|
88
|
+
#puts ports.length
|
89
|
+
#puts domains
|
90
|
+
#exit
|
91
|
+
|
92
|
+
if options[:diagnostic]
|
93
|
+
errors = Array.new
|
94
|
+
# Checking domains to forward
|
95
|
+
for domain in domains
|
96
|
+
if not domain =~ /^([\da-z\.-]+)\.([a-z\.]{2,6})$/
|
97
|
+
errors << "Incorrect domain given: %s" % [domain]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
# Checking if host is accesible
|
101
|
+
require 'socket'
|
102
|
+
for pair in ports
|
103
|
+
begin
|
104
|
+
s = TCPSocket.open(local_host, pair[0])
|
105
|
+
rescue Errno::ECONNREFUSED => e
|
106
|
+
errors << "Problem connecting to %s:%s: %s" % [local_host, pair[0], e.message]
|
107
|
+
rescue SocketError
|
108
|
+
errors << "Local host %s is not accessible" % local_host
|
109
|
+
break
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
if errors.empty?
|
114
|
+
puts "No errors found, proceeeding"
|
115
|
+
else
|
116
|
+
puts "Errors found:"
|
117
|
+
puts errors.collect {|e| "\t"+e}
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
sauce = SauceREST::Client.new "https://#{username}:#{access_key}@saucelabs.com/rest/#{username}/"
|
124
|
+
|
125
|
+
if options[:shutdown]
|
126
|
+
puts "Searching for existing tunnels using requested domains..."
|
127
|
+
tunnels = sauce.list :tunnel
|
128
|
+
for tunnel in tunnels
|
129
|
+
for domain in domains
|
130
|
+
if tunnel['DomainNames'].include?(domain)
|
131
|
+
puts "tunnel %s is currenty using requested domain %s" % [
|
132
|
+
tunnel['_id'], domain]
|
133
|
+
puts "shutting down tunnel %s" % tunnel['_id']
|
134
|
+
sauce.delete :tunnel, tunnel['_id']
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
puts "Launching tunnel machine..."
|
141
|
+
response = sauce.create(:tunnel,
|
142
|
+
'DomainNames' => domains)
|
143
|
+
|
144
|
+
if response.has_key? 'error'
|
145
|
+
puts "Error: %s" % [response['error']]
|
146
|
+
exit
|
147
|
+
end
|
148
|
+
|
149
|
+
tunnel_id = response['id']
|
150
|
+
puts "Tunnel id: %s" % tunnel_id
|
151
|
+
|
152
|
+
begin
|
153
|
+
interval = 10
|
154
|
+
timeout = 600
|
155
|
+
t = 0
|
156
|
+
while t < timeout
|
157
|
+
tunnel = sauce.get :tunnel, tunnel_id
|
158
|
+
puts "Status: %s" % tunnel['Status']
|
159
|
+
if tunnel['Status'] == 'running'
|
160
|
+
break
|
161
|
+
end
|
162
|
+
|
163
|
+
sleep interval
|
164
|
+
t += interval
|
165
|
+
end
|
166
|
+
|
167
|
+
gateway = Net::SSH::Gateway.new(tunnel['Host'], username,
|
168
|
+
{:password => access_key})
|
169
|
+
begin
|
170
|
+
for pair in ports
|
171
|
+
gateway.open_remote(pair[0], local_host, pair[1], "0.0.0.0") do |rp, rh|
|
172
|
+
puts "ssh remote tunnel opened"
|
173
|
+
if options.has_key?(:readyfile)
|
174
|
+
File.open(options[:readyfile], "w") do |the_file|
|
175
|
+
the_file.puts "ready"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
while true
|
179
|
+
sleep 1
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
ensure
|
184
|
+
gateway.shutdown!
|
185
|
+
end
|
186
|
+
rescue Interrupt
|
187
|
+
nil
|
188
|
+
ensure
|
189
|
+
puts "Aborted -- shutting down tunnel machine"
|
190
|
+
sauce.delete :tunnel, tunnel_id
|
191
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saucelabs-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 0.8.
|
9
|
+
- 24
|
10
|
+
version: 0.8.24
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kelly Felkins, Chad Woolley, Sam Pierson, Nate Clark
|
@@ -15,12 +15,12 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-19 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
prerelease: false
|
23
22
|
type: :runtime
|
23
|
+
prerelease: false
|
24
24
|
name: rest-client
|
25
25
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
26
|
none: false
|
@@ -35,8 +35,8 @@ dependencies:
|
|
35
35
|
version: 1.5.0
|
36
36
|
requirement: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
|
-
prerelease: false
|
39
38
|
type: :runtime
|
39
|
+
prerelease: false
|
40
40
|
name: net-ssh
|
41
41
|
version_requirements: &id002 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
@@ -51,8 +51,8 @@ dependencies:
|
|
51
51
|
version: 2.0.12
|
52
52
|
requirement: *id002
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
|
-
prerelease: false
|
55
54
|
type: :runtime
|
55
|
+
prerelease: false
|
56
56
|
name: net-ssh-gateway
|
57
57
|
version_requirements: &id003 !ruby/object:Gem::Requirement
|
58
58
|
none: false
|
@@ -67,8 +67,8 @@ dependencies:
|
|
67
67
|
version: 1.0.1
|
68
68
|
requirement: *id003
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
prerelease: false
|
71
70
|
type: :runtime
|
71
|
+
prerelease: false
|
72
72
|
name: selenium-client
|
73
73
|
version_requirements: &id004 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
@@ -83,8 +83,8 @@ dependencies:
|
|
83
83
|
version: 1.2.17
|
84
84
|
requirement: *id004
|
85
85
|
- !ruby/object:Gem::Dependency
|
86
|
-
prerelease: false
|
87
86
|
type: :runtime
|
87
|
+
prerelease: false
|
88
88
|
name: lsof
|
89
89
|
version_requirements: &id005 !ruby/object:Gem::Requirement
|
90
90
|
none: false
|
@@ -130,8 +130,11 @@ files:
|
|
130
130
|
- lib/saucelabs_adapter/tunnels/sauce_tunnel.rb
|
131
131
|
- lib/saucelabs_adapter/tunnels/ssh_tunnel.rb
|
132
132
|
- lib/saucelabs_adapter/utilities.rb
|
133
|
+
- lib/saucerest-ruby/README.md
|
133
134
|
- lib/saucerest-ruby/gateway.rb
|
135
|
+
- lib/saucerest-ruby/listtunnels.rb
|
134
136
|
- lib/saucerest-ruby/saucerest.rb
|
137
|
+
- lib/saucerest-ruby/tunnel.rb
|
135
138
|
- README.markdown
|
136
139
|
- spec/selenium_config_spec.rb
|
137
140
|
- spec/spec_helper.rb
|