sauce_connect 3.6.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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/sauce/connect.rb +242 -0
  3. metadata +70 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b56c2f924091bac3a7f5aca719edd393812043d6
4
+ data.tar.gz: e50ee142b53516ce21bf448a12981241b484e345
5
+ SHA512:
6
+ metadata.gz: a2dbef3999ab736761308dd400f22ee5fe0f2ef67c2cd9e6dbf19f3ffff7c363119d2aa9560beba4bc302621f348e7364db2dbb21cf20cc0b8b865ad7118e066
7
+ data.tar.gz: 43e4d418185295b57f69a84806a69c768c6ff762f04d528e9550299cb8651ec8c0351007bebe9e4c981e479e8ed0a6454519285e95c600a846dddccea370e9af
@@ -0,0 +1,242 @@
1
+ require 'sauce/config'
2
+ require 'net/http'
3
+ require 'socket'
4
+
5
+ module Sauce
6
+ class Connect
7
+ class TunnelNotPossibleException < StandardError
8
+ end
9
+
10
+ TIMEOUT = 90
11
+
12
+ attr_reader :status, :error
13
+
14
+ def initialize(options={})
15
+ @ready = false
16
+ @status = "uninitialized"
17
+ @error = nil
18
+ @quiet = options[:quiet]
19
+ @timeout = options.fetch(:timeout) { TIMEOUT }
20
+ @config = Sauce::Config.new(options)
21
+ @skip_connection_test = @config[:skip_connection_test]
22
+ @cli_options = @config[:connect_options]
23
+ @sc4_executable = @config[:sauce_connect_4_executable]
24
+
25
+ if @config.username.nil?
26
+ raise ArgumentError, "Username required to launch Sauce Connect. Please set the environment variable $SAUCE_USERNAME"
27
+ end
28
+
29
+ if @config.access_key.nil?
30
+ raise ArgumentError, "Access key required to launch Sauce Connect. Please set the environment variable $SAUCE_ACCESS_KEY"
31
+ end
32
+
33
+ if @sc4_executable.nil?
34
+ raise TunnelNotPossibleException, Sauce::Connect.plzGetSC4
35
+ end
36
+ end
37
+
38
+ def ensure_connection_is_possible
39
+ $stderr.puts "[Checking REST API is contactable...]" unless @quiet
40
+ uri = URI("http://saucelabs.com/rest/v1/#{@config[:username]}/tunnels")
41
+
42
+ response = Net::HTTP.start(uri.host, uri.port) do |http|
43
+ request = Net::HTTP::Get.new uri.request_uri
44
+ request.basic_auth(@config[:username], @config[:access_key])
45
+ response = http.request request
46
+ end
47
+
48
+ unless response.kind_of? Net::HTTPOK
49
+ $stderr.puts Sauce::Connect.cant_access_rest_api_message
50
+ raise TunnelNotPossibleException, "Couldn't access REST API"
51
+ end
52
+
53
+ begin
54
+ $stderr.puts "[Checking port 443 is open...]" unless @quiet
55
+ socket = TCPSocket.new 'saucelabs.com', 443
56
+ rescue SystemCallError => e
57
+ raise e unless e.class.name.start_with? 'Errno::'
58
+ $stderr.puts Sauce::Connect.port_not_open_message
59
+ raise TunnelNotPossibleException, "Couldn't use port 443"
60
+ end
61
+ end
62
+
63
+ def connect
64
+ unless @skip_connection_test
65
+ ensure_connection_is_possible
66
+ end
67
+
68
+ puts "[Sauce Connect is connecting to Sauce Labs...]"
69
+
70
+ formatted_cli_options = array_of_formatted_cli_options_from_hash(cli_options)
71
+
72
+ command_args = ['-u', @config.username, '-k', @config.access_key]
73
+ command_args << formatted_cli_options
74
+
75
+ command = "exec #{find_sauce_connect} #{command_args.join(' ')} 2>&1"
76
+
77
+ unless @quiet
78
+ string_arguments = formatted_cli_options.join(' ')
79
+ puts "[Sauce Connect arguments: '#{string_arguments}' ]"
80
+ end
81
+
82
+ @pipe = IO.popen(command)
83
+
84
+ @process_status = $?
85
+ at_exit do
86
+ Process.kill("INT", @pipe.pid)
87
+ while @ready
88
+ sleep 1
89
+ end
90
+ end
91
+
92
+ Thread.new {
93
+ while( (line = @pipe.gets) )
94
+ if line =~ /Tunnel remote VM is (.*) (\.\.|at)/
95
+ @status = $1
96
+ end
97
+ if line =~/You may start your tests\./i
98
+ @ready = true
99
+ end
100
+ if line =~ /- (Problem.*)$/
101
+ @error = $1
102
+ @quiet = false
103
+ end
104
+ if line =~ /== Missing requirements ==/
105
+ @error = "Missing requirements"
106
+ @quiet = false
107
+ end
108
+ if line =~/Invalid API_KEY provided/
109
+ @error = "Invalid API_KEY provided"
110
+ @quiet = false
111
+ end
112
+ $stderr.puts line unless @quiet
113
+ end
114
+ @ready = false
115
+ }
116
+ end
117
+
118
+ def cli_options
119
+ cli_options = { readyfile: "sauce_connect.ready" }
120
+ cli_options.merge!(@cli_options) if @cli_options
121
+ cli_options
122
+ end
123
+
124
+ def wait_until_ready
125
+ start = Time.now
126
+ while !@ready and (Time.now-start) < @timeout and @error != "Missing requirements"
127
+ sleep 0.5
128
+ end
129
+
130
+ if @error == "Missing requirements"
131
+ raise "Missing requirements"
132
+ end
133
+
134
+ if !@ready
135
+ error_message = "Sauce Connect failed to connect after #{@timeout} seconds"
136
+ error_message << "\n(Using Sauce Connect at #{@sc4_executable}"
137
+ raise error_message
138
+ end
139
+ end
140
+
141
+ def disconnect
142
+ if @ready
143
+ Process.kill("INT", @pipe.pid)
144
+ while @ready
145
+ sleep 1
146
+ end
147
+ end
148
+ end
149
+
150
+ # Check whether the path, or it's bin/sc descendant, exists and is executable
151
+ def find_sauce_connect
152
+ paths = [@sc4_executable, File.join("#{@sc4_executable}", "bin", "sc")]
153
+
154
+ sc_path = paths.find do |path|
155
+ path_is_connect_executable? path
156
+ end
157
+
158
+ if sc_path.nil?
159
+ raise TunnelNotPossibleException, "No executable found at #{sc_path}, or it can't be executed by #{Process.euid}"
160
+ end
161
+
162
+ return File.absolute_path sc_path
163
+ end
164
+
165
+ def path_is_connect_executable? path
166
+ absolute_path = File.absolute_path path
167
+ return (File.exist? absolute_path) && (File.executable? absolute_path) && !(Dir.exist? absolute_path)
168
+ end
169
+
170
+ # Global Sauce Connect-ness
171
+ @connection = nil
172
+
173
+ def self.connect!(*args)
174
+ @connection = self.new(*args)
175
+ @connection.connect
176
+ @connection.wait_until_ready
177
+ at_exit do
178
+ @connection.disconnect
179
+ end
180
+ end
181
+
182
+ def self.ensure_connected(*args)
183
+ if @connection
184
+ @connection.wait_until_ready
185
+ else
186
+ connect!(*args)
187
+ end
188
+ end
189
+
190
+ private
191
+
192
+ def array_of_formatted_cli_options_from_hash(hash)
193
+ hash.collect do |key, value|
194
+ opt_name = key.to_s.gsub("_", "-")
195
+ "--#{opt_name} #{value}"
196
+ end
197
+ end
198
+
199
+ def self.port_not_open_message
200
+ <<-ENDLINE
201
+ Unable to connect to port 443 on saucelabs.com, which may interfere with
202
+ Sauce Connect.
203
+
204
+ This might be caused by a HTTP mocking framework like WebMock or
205
+ FakeWeb. Check out
206
+ (https://github.com/saucelabs/sauce_ruby#network-mocking)
207
+ if you're using one. Sauce Connect needs access to *.saucelabs.com,
208
+ port 80 and port 443.
209
+
210
+ You can disable network tests by setting :skip_connection_test to true in
211
+ your Sauce.config block.
212
+ ENDLINE
213
+ end
214
+
215
+ def self.cant_access_rest_api_message
216
+ <<-ENDLINE
217
+ Unable to connect to the Sauce REST API, which may interfere with
218
+ Sauce Connect.
219
+
220
+ This might be caused by a HTTP mocking framework like WebMock or
221
+ FakeWeb. Check out
222
+ (https://github.com/saucelabs/sauce_ruby#network-mocking)
223
+ if you're using one. Sauce Connect needs access to *.saucelabs.com,
224
+ port 80 and port 443.
225
+
226
+ You can disable network tests by setting :skip_connection_test to true in
227
+ your Sauce.config block.
228
+ ENDLINE
229
+ end
230
+
231
+ def self.plzGetSC4
232
+ <<-ENDLINE
233
+ Using Sauce Connect 3 has been deprecated. Please set the :sauce_connect_4_executable
234
+ option in your Sauce.config block to the path of an installation of
235
+ Sauce Connect 4.
236
+
237
+ You can download Sauce Connect 4 for free at
238
+ http://docs.saucelabs.com/sauce_connect
239
+ ENDLINE
240
+ end
241
+ end
242
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sauce_connect
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.6.1
5
+ platform: ruby
6
+ authors:
7
+ - R. Tyler Croy
8
+ - Steve Hazel
9
+ - Dylan Lacey
10
+ - Rick Martínez
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2015-06-26 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: sauce_ruby
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '3.5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.5'
30
+ description: A wrapper to start and stop a Sauce Connect tunnel programatically.
31
+ email:
32
+ - tyler@monkeypox.org
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/sauce/connect.rb
38
+ homepage: https://docs.saucelabs.com/reference/sauce-connect
39
+ licenses:
40
+ - Apache 2.0
41
+ metadata: {}
42
+ post_install_message: |2
43
+ To use the Sauce Connect gem, you'll need to download the appropriate
44
+ Sauce Connect binary from https://docs.saucelabs.com/reference/sauce-connect
45
+
46
+ Then, set the 'sauce_connect_4_executable' key in your Sauce.config block, to
47
+ the path of the unzipped file's /bin/sc.
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements:
62
+ - An account at http://www.saucelabs.com
63
+ - A working copy of Sauce Connect from https://docs.saucelabs.com/reference/sauce-connect
64
+ rubyforge_project:
65
+ rubygems_version: 2.4.6
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Manage Sauce Connect from within your tests
69
+ test_files: []
70
+ has_rdoc: