sauce 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +15 -16
- data/README.markdown +17 -15
- data/VERSION +1 -1
- data/lib/job.rb +135 -0
- data/lib/rest.rb +7 -1
- data/lib/sauce.rb +1 -0
- data/lib/tunnel.rb +1 -1
- data/test/test_jobs.rb +58 -0
- data/test/test_tunnels.rb +83 -0
- data/test/{test_sauce.rb → test_videos.rb} +0 -0
- metadata +8 -4
data/LICENSE
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
Copyright (c) 2009 Sauce Labs Inc
|
2
2
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
the following conditions:
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
10
9
|
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
13
12
|
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
OF
|
20
|
-
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.markdown
CHANGED
@@ -7,16 +7,17 @@ Features
|
|
7
7
|
--------
|
8
8
|
Current:
|
9
9
|
|
10
|
-
*
|
10
|
+
* ActiveRecord-like interface for tunnels: Find/create/destroy
|
11
|
+
* Same with jobs
|
11
12
|
|
12
13
|
Planned:
|
13
14
|
|
14
|
-
*
|
15
|
+
* Extend to automatic retrieval of jobs logs, videos, reverse tunnels
|
15
16
|
* Start/stop local instances of Sauce RC
|
16
17
|
|
17
18
|
Install
|
18
19
|
-------
|
19
|
-
Make sure you're pulling in gems from
|
20
|
+
Make sure you're pulling in gems from http://rubygems.org/, and then:
|
20
21
|
|
21
22
|
`gem install sauce`
|
22
23
|
|
@@ -29,20 +30,21 @@ Here's how to start a tunnel using the Sauce gem
|
|
29
30
|
account = YAML.load_file "live_account.yml"
|
30
31
|
client = Sauce::Client.new(:username => account["username"],
|
31
32
|
:access_key => account["access_key"])
|
32
|
-
|
33
|
+
|
34
|
+
tunnel = client.tunnel.create('DomainNames' => ["example.com"])
|
33
35
|
tunnel.refresh!
|
34
36
|
|
35
|
-
client.tunnels # => [#<Sauce::Tunnel:0x1250e6c
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
tunnel.destroy
|
37
|
+
client.tunnels.all # => [#<Sauce::Tunnel:0x1250e6c
|
38
|
+
@host=nil,
|
39
|
+
@status="running",
|
40
|
+
@id="389a1c2a3d49861474c512e9a904be9e",
|
41
|
+
@client=#<RestClient::Resource:0x1257fb4
|
42
|
+
@block=nil,
|
43
|
+
@url="https://username:access_key@saucelabs.com/rest/username/",
|
44
|
+
@options={}>,
|
45
|
+
@owner="username">]
|
46
|
+
|
47
|
+
tunnel.destroy
|
46
48
|
|
47
49
|
Note on Patches/Pull Requests
|
48
50
|
-----------------------------
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/job.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'net/telnet'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'net/ssh/gateway'
|
4
|
+
require 'gateway_ext'
|
5
|
+
|
6
|
+
module Sauce
|
7
|
+
# Interact with a Sauce Labs selenium jobs as if it were a ruby object
|
8
|
+
class Job
|
9
|
+
|
10
|
+
#{"BrowserVersion": "3.", "Name": "prsel_./spec/integration/people_a_1_spec.rb", "_rev": "5-228269313", "CreationTime": 1266698090, "AssignmentTime": 1266698097, "Server": "10.212.146.145:4443", "AssignedTo": "f663372ba04444ce8cb3e6f61503f304", "ChefStartTime": 1266698101, "EndTime": 1266698139, "Type": "job", "Interactive": "true", "Status": "complete", "SeleniumServerLogUploadRequest": {"bucket": "sauce-userdata", "key": "sgrove/6337fe576deba0ba278dc1b5dfceac5f/selenium-server.log"}, "Tags": [], "ResultId": "6337fe576deba0ba278dc1b5dfceac5f", "AttachmentRequests": {}, "ModificationTime": 1266698139, "Browser": "firefox", "StartTime": 1266698101, "Owner": "sgrove", "_id": "01fc48caba6d15b46fad79e1b0562bbe", "OS": "Linux", "VideoUploadRequest": {"bucket": "sauce-userdata", "key": "sgrove/6337fe576deba0ba278dc1b5dfceac5f/video.flv"}}
|
11
|
+
|
12
|
+
attr_accessor :owner, :id, :name, :_rev, :server, :assigned_to, :sauce_type, :interactive, :status,:tags, :result_id
|
13
|
+
attr_accessor :selenium_server_log_upload_request, :attachment_requests, :videoupload_request
|
14
|
+
attr_accessor :creation_time, :assignment_time, :chef_start_time, :end_time, :modification_time, :start_time
|
15
|
+
attr_accessor :os, :browser, :browser_version
|
16
|
+
|
17
|
+
# TODO: Buckets for logs and videos
|
18
|
+
|
19
|
+
# Get the class @@client.
|
20
|
+
# TODO: Consider metaprogramming this away
|
21
|
+
def self.client
|
22
|
+
@@client
|
23
|
+
end
|
24
|
+
|
25
|
+
# Set the class @@client.
|
26
|
+
# TODO: Consider metaprogramming this away
|
27
|
+
def self.client=(client)
|
28
|
+
@@client = client
|
29
|
+
end
|
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
|
+
|
43
|
+
def self.first
|
44
|
+
self.all.first
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.last
|
48
|
+
self.all.last
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.all
|
52
|
+
=begin
|
53
|
+
responses = JSON.parse @@client["jobs/recent"].get
|
54
|
+
return responses.collect{|response| Sauce::Job.new(response)}
|
55
|
+
=end
|
56
|
+
return self.complete_jobs + self.in_progress_jobs
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.destroy
|
60
|
+
self.all.each { |tunnel| tunnel.destroy }
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.find id
|
64
|
+
#puts "GET-URL: #{@@client.url}jobs/#{id}"
|
65
|
+
Sauce::Job.new JSON.parse(@@client["jobs/#{id}"].get)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.complete_jobs
|
69
|
+
responses = JSON.parse @@client["complete-jobs"].get
|
70
|
+
start = Time.now
|
71
|
+
jobs = responses["jobs"].collect{|response| Sauce::Job.find(response["id"])}
|
72
|
+
lapsed = Time.now - start
|
73
|
+
puts "Took #{lapsed} seconds"
|
74
|
+
return jobs
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.in_progress_jobs
|
78
|
+
responses = JSON.parse @@client["in-progress-jobs"].get
|
79
|
+
return [] if responses == []
|
80
|
+
start = Time.now
|
81
|
+
jobs = responses["jobs"].collect{|response| Sauce::Job.find(response["id"])}
|
82
|
+
lapsed = Time.now - start
|
83
|
+
puts "Took #{lapsed} seconds"
|
84
|
+
return jobs
|
85
|
+
end
|
86
|
+
|
87
|
+
# Creates an instance representing a job.
|
88
|
+
def initialize(options)
|
89
|
+
build!(options)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Retrieves the latest information on this job from the Sauce Labs' server
|
93
|
+
def refresh!
|
94
|
+
response = JSON.parse @@client["jobs/#{@id}"].get
|
95
|
+
puts "\tjob refresh with: #{response.inspect}"
|
96
|
+
build! response
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
# Sets all internal variables from a hash
|
103
|
+
def build!(options)
|
104
|
+
#puts "\tBuild with #{options.inspect}"
|
105
|
+
|
106
|
+
@owner = options["Owner"]
|
107
|
+
@id = options["_id"]
|
108
|
+
@id = options["id"] if @id.nil? or @id.empty?
|
109
|
+
@name = options["Name"]
|
110
|
+
@_rev = options["_rev"]
|
111
|
+
@server = options["Server"]
|
112
|
+
@assigned_to = options["AssignedTo"]
|
113
|
+
|
114
|
+
@sauce_type = options["Type"]
|
115
|
+
@interactive = options["Interactive"]
|
116
|
+
@status = options["Status"]
|
117
|
+
@tags = options["Tags"]
|
118
|
+
@result_id = options["ResultId"]
|
119
|
+
|
120
|
+
@os = options["OS"]
|
121
|
+
@browser = options["Browser"]
|
122
|
+
@browser_version = options["BrowserVersion"]
|
123
|
+
|
124
|
+
# TODO: Should this be created_at and updated_at? Probably.
|
125
|
+
@creation_time = options["CreationTime"]
|
126
|
+
@assignment_time = options["AssignmentTime"]
|
127
|
+
@chef_start_time = options["ChefStartTime"]
|
128
|
+
@end_time = options["EndTime"]
|
129
|
+
@modification_time = options["ModificationTime"]
|
130
|
+
@start_time = options["StartTime"]
|
131
|
+
|
132
|
+
raise NoIDError if @id.nil? or @id.empty?
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/rest.rb
CHANGED
@@ -8,7 +8,7 @@ module Sauce
|
|
8
8
|
class MisconfiguredError < StandardError; end #nodoc
|
9
9
|
|
10
10
|
attr_accessor :username, :access_key, :client, :ip, :api_url
|
11
|
-
attr_accessor :tunnels
|
11
|
+
attr_accessor :tunnels, :jobs
|
12
12
|
|
13
13
|
def initialize(options)
|
14
14
|
@username = options[:username]
|
@@ -24,6 +24,12 @@ module Sauce
|
|
24
24
|
@tunnels.account = {:username => @username,
|
25
25
|
:access_key => @access_key,
|
26
26
|
:ip => @ip}
|
27
|
+
|
28
|
+
@jobs = Sauce::Job
|
29
|
+
@jobs.client = @client
|
30
|
+
@jobs.account = {:username => @username,
|
31
|
+
:access_key => @access_key,
|
32
|
+
:ip => @ip}
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
data/lib/sauce.rb
CHANGED
data/lib/tunnel.rb
CHANGED
data/test/test_jobs.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class TestSauce < Test::Unit::TestCase
|
5
|
+
context "A jobs instance" do
|
6
|
+
setup do
|
7
|
+
# Create this file and put in your details to run the tests
|
8
|
+
account = YAML.load_file "live_account.yml"
|
9
|
+
@username = account["username"]
|
10
|
+
@access_key = account["access_key"]
|
11
|
+
@ip = account["ip"]
|
12
|
+
@client = Sauce::Client.new(:username => @username,
|
13
|
+
:access_key => @access_key)
|
14
|
+
end
|
15
|
+
|
16
|
+
should "initialize with passed variables" do
|
17
|
+
job_json = JSON.parse '{"BrowserVersion": "3.", "Name": "example_job/name.rb", "_rev": "5-228269313", "CreationTime": 1266698090, "AssignmentTime": 1266698097, "Server": "192.168.0.1:4443", "AssignedTo": "f663372ba04444ce8cb3e6f61503f304", "ChefStartTime": 1266698101, "EndTime": 1266698139, "Type": "job", "Interactive": "true", "Status": "complete", "SeleniumServerLogUploadRequest": {"bucket": "sauce-userdata", "key": "sgrove/6337fe576deba0ba278dc1b5dfceac5f/selenium-server.log"}, "Tags": ["tag_1", "tag_2"], "ResultId": "6337fe576deba0ba278dc1b5dfceac5f", "AttachmentRequests": {}, "ModificationTime": 1266698139, "Browser": "firefox", "StartTime": 1266698101, "Owner": "sgrove", "_id": "01fc48caba6d15b46fad79e1b0562bbe", "OS": "Linux", "VideoUploadRequest": {"bucket": "sauce-userdata", "key": "sgrove/6337fe576deba0ba278dc1b5dfceac5f/video.flv"}}'
|
18
|
+
|
19
|
+
client = Sauce::Client.new(:username => "test_user",
|
20
|
+
:access_key => "abc123")
|
21
|
+
|
22
|
+
job = client.jobs.new(job_json)
|
23
|
+
|
24
|
+
assert_equal "sgrove", job.owner
|
25
|
+
assert_equal "01fc48caba6d15b46fad79e1b0562bbe", job.id
|
26
|
+
assert_equal "example_job/name.rb", job.name
|
27
|
+
assert_equal "5-228269313", job._rev
|
28
|
+
assert_equal "192.168.0.1:4443", job.server
|
29
|
+
assert_equal "f663372ba04444ce8cb3e6f61503f304", job.assigned_to
|
30
|
+
|
31
|
+
assert_equal "job", job.sauce_type
|
32
|
+
assert_equal "true", job.interactive
|
33
|
+
assert_equal "complete", job.status
|
34
|
+
assert_equal ["tag_1", "tag_2"], job.tags
|
35
|
+
assert_equal "6337fe576deba0ba278dc1b5dfceac5f", job.result_id
|
36
|
+
|
37
|
+
# TODO: Buckets
|
38
|
+
#assert_equal , job.selenium_server_log_upload_request
|
39
|
+
#assert_equal , job.attachment_requests
|
40
|
+
#assert_equal , job.videoupload_request
|
41
|
+
|
42
|
+
assert_equal "Linux", job.os
|
43
|
+
assert_equal "firefox", job.browser
|
44
|
+
assert_equal "3.", job.browser_version
|
45
|
+
|
46
|
+
assert_equal 1266698090, job.creation_time
|
47
|
+
assert_equal 1266698097, job.assignment_time
|
48
|
+
assert_equal 1266698101, job.chef_start_time
|
49
|
+
assert_equal 1266698139, job.end_time
|
50
|
+
assert_equal 1266698139, job.modification_time
|
51
|
+
assert_equal 1266698101, job.start_time
|
52
|
+
end
|
53
|
+
|
54
|
+
def teardown
|
55
|
+
@client.tunnels.destroy
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSauce < Test::Unit::TestCase
|
4
|
+
context "A Client instance" do
|
5
|
+
setup do
|
6
|
+
# Create this file and put in your details to run the tests
|
7
|
+
account = YAML.load_file "live_account.yml"
|
8
|
+
@username = account["username"]
|
9
|
+
@access_key = account["access_key"]
|
10
|
+
@ip = account["ip"]
|
11
|
+
@client = Sauce::Client.new(:username => @username,
|
12
|
+
:access_key => @access_key)
|
13
|
+
@client.tunnels.destroy_all
|
14
|
+
end
|
15
|
+
|
16
|
+
should "initialize with passed variables" do
|
17
|
+
client = Sauce::Client.new(:username => "test_user",
|
18
|
+
:access_key => "abc123")
|
19
|
+
assert_equal client.api_url, "https://test_user:abc123@saucelabs.com/rest/test_user/"
|
20
|
+
end
|
21
|
+
|
22
|
+
should "create a tunnel with the current user" do
|
23
|
+
tunnel = @client.tunnels.create('DomainNames' => ["192.168.0.110"])
|
24
|
+
tunnel.refresh!
|
25
|
+
assert_not_nil tunnel
|
26
|
+
assert_equal @username, tunnel.owner
|
27
|
+
end
|
28
|
+
|
29
|
+
should "list current tunnels" do
|
30
|
+
@client.tunnels.create('DomainNames' => ["192.168.0.111"])
|
31
|
+
@client.tunnels.create('DomainNames' => ["192.168.0.112"])
|
32
|
+
@client.tunnels.create('DomainNames' => ["192.168.0.113"])
|
33
|
+
|
34
|
+
tunnels = @client.tunnels.all
|
35
|
+
assert_equal 3, tunnels.select{|t| t.status != "halting"}.count
|
36
|
+
end
|
37
|
+
|
38
|
+
should "destroy a tunnel" do
|
39
|
+
tunnel = @client.tunnels.create('DomainNames' => ["192.168.0.114"])
|
40
|
+
tunnel.destroy
|
41
|
+
assert_equal "halting", tunnel.status
|
42
|
+
end
|
43
|
+
|
44
|
+
should "destroy all tunnels" do
|
45
|
+
tunnel = @client.tunnels.create('DomainNames' => ["192.168.0.115"])
|
46
|
+
tunnel = @client.tunnels.create('DomainNames' => ["192.168.0.116"])
|
47
|
+
tunnel = @client.tunnels.create('DomainNames' => ["192.168.0.117"])
|
48
|
+
|
49
|
+
@client.tunnels.destroy_all
|
50
|
+
|
51
|
+
@client.tunnels.all.each do |tunnel|
|
52
|
+
assert_equal "halting", tunnel.status
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
should "say hello on port 1025 if healthy" do
|
57
|
+
tunnel = @client.tunnels.create('DomainNames' => [@ip])
|
58
|
+
|
59
|
+
max_retries = 30
|
60
|
+
retries = 0
|
61
|
+
until tunnel.status == "running" or retries >= max_retries
|
62
|
+
sleep 5
|
63
|
+
retries += 1
|
64
|
+
tunnel.refresh!
|
65
|
+
end
|
66
|
+
|
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?
|
77
|
+
end
|
78
|
+
|
79
|
+
def teardown
|
80
|
+
@client.tunnels.destroy_all
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
File without changes
|
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.
|
4
|
+
version: 0.3.0
|
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-
|
12
|
+
date: 2010-02-26 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -48,11 +48,13 @@ files:
|
|
48
48
|
- README.markdown
|
49
49
|
- Rakefile
|
50
50
|
- VERSION
|
51
|
+
- lib/job.rb
|
51
52
|
- lib/rest.rb
|
52
53
|
- lib/sauce.rb
|
53
54
|
- lib/tunnel.rb
|
54
55
|
- test/helper.rb
|
55
|
-
- test/
|
56
|
+
- test/test_jobs.rb
|
57
|
+
- test/test_tunnels.rb
|
56
58
|
has_rdoc: true
|
57
59
|
homepage: http://github.com/sgrove/sauce
|
58
60
|
licenses: []
|
@@ -85,4 +87,6 @@ test_files:
|
|
85
87
|
- test/debug.rb
|
86
88
|
- test/helper.rb
|
87
89
|
- test/irb_boot.rb
|
88
|
-
- test/
|
90
|
+
- test/test_jobs.rb
|
91
|
+
- test/test_tunnels.rb
|
92
|
+
- test/test_videos.rb
|