sauce 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
data/lib/rest.rb CHANGED
@@ -7,12 +7,13 @@ module Sauce
7
7
  class BadAccessError < StandardError; end #nodoc
8
8
  class MisconfiguredError < StandardError; end #nodoc
9
9
 
10
- attr_accessor :username, :access_key, :client, :api_url
10
+ attr_accessor :username, :access_key, :client, :ip, :api_url
11
11
  attr_accessor :tunnels
12
12
 
13
13
  def initialize(options)
14
14
  @username = options[:username]
15
15
  @access_key = options[:access_key]
16
+ @ip = options[:ip]
16
17
 
17
18
  raise MisconfiguredError if @username.nil? or @access_key.nil?
18
19
  @api_url = "https://#{@username}:#{@access_key}@saucelabs.com/rest/#{@username}/"
@@ -20,6 +21,9 @@ module Sauce
20
21
 
21
22
  @tunnels = Sauce::Tunnel
22
23
  @tunnels.client = @client
24
+ @tunnels.account = {:username => @username,
25
+ :access_key => @access_key,
26
+ :ip => @ip}
23
27
  end
24
28
  end
25
29
  end
data/lib/sauce.rb CHANGED
@@ -1,2 +1,3 @@
1
- require 'rest'
2
1
  require 'tunnel'
2
+ require 'rest'
3
+
data/lib/tunnel.rb CHANGED
@@ -1,19 +1,20 @@
1
+ require 'net/telnet'
2
+ require 'net/ssh'
3
+ require 'net/ssh/gateway'
4
+ require 'gateway_ext'
5
+
1
6
  module Sauce
2
7
  # Interact with a Sauce Labs tunnel as if it were a ruby object
3
8
  class Tunnel
4
9
  class NoIDError < StandardError; end #nodoc
5
10
 
6
- attr_accessor :application_address, :username, :access_key, :timeout
7
- attr_accessor :status, :owner, :creation_time, :id, :host
11
+ #{"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"]}
8
12
 
9
- def self.create(options)
10
- response = JSON.parse @@client[:tunnels].post(options.to_json, :content_type => 'application/json')
11
- Tunnel.new response
12
- end
13
-
14
- def initialize(options)
15
- build!(options)
16
- end
13
+ attr_accessor :owner, :access_key, :status
14
+ attr_accessor :id, :host, :domain_names, :timeout
15
+ attr_accessor :launch_time, :created_at, :updated_at
16
+
17
+ attr_accessor :application_address, :gateway, :port, :thread
17
18
 
18
19
  # Get the class @@client.
19
20
  # TODO: Consider metaprogramming this away
@@ -27,6 +28,18 @@ module Sauce
27
28
  @@client = client
28
29
  end
29
30
 
31
+ # Get the class @@client.
32
+ # TODO: Consider metaprogramming this away
33
+ def self.account
34
+ @@account
35
+ end
36
+
37
+ # Set the class @@client.
38
+ # TODO: Consider metaprogramming this away
39
+ def self.account=(account)
40
+ @@account = account
41
+ end
42
+
30
43
  def self.first
31
44
  self.all.first
32
45
  end
@@ -44,8 +57,21 @@ module Sauce
44
57
  self.all.each { |tunnel| tunnel.destroy }
45
58
  end
46
59
 
60
+ # Creates a new tunnel machine
61
+ def self.create(options)
62
+ response = JSON.parse @@client[:tunnels].post(options.to_json, :content_type => 'application/json')
63
+ #puts response.inspect
64
+ Tunnel.new response
65
+ end
66
+
67
+ # Creates an instance representing a machine, but does not actually create the machine. See #create for that.
68
+ def initialize(options)
69
+ build!(options)
70
+ end
71
+
47
72
  # Hits the destroy url for this tunnel, and then refreshes. Keep in mind it takes some time to completely teardown a tunnel.
48
73
  def destroy
74
+ close_gateway
49
75
  response = @@client["tunnels/#{@id}"].delete
50
76
  refresh!
51
77
  end
@@ -53,11 +79,47 @@ module Sauce
53
79
  # Retrieves the latest information on this tunnel from the Sauce Labs' server
54
80
  def refresh!
55
81
  response = JSON.parse @@client["tunnels/#{@id}"].get
82
+ #puts "\Tunnel refresh with: #{response.inspect}"
56
83
  build! response
84
+ self
85
+ end
86
+
87
+ # Shortcut method to find out if a tunnel is marked as dead
88
+ def preparing?
89
+ refresh!
90
+ status == "new" or status == "booting"
91
+ end
92
+
93
+ # Shortcut method to find out if a tunnel is marked as dead
94
+ def halting?
95
+ refresh!
96
+ status == "halting"
97
+ end
98
+
99
+ # Shortcut method to find out if a tunnel is marked as dead
100
+ def terminated?
101
+ refresh!
102
+ status == "terminated"
103
+ end
104
+
105
+ # A tunnel is healthy if 1.) its status is "running" and 2.) It says hello
106
+ def healthy?
107
+ # TODO: Implement 3.) We can reach through and touch a service on the reverse end of the tunnel
108
+ refresh!
109
+ =begin
110
+ puts "\tRunning? #{self.status == 'running'}"
111
+ puts "\tSays hello? #{self.says_hello?}"
112
+ puts "\tThread running? #{self.still_running?}"
113
+ =end
114
+ return true if not self.terminated? and self.status == "running" and self.says_hello? and self.still_running?
115
+ return false
57
116
  end
