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