sauce 0.20.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,12 @@
1
- Sauce OnDemand is a Selenium testing cloud service, developed by Sauce
2
- Labs Inc (saucelabs.com). This is the Ruby client adapter for Sauce
3
- OnDemand.
1
+ Sauce OnDemand is a Selenium testing cloud service, developed by Sauce Labs Inc
2
+ (saucelabs.com). This is the Ruby client adapter for Sauce OnDemand.
4
3
 
5
4
  Features
6
5
  --------
7
6
 
8
7
  * Drop-in replacement for Selenium::Client::Driver that takes care of connecting to Sauce OnDemand
9
8
  * RSpec, Test::Unit, and Rails integration for tests, including automatic setup of Sauce Connect
10
- * ActiveRecord-like interface for tunnels and jobs: Find/create/destroy
9
+ * ActiveRecord-like interface for job metadata: Find/create/destroy
11
10
 
12
11
  Install
13
12
  -------
@@ -189,12 +188,6 @@ If you want tests to go a bit faster, globally install the gems with native exte
189
188
  * gem install ffi sqlite3 json
190
189
  * rvm use default
191
190
 
192
- Plans
193
- -----
194
-
195
- * Webrat integration
196
- * Extend to automatic retrieval of jobs logs, videos, reverse tunnels
197
-
198
191
  Copyright
199
192
  ---------
200
193
 
@@ -1,6 +1,4 @@
1
- require 'rubygems'
2
1
  require 'sauce/utilities'
3
- require 'sauce/tunnel'
4
2
  require 'sauce/job'
5
3
  require 'sauce/client'
6
4
  require 'sauce/config'
@@ -9,7 +9,7 @@ module Sauce
9
9
 
10
10
  attr_accessor :client
11
11
  attr_accessor :protocol, :host, :port, :api_path, :api_version, :ip, :api_url
12
- attr_accessor :tunnels, :jobs
12
+ attr_accessor :jobs
13
13
 
14
14
  def initialize(options={})
15
15
  config = Sauce::Config.new
@@ -24,13 +24,6 @@ module Sauce
24
24
  @api_url = "#{@protocol}://#{config.username}:#{config.access_key}@#{@host}:#{@port}/#{@api_path}/v#{@api_version}/#{config.username}/"
25
25
  @client = RestClient::Resource.new @api_url
26
26
 
27
- @tunnels = Sauce::Tunnel
28
- @tunnels.client = @client
29
- @tunnels.account = {
30
- :username => config.username,
31
- :access_key => config.access_key,
32
- :ip => @ip}
33
-
34
27
  @jobs = Sauce::Job
35
28
  @jobs.client = @client
36
29
  @jobs.account = {
@@ -1,8 +1,3 @@
1
- require 'net/telnet'
2
- require 'net/ssh'
3
- require 'net/ssh/gateway'
4
- require 'sauce/gateway_ext'
5
-
6
1
  module Sauce
7
2
  # Interact with a Sauce Labs selenium jobs as if it were a ruby object
8
3
  class Job
@@ -2,13 +2,13 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{sauce}
5
- s.version = "0.20.0"
5
+ s.version = "1.0.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Eric Allen", "Sean Grove", "Steven Hazel"]
9
- s.date = %q{2011-03-26}
9
+ s.date = %q{2011-04-11}
10
10
  s.default_executable = %q{sauce}