58
117
 
59
- # Sauce Labs' server will say hello on port 1025 as a sanity check. If no hello, something is wrong. TODO: Make it say hello on port 1025. Currently a hack.
118
+ # Sauce Labs' server will say hello on port 1025 as a sanity check. If no hello, something is wrong.
119
+ # TODO: Make it say hello on port 1025. Currently a hack.
60
120
  def says_hello?(options={})
121
+ return false unless self.status == "running"
122
+
61
123
  # TODO: Read from options if necessary
62
124
  connection = {}
63
125
  connection[:host] = @host
@@ -66,6 +128,8 @@ module Sauce
66
128
  connection[:telnet_mode] = true
67
129
  connection[:timeout] = 10
68
130
 
131
+ #puts "telnet: #{connection.inspect}"
132
+
69
133
  host = Net::Telnet::new("Host" => connection[:host],
70
134
  "Port" => connection[:port],
71
135
  "Prompt" => connection[:prompt],
@@ -78,15 +142,77 @@ module Sauce
78
142
  line[0,prefix.length] == prefix
79
143
  end
80
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
+
81
202
  protected
82
203
 
83
204
  # Sets all internal variables from a hash
84
205
  def build!(options)
206
+ #puts "\tBuild with #{options.inspect}"
85
207
  @status = options["Status"]
86
- @owner = options["Owner"]
87
- @id = options["_id"]
88
- @id = options["id"] if @id.nil? or @id.empty?
89
- @host = options["Host"]
208
+ @owner = options["Owner"]
209
+ @id = options["_id"]
210
+ @id = options["id"] if @id.nil? or @id.empty?
211
+ @host = options["Host"]
212
+ @created_at = options["CreationTime"]
213
+ @updated_at = options["ModificationTime"]
214
+ @launch_time = options["LaunchTime"]
215
+ @domain_names = options["DomainNames"]
90
216
 
91
217
  raise NoIDError if @id.nil? or @id.empty?
92
218
  end
data/test/debug.rb CHANGED
@@ -1,11 +1,34 @@
1
- require 'helper'
1
+ require 'irb_boot'
2
2
 
3
3
  c = Sauce::Client.new(:username => "sgrove",
4
- :access_key => "4c592ce3-8f45-4cd6-8e3e-65b9f0b173d0")
4
+ :access_key => "733a44e2-4226-488f-8126-6f6d59bdf386",
5
+ :ip => "67.188.3.10")
6
+
7
+ =begin
8
+ t = c.tunnels.first
5
9
 
6
10
  c.destroy_all_tunnels
7
11
  t = c.create_tunnel('DomainNames' => ["111.111.111.111"])
8
12
 
9
13
  puts c.tunnels.inspect
14
+ =end
10
15
 
11
- c.destroy_all_tunnels
16
+ t = c.tunnels.first
17
+
18
+ if t.nil?
19
+ puts "Starting a new tunnel"
20
+ t = c.tunnels.create("DomainNames" => ["sgrove.tst"])
21
+ until t.status == "running"
22
+ print "." ; STDOUT.flush
23
+ t.refresh!
24
+ sleep 1
25
+ end
26
+ end
27
+
28
+ puts t.inspect
29
+ t.open_gateway
30
+
31
+ puts "Checking to see if thread is running."
32
+ puts t.still_running?
33
+ puts t.thread.inspect
34
+ t.thread.join if t.still_running?
data/test/irb_boot.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'net/telnet'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'sauce'
data/test/test_sauce.rb CHANGED
@@ -65,6 +65,15 @@ class TestSauce < Test::Unit::TestCase
65
65
  end
66
66
 
67
67
  assert_equal true, tunnel.says_hello?
68
+
69
+ tunnel.destroy # cleanup
70
+ end
71
+
72
+ should "not attempt to telnet if status is not running" do
73
+ tunnel = @client.tunnels.create('DomainNames' => [@ip])
74
+
75
+ tunnel.status = "booting"
76
+ assert_equal false, tunnel.says_hello?
68
77
  end
69
78
 
70
79
  def teardown
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sauce
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Grove
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-18 00:00:00 -08:00
12
+ date: 2010-02-22 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -84,4 +84,5 @@ summary: Ruby access to Sauce Labs' features
84
84
  test_files:
85
85
  - test/debug.rb
86
86
  - test/helper.rb
87
+ - test/irb_boot.rb
87
88
  - test/test_sauce.rb