11
- s.description = %q{A Ruby interface to Sauce Labs' services. Start/stop tunnels, retrieve Selenium logs, access video replays, etc.}
11
+ s.description = %q{A Ruby interface to Sauce OnDemand.}
12
12
  s.email = %q{help@saucelabs.com}
13
13
  s.executables = ["sauce"]
14
14
  s.files = [
@@ -30,13 +30,11 @@ Gem::Specification.new do |s|
30
30
  "lib/sauce/client.rb",
31
31
  "lib/sauce/config.rb",
32
32
  "lib/sauce/connect.rb",
33
- "lib/sauce/gateway_ext.rb",
34
33
  "lib/sauce/heroku.rb",
35
34
  "lib/sauce/integrations.rb",
36
35
  "lib/sauce/job.rb",
37
36
  "lib/sauce/raketasks.rb",
38
37
  "lib/sauce/selenium.rb",
39
- "lib/sauce/tunnel.rb",
40
38
  "lib/sauce/utilities.rb",
41
39
  "sauce.gemspec",
42
40
  "support/sauce_connect",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sauce
3
3
  version: !ruby/object:Gem::Version
4
- hash: 79
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 20
9
9
  - 0
10
- version: 0.20.0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Eric Allen
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-03-26 00:00:00 -07:00
20
+ date: 2011-04-11 00:00:00 -07:00
21
21
  default_executable: sauce
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -142,7 +142,7 @@ dependencies:
142
142
  version: 1.5.0
143
143
  type: :runtime
144
144
  version_requirements: *id008
145
- description: A Ruby interface to Sauce Labs' services. Start/stop tunnels, retrieve Selenium logs, access video replays, etc.
145
+ description: A Ruby interface to Sauce OnDemand.
146
146
  email: help@saucelabs.com
147
147
  executables:
148
148
  - sauce
@@ -169,13 +169,11 @@ files:
169
169
  - lib/sauce/client.rb
170
170
  - lib/sauce/config.rb
171
171
  - lib/sauce/connect.rb
172
- - lib/sauce/gateway_ext.rb
173
172
  - lib/sauce/heroku.rb
174
173
  - lib/sauce/integrations.rb
175
174
  - lib/sauce/job.rb
176
175
  - lib/sauce/raketasks.rb
177
176
  - lib/sauce/selenium.rb
178
- - lib/sauce/tunnel.rb
179
177
  - lib/sauce/utilities.rb
180
178
  - sauce.gemspec
181
179
  - support/sauce_connect
@@ -1,40 +0,0 @@
1
- # NOTE: This has been superseded by sauce/connect. Consider for deprecation
2
-
3
- # http://groups.google.com/group/capistrano/browse_thread/thread/455c0c8a6faa9cc8?pli=1
4
- class Net::SSH::Gateway
5
- # Opens a SSH tunnel from a port on a remote host to a given host and port
6
- # on the local side
7
- # (equivalent to openssh -R parameter)
8
- def open_remote(port, host, remote_port, remote_host = "127.0.0.1")
9
- ensure_open!
10
-
11
- begin
12
- @session_mutex.synchronize do
13
- result = @session.forward.remote(port, host, remote_port, remote_host)
14
- end
15
-
16
- if block_given?
17
- begin
18
- yield [remote_port, remote_host]
19
- ensure
20
- close_remote(remote_port, remote_host)
21
- end
22
- else
23
- return [remote_port, remote_host]
24
- end
25
- rescue Errno::EADDRINUSE
26
- retry
27
- end
28
- end
29
-
30
- # Cancels port-forwarding over an open port that was previously opened via
31
- # #open_remote.
32
- def close_remote(port, host = "127.0.0.1")
33
- puts "Close the remote port #{host}:#{port}!"
34
- ensure_open!
35
-
36
- @session_mutex.synchronize do
37
- @session.forward.cancel_remote(port, host)
38
- end
39
- end
40
- end
@@ -1,239 +0,0 @@
1
- # NOTE: This has been superseded by sauce/connect. Consider for deprecation
2
-
3
- require 'net/telnet'
4
- require 'net/ssh'
5
- require 'net/ssh/gateway'
6
- require 'sauce/gateway_ext'
7
-
8
- module Sauce
9
- # Interact with a Sauce Labs tunnel as if it were a ruby object
10
- class Tunnel
11
- class NoIDError < StandardError; end #nodoc
12
-
13
- #{"Status": "running", "CreationTime": 1266545716, "ModificationTime": 1266545793, "Host": "ec2-184-73-16-13.compute-1.amazonaws.com", "LaunchTime": 1266545726, "Owner": "sgrove", "_id": "1090b4b0b50477cf40fc44c146b408a4", "Type": "tunnel", "id": "1090b4b0b50477cf40fc44c146b408a4", "DomainNames": ["sgrove.tst"]}
14
-
15
- attr_accessor :owner, :access_key, :status
16
- attr_accessor :id, :host, :domain_names, :timeout
17
- attr_accessor :launch_time, :created_at, :updated_at
18
-
19
- attr_accessor :application_address, :gateway, :port, :thread
20
-
21
- # Get the class @@client.
22
- # TODO: Consider metaprogramming this away
23
- def self.client
24
- @@client
25
- end
26
-
27
- # Set the class @@client.
28
- # TODO: Consider metaprogramming this away
29
- def self.client=(client)
30
- @@client = client
31
- end
32
-
33
- # Get the class @@client.
34
- # TODO: Consider metaprogramming this away
35
- def self.account
36
- @@account
37
- end
38
-
39
- # Set the class @@client.
40
- # TODO: Consider metaprogramming this away
41
- def self.account=(account)
42
- @@account = account
43
- end
44
-
45
- def self.first
46
- self.all.first
47
- end
48
-
49
- def self.last
50
- self.all.last
51
- end
52
-
53
- def self.all
54
- responses = JSON.parse @@client[:tunnels].get.body
55
- return responses.collect{|response| Sauce::Tunnel.new(response)}
56
- end
57
-
58
- def self.destroy_all
59
- self.all.each { |tunnel| tunnel.destroy }
60
- end
61
-
62
- # Creates a new tunnel machine
63
- def self.create(options)
64
- response = JSON.parse @@client[:tunnels].post(options.to_json, :content_type => 'application/json').body
65
- #puts response.inspect
66
- Tunnel.new response
67
- end
68
-
69
- # Creates an instance representing a machine, but does not actually create the machine. See #create for that.
70
- def initialize(options)
71
- build!(options)
72
- end
73
-
74
- # Hits the destroy url for this tunnel, and then refreshes. Keep in mind it takes some time to completely teardown a tunnel.
75
- def destroy
76
- close_gateway
77
- response = @@client["tunnels/#{@id}"].delete.body
78
- refresh!
79
- end
80
-
81
- # Retrieves the latest information on this tunnel from the Sauce Labs' server
82
- def refresh!
83
- response = JSON.parse @@client["tunnels/#{@id}"].get.body
84
- #puts "\Tunnel refresh with: #{response.inspect}"
85
- build! response
86
- self
87
- end
88
-
89
- # Shortcut method to find out if a tunnel is marked as dead
90
- def preparing?
91
- refresh!
92
- status == "new" or status == "booting"
93
- end
94
-
95
- # Shortcut method to find out if a tunnel is marked as dead
96
- def halting?
97
- refresh!
98
- status == "halting"
99
- end
100
-
101
- # Shortcut method to find out if a tunnel is marked as dead
102
- def terminated?
103
- refresh!
104
- status == "terminated"
105
- end
106
-
107
- # A tunnel is healthy if 1.) its status is "running" and 2.) It says hello
108
- def healthy?
109
- # TODO: Implement 3.) We can reach through and touch a service on the reverse end of the tunnel
110
- refresh!
111
- =begin
112
- puts "\tRunning? #{self.status == 'running'}"
113
- puts "\tSays hello? #{self.says_hello?}"
114
- puts "\tThread running? #{self.still_running?}"
115
- =end
116
- return true if not self.terminated? and self.status == "running" and self.says_hello? and self.still_running?
117
- return false
118
- end
119
-
120
- # Sauce Labs' server will say hello on port 1025 as a sanity check. If no hello, something is wrong.
121
- # TODO: Make it say hello on port 1025. Currently a hack.
122
- def says_hello?(options={})
123
- return false unless self.status == "running" and not @host.nil?
124
-
125
- # TODO: Read from options if necessary
126
- connection = {}
127
- connection[:host] = @host
128
- connection[:port] = 22
129
- connection[:prompt] = /[$%#>] \z/n
130
- connection[:telnet_mode] = true
131
- connection[:timeout] = 10
132
-
133
- host = Net::Telnet::new("Host" => connection[:host],
134
- "Port" => connection[:port],
135
- "Prompt" => connection[:prompt],
136
- "Telnetmode" => connection[:telnet_mode],
137
- "Timeout" => connection[:timeout])
138
- line = host.lines.first.chomp
139
-
140
- # Temporary workaround port 1025 problem
141
- prefix = "SSH-2.0-Twisted"
142
- line[0,prefix.length] == prefix
143
- end
144
-
145
- # Debug method
146
- def mini_repair
147
- refresh!
148
- if not self.terminated? and self.status == "running" and self.says_hello?
149
- if not self.still_running?
150
- open_gateway
151
- return true if self.still_running?
152
- end
153
- end
154
- return false
155
- end
156
-
157
- # Opens a reverse ssh tunnel to the tunnel machine
158
- def open_gateway
159
- # TODO: Make ports configurable
160
-
161
- @gateway = Net::SSH::Gateway.new(host, owner, {:password => @@account[:access_key]})
162
-
163
- # Notes for anyone looking at this method
164
- # gateway.open_remote(3000, # Port where your local application is running. Usually 3000 for rails dev
165
- # "localhost", # Hostname/local ip your rails app is running on. Usually "localhost" for rails dev
166
- # 80, # This is the port to run your selenium tests against, i.e. :url => "http://<some_host>:80"
167
- # # <some_host> is the DomainNames you started the tunnel machine with.
168
- # "0.0.0.0") # Do not change this unless your god has commanded you to do so. I'm serious.
169
- port = 3000
170
- local_host = "localhost"
171
- remote_port = 80
172
- #puts "This is the experimental non-blocking gateway_open. Well done."
173
- #puts "gateway.open_remote(#{port}, #{local_host}, #{remote_port}, 0.0.0.0)"
174
- #gateway.open_remote(pair[0], local_host, pair[1], "0.0.0.0") do |rp, rh|
175
-
176
- @thread = Thread.new(host, port, remote_port, owner, @@account[:access_key]) do
177
- Thread.pass
178
- @gateway.open_remote(3000,
179
- "localhost",
180
- 80,
181
- "0.0.0.0") do |rp, rh|
182
- while true do
183
- sleep 10
184
- end
185
- end
186
- end
187
-
188
- @thread.run
189
- end
190
-
191
- # Closes the reverse ssh tunnel if open
192
- def close_gateway
193
- @thread.kill if @thread
194
- end
195
-
196
- # Returns true if this tunnel has a thread that needs to be monitored
197
- def still_running?
198
- #puts "\t\t#{@thread.inspect}.nil?"
199
- not @thread.nil?
200
- end
201
-
202
- # Returns a json representation of the current state of the tunnel object
203
- def to_json(options={})
204
- json = {
205
- :id => @id,
206
- :owner => @owner,
207
- :status => @status,
208
- :host => @host,
209
- :creation_time => @creation_time,
210
- :start_time => @start_time,
211
- :end_time => @end_time,
212
- :domain_name => @domain_names
213
- }
214
-
215
- options[:except].each { |key| json.delete(key) } if options[:except]
216
- json = json.select { |key,value| options[:only].include? key } if options[:only]
217
-
218
- return json
219
- end
220
-
221
- protected
222
-
223
- # Sets all internal variables from a hash
224
- def build!(options)
225
- options = options["tunnel"] unless options["tunnel"].nil?
226
- #puts "\tBuild with #{options.inspect}"
227
- @status = options["status"]
228
- @owner = options["owner"]
229
- @id = options["id"]
230
- @host = options["host"]
231
- @creation_time = options["creation_time"]
232
- @start_time = options["start_time"]
233
- @end_time = options["end_time"]
234
- @domain_names = options["domain_names"]
235
-
236
- raise NoIDError if @id.nil?
237
- end
238
- end
239
- end