triton-internal 0.1.0
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.
- checksums.yaml +7 -0
- data/Users/thomas/tdh/triton/Gemfile +4 -0
- data/Users/thomas/tdh/triton/Gemfile.lock +51 -0
- data/Users/thomas/tdh/triton/LICENSE +21 -0
- data/Users/thomas/tdh/triton/README.md +87 -0
- data/Users/thomas/tdh/triton/Rakefile +6 -0
- data/Users/thomas/tdh/triton/bin/console +17 -0
- data/Users/thomas/tdh/triton/bin/setup +8 -0
- data/Users/thomas/tdh/triton/lib/triton/api_base.rb +120 -0
- data/Users/thomas/tdh/triton/lib/triton/cnapi.rb +78 -0
- data/Users/thomas/tdh/triton/lib/triton/imgapi.rb +38 -0
- data/Users/thomas/tdh/triton/lib/triton/indifferent_hash.rb +120 -0
- data/Users/thomas/tdh/triton/lib/triton/internal.rb +7 -0
- data/Users/thomas/tdh/triton/lib/triton/napi.rb +51 -0
- data/Users/thomas/tdh/triton/lib/triton/papi.rb +15 -0
- data/Users/thomas/tdh/triton/lib/triton/remote_exception.rb +53 -0
- data/Users/thomas/tdh/triton/lib/triton/version.rb +3 -0
- data/Users/thomas/tdh/triton/lib/triton/vmapi.rb +50 -0
- data/Users/thomas/tdh/triton/lib/triton.rb +57 -0
- data/Users/thomas/tdh/triton/pkg/triton-internal-0.1.0.gem +0 -0
- data/Users/thomas/tdh/triton/spec/api_base_spec.rb +288 -0
- data/Users/thomas/tdh/triton/spec/spec_helper.rb +16 -0
- data/Users/thomas/tdh/triton/spec/triton_spec.rb +32 -0
- data/Users/thomas/tdh/triton/triton-internal.gemspec +30 -0
- metadata +138 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
module Triton
|
2
|
+
|
3
|
+
# This module "magically" defines any constants as
|
4
|
+
# RemoteExceptions, so when the server send back
|
5
|
+
# error structures such as:
|
6
|
+
#
|
7
|
+
# {"code" => "WidgetInvalid", ...}
|
8
|
+
#
|
9
|
+
# it means you can:
|
10
|
+
#
|
11
|
+
# begin
|
12
|
+
# ...
|
13
|
+
# rescue Triton::RemoteException::WidgetInvalid
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# without having to exhaustively define all such exceptions beforehand
|
17
|
+
module RemoteExceptions
|
18
|
+
def self.const_missing(name)
|
19
|
+
klass = Class.new(RemoteException)
|
20
|
+
RemoteExceptions.const_set(name, klass)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# In tests, you can also `raise Triton::RemoteExceptions::WidgetFailure, 'the-message'
|
26
|
+
# and also `raise Triton::RemoteException, { "code" => 'WidgetFailure', 'message' => 'the-message' }
|
27
|
+
# with the same behaviour
|
28
|
+
#
|
29
|
+
class RemoteException < RuntimeError
|
30
|
+
def self.exception(payload)
|
31
|
+
if payload.is_a?(Hash) && payload.keys.include?('code')
|
32
|
+
const = Triton::RemoteExceptions.const_get(payload['code'].intern)
|
33
|
+
const.new(payload)
|
34
|
+
else
|
35
|
+
self.new(payload)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :errors, :body, :code
|
40
|
+
|
41
|
+
def initialize(hash_or_string)
|
42
|
+
if hash_or_string.is_a?(Hash)
|
43
|
+
@errors = hash_or_string['errors']
|
44
|
+
@code = hash_or_string['code']
|
45
|
+
@body = hash_or_string
|
46
|
+
super(hash_or_string.fetch('message') { body.to_s })
|
47
|
+
else
|
48
|
+
super(hash_or_string)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Triton
|
2
|
+
class Vmapi < ApiBase
|
3
|
+
|
4
|
+
# The commit used to compile this itnerface:
|
5
|
+
# https://github.com/joyent/sdc-vmapi/blob/590a4e09c0c76093f66f4ff69d6b4fd66de09bb6/docs/index.md
|
6
|
+
#
|
7
|
+
|
8
|
+
self.name = "vmapi"
|
9
|
+
|
10
|
+
call('Ping', :method => :get, :path => '/ping')
|
11
|
+
call('ListVms', :method => :get, :path => '/vms' )
|
12
|
+
call('GetVm', :method => :get, :path => '/vms/:uuid')
|
13
|
+
call('CreateVm', :method => :post, :path => '/vms')
|
14
|
+
call("DeleteVm", :method => :delete, :path => '/vms/:uuid')
|
15
|
+
|
16
|
+
{
|
17
|
+
'StartVm' => 'start',
|
18
|
+
'StopVm' => 'stop',
|
19
|
+
'RebootVm' => 'reboot',
|
20
|
+
'ReprovisionVm' => 'reprovision',
|
21
|
+
'UpdateVm' => 'update',
|
22
|
+
'AddNics' => 'add_nics',
|
23
|
+
'UpdateNics' => 'update_nics',
|
24
|
+
'RemoveNics' => 'remove_nics',
|
25
|
+
'CreateSnapshot' => 'create_snapshot',
|
26
|
+
'DeleteSnapshot' => 'delete_snapshot',
|
27
|
+
'RollbackSnapshot' => 'rollback_snapshot'
|
28
|
+
}.each do |api_name, action_name|
|
29
|
+
call(api_name, :method => :post, :path => "/vms/:uuid?action=#{action_name}")
|
30
|
+
end
|
31
|
+
|
32
|
+
# :type in the following calls must be one of 'tags', 'customer_metadata', or 'internal_metadata'
|
33
|
+
call("ListMetadata", :method => :get, :path => '/vms/:uuid/:type')
|
34
|
+
call("GetMetadata", :method => :get, :path => '/vms/:uuid/:type/:key')
|
35
|
+
call("AddMetadata", :method => :post, :path => '/vms/:uuid/:type', :body_param => 'metadata')
|
36
|
+
call("SetMetadata", :method => :put, :path => '/vms/:uuid/:type', :body_param => 'metadata')
|
37
|
+
call("DeleteMetadata", :method => :delete, :path => '/vms/:uuid/:type/:key')
|
38
|
+
call("DeleteAllMetadata", :method => :delete, :path => '/vms/:uuid/:type')
|
39
|
+
call("AddRoleTags", :method => :post, :path => '/vms/:uuid/role_tags')
|
40
|
+
call("SetRoleTags", :method => :put, :path => '/vms/:uuid/role_tags')
|
41
|
+
call("DeleteRoleTag", :method => :delete, :path => '/vms/:uuid/role_tags/:role_tag')
|
42
|
+
call("DeleteAllRoleTags", :method => :delete, :path => '/vms/:uuid/role_tags')
|
43
|
+
|
44
|
+
call("GetJobs", :method => :get, :path => '/jobs')
|
45
|
+
call("ListVmJobs", :method => :get, :path => '/vms/:uuid/jobs')
|
46
|
+
call("GetJob", :method => :get, :path => '/jobs/:uuid')
|
47
|
+
call("GetStatuses", :method => :get, :path => '/statuses')
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'triton/version'
|
2
|
+
require 'rest-client'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Triton
|
6
|
+
|
7
|
+
def self.suffix=(new_suffix)
|
8
|
+
@suffix = new_suffix
|
9
|
+
end
|
10
|
+
def self.suffix
|
11
|
+
@suffix
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def self.socks=(new_socks)
|
16
|
+
if new_socks
|
17
|
+
server,port = new_socks.to_s.split(":")
|
18
|
+
if port.nil?
|
19
|
+
port = server
|
20
|
+
server = "127.0.0.1"
|
21
|
+
end
|
22
|
+
begin
|
23
|
+
require 'socksify'
|
24
|
+
TCPSocket::socks_server = server
|
25
|
+
TCPSocket::socks_port = port.to_i
|
26
|
+
rescue LoadError
|
27
|
+
$stderr.puts "Could not load 'socksify' gem. Socks forwarding won't work."
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
TestModeLeak = Class.new(RuntimeError)
|
34
|
+
def self.test_mode=(value)
|
35
|
+
@test_mode = value
|
36
|
+
end
|
37
|
+
def self.test_mode
|
38
|
+
@test_mode
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.logger=(logger)
|
42
|
+
@logger = logger
|
43
|
+
end
|
44
|
+
def self.logger
|
45
|
+
@logger ||= Logger.new("/dev/null")
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'triton/remote_exception'
|
49
|
+
require 'triton/api_base'
|
50
|
+
require 'triton/vmapi'
|
51
|
+
require 'triton/cnapi'
|
52
|
+
require 'triton/napi'
|
53
|
+
require 'triton/papi'
|
54
|
+
require 'triton/imgapi'
|
55
|
+
require 'triton/indifferent_hash'
|
56
|
+
|
57
|
+
end
|
Binary file
|
@@ -0,0 +1,288 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ApiMapping" do
|
4
|
+
|
5
|
+
let(:fakeapi) do
|
6
|
+
Class.new(Triton::ApiBase) do
|
7
|
+
self.name = "fakeapi"
|
8
|
+
call("TestMethod", {
|
9
|
+
:method => :post,
|
10
|
+
:path => "/testmethod/path"
|
11
|
+
})
|
12
|
+
|
13
|
+
call("GetMethod", {
|
14
|
+
:path => "/testmethod/path"
|
15
|
+
})
|
16
|
+
|
17
|
+
call("GetThing", {
|
18
|
+
:path => "/things/:thing/foo"
|
19
|
+
})
|
20
|
+
|
21
|
+
call("PostThing", {
|
22
|
+
:method => :post,
|
23
|
+
:path => "/things/:thing"
|
24
|
+
})
|
25
|
+
|
26
|
+
call("GetThingWithQueryString", {
|
27
|
+
:path => "/things/:thing/foo?a=b"
|
28
|
+
})
|
29
|
+
|
30
|
+
call("SetTags", {
|
31
|
+
:method => :post,
|
32
|
+
:path => "/thing/:id/tag",
|
33
|
+
:body_param => :metadata
|
34
|
+
})
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "instance behaviour" do
|
40
|
+
|
41
|
+
subject { fakeapi.new("TestMethod") }
|
42
|
+
|
43
|
+
it "should memoise the request" do
|
44
|
+
first_request = subject.request
|
45
|
+
expect(subject.request.object_id).to eq(first_request.object_id)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should pass execute to the request" do
|
49
|
+
expect(subject.request).to receive(:execute).and_return("{}")
|
50
|
+
subject.execute
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have a shortcut to execute the method from the class" do
|
54
|
+
expect(fakeapi).to respond_to(:execute)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "init - when the call isn't defined" do
|
59
|
+
it "should raise an exception if the call isn't recognised" do
|
60
|
+
expect { fakeapi.new("Unknown") }.to raise_exception(Triton::ApiBase::UnknownCall)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should be a NoMethodError" do
|
64
|
+
expect(Triton::ApiBase::UnknownCall.new).to be_a(NoMethodError)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "response handling" do
|
69
|
+
subject { fakeapi.new("TestMethod") }
|
70
|
+
|
71
|
+
it "should decode the payload as JSON" do
|
72
|
+
allow(subject.request).to receive(:execute).and_return('{"something": "here"}')
|
73
|
+
expect(subject.execute).to eq({"something" => "here"})
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return a hash with indifferent key access" do
|
77
|
+
allow(subject.request).to receive(:execute).and_return('{"something": "here", "nested": {"something": "inner"}}')
|
78
|
+
expect(subject.execute[:something]).to eq("here")
|
79
|
+
expect(subject.execute['something']).to eq("here")
|
80
|
+
expect(subject.execute[:nested][:something]).to eq("inner")
|
81
|
+
expect(subject.execute[:nested]['something']).to eq("inner")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "response exception handling" do
|
86
|
+
subject { fakeapi.new("TestMethod") }
|
87
|
+
|
88
|
+
let(:exception) { RestClient::Exception.new(double("Response", :body => "body"))}
|
89
|
+
|
90
|
+
before do
|
91
|
+
# Simulate a RestClient exception when we execute
|
92
|
+
allow(subject.request).to receive(:execute).and_raise(exception)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should re-raise the original RestClient exception if the body doesn't contain valid JSON" do
|
96
|
+
expect { subject.execute }.to raise_exception(exception)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should raise a Triton::RemoteException if the JSON decoded, but doesn't contain a 'code' field" do
|
100
|
+
allow(exception.response).to receive(:body).and_return("{}")
|
101
|
+
expect { subject.execute }.to raise_exception(Triton::RemoteException)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should synthesize an exception class if a 'code' is present" do
|
105
|
+
allow(exception.response).to receive(:body).and_return('{"code": "ItScrewedUp"}')
|
106
|
+
expect { subject.execute }.to raise_exception(Triton::RemoteExceptions::ItScrewedUp)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should be possible to raise a RemoteException with a struct" do
|
110
|
+
expect do
|
111
|
+
raise Triton::RemoteExceptions::RemoteException, { 'code' => 'ResourceNotFound', 'message' => 'VM not found'}
|
112
|
+
end.to raise_exception(Triton::RemoteExceptions::ResourceNotFound, 'VM not found')
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should be possible to raise a RemoteException with a message directly" do
|
116
|
+
expect do
|
117
|
+
raise Triton::RemoteExceptions::ResourceNotFound, 'VM not found'
|
118
|
+
end.to raise_exception(Triton::RemoteExceptions::ResourceNotFound, 'VM not found')
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should be possible to raise a RemoteException from a mock with a message in a test" do
|
122
|
+
object = Object.new
|
123
|
+
allow(object).to receive(:crash).and_raise(Triton::RemoteExceptions::ResourceNotFound, 'VM not found')
|
124
|
+
|
125
|
+
expect do
|
126
|
+
object.crash
|
127
|
+
end.to raise_exception(Triton::RemoteExceptions::ResourceNotFound, 'VM not found')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "request" do
|
132
|
+
subject { fakeapi.new("TestMethod").request }
|
133
|
+
|
134
|
+
it "should build a RestClient request" do
|
135
|
+
expect(subject).to be_a(RestClient::Request)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should use the specified name as the first part of the hostname" do
|
139
|
+
expect(subject.url).to match(%r{^http://fakeapi})
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should append the configured suffix to the hostname" do
|
143
|
+
expect(subject.url).to match(%r{^http://fakeapi.test/})
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should append the path to the url" do
|
147
|
+
expect(URI.parse(subject.url).path).to eq("/testmethod/path")
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
it "should set the method" do
|
152
|
+
expect(subject.method).to eq(:post)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should default the method to :get" do
|
156
|
+
expect(fakeapi.new("GetMethod").request.method).to eq(:get)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "path parametisation" do
|
161
|
+
it "should replace any :<word> values with the associated argument" do
|
162
|
+
expect(URI.parse(fakeapi.new("GetThing", :thing => "IDENT").request.url).path).to eq("/things/IDENT/foo")
|
163
|
+
end
|
164
|
+
it "should URL encode any value" do
|
165
|
+
expect(URI.parse(fakeapi.new("GetThing", :thing => "IDE/NT").request.url).path).to eq("/things/IDE%2FNT/foo")
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should exclude any arguments used to build the URL from the query string of GET requests" do
|
169
|
+
request = fakeapi.new("GetThing", 'thing' => "123", :foo => "bar").request
|
170
|
+
expect(URI.parse(request.url).query).to eq("foo=bar")
|
171
|
+
end
|
172
|
+
it "should exclude any arguments used to build the URL from the payload of non-get requests" do
|
173
|
+
request = fakeapi.new("PostThing", 'thing' => "123", :foo => "bar").request
|
174
|
+
expect(URI.parse(request.url).path).to eq("/things/123")
|
175
|
+
expect(JSON.load(request.payload)).to eq("foo" => "bar")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should accept application/json" do
|
180
|
+
expect(fakeapi.new("GetThing", :thing => "IDENT").request.headers['Accept']).to eq("application/json")
|
181
|
+
expect(fakeapi.new("TestMethod").request.headers['Accept']).to eq("application/json")
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "arguments - GET requests" do
|
185
|
+
subject { fakeapi.new("GetMethod", :foo=>"bar/baz", :bar=>"baz").request }
|
186
|
+
it "should urlencode and append to the URL as a query string" do
|
187
|
+
expect(URI.parse(subject.url).query).to eq("foo=bar%2Fbaz&bar=baz")
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should append carefully if there is already a query string" do
|
191
|
+
url = fakeapi.new("GetThingWithQueryString", :thing => 1, :foo=>"bar", :bar=>"foo/bar").request.url
|
192
|
+
expect(URI.parse(url).query).to eq("a=b&foo=bar&bar=foo%2Fbar")
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should not set a payload" do
|
197
|
+
expect(subject.payload).to be_nil
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should not set a Content-Type header" do
|
201
|
+
expect(subject.headers["Content-Type"]).to be_nil
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "arguments - non-GET" do
|
206
|
+
subject { fakeapi.new("TestMethod", 'some' => 'args', :live => :here).request }
|
207
|
+
|
208
|
+
it "should set the Content-Body to application/json" do
|
209
|
+
expect(subject.headers["Content-Type"]).to eq("application/json")
|
210
|
+
end
|
211
|
+
it "should serialize the arguments to JSON as the payload" do
|
212
|
+
expect(JSON.load(subject.payload)).to eq({'some' => 'args', 'live' => 'here'})
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should generate a snake-case function call from the Api name" do
|
218
|
+
expect(fakeapi).to respond_to(:get_method)
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
describe "camelise" do
|
223
|
+
it "should return a camel_case string" do
|
224
|
+
expect("foo".camelise).to eq("Foo")
|
225
|
+
expect("foo_bar".camelise).to eq("FooBar")
|
226
|
+
expect("foo_bar_baz".camelise).to eq("FooBarBaz")
|
227
|
+
expect("foo______bar_baz".camelise).to eq("FooBarBaz")
|
228
|
+
end
|
229
|
+
it "should return nil if an unexpected string is encountered" do
|
230
|
+
expect("something-wrong".camelise).to eq(nil)
|
231
|
+
expect("Capsyousay".camelise).to eq(nil)
|
232
|
+
expect("wow!".camelise).to eq(nil)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "test_mode" do
|
237
|
+
before do
|
238
|
+
Triton.test_mode = true
|
239
|
+
end
|
240
|
+
it "should raise an exception if a request is attempted when test_mode is set" do
|
241
|
+
expect do
|
242
|
+
fakeapi.test_method()
|
243
|
+
end.to raise_exception(Triton::TestModeLeak)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should include the Api call name in the exception" do
|
247
|
+
expect do
|
248
|
+
fakeapi.test_method()
|
249
|
+
end.to raise_exception do |ex|
|
250
|
+
expect(ex.message).to include("TestMethod")
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should include the call route in the exception" do
|
255
|
+
expect do
|
256
|
+
fakeapi.test_method()
|
257
|
+
end.to raise_exception do |ex|
|
258
|
+
expect(ex.message).to include("POST /testmethod/path")
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should include the parameters in the exception" do
|
263
|
+
expect do
|
264
|
+
fakeapi.test_method("param" => "value")
|
265
|
+
end.to raise_exception do |ex|
|
266
|
+
expect(ex.message).to include(%{"param": "value"})
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
describe "body_param option" do
|
273
|
+
|
274
|
+
subject { fakeapi.new('SetTags', :id => "the-id", :other_param => "other_value", :key => 'value', :metadata => { "tag1" => "value1", "tag2" => "value2" })}
|
275
|
+
|
276
|
+
it "should write the value of the body_param to the body" do
|
277
|
+
expect(JSON.load(subject.request.payload)).to eq({ "tag1" => "value1", "tag2" => "value2" })
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should set any additional parameters on the query-string" do
|
281
|
+
expect(URI.parse(subject.request.url).query).to eq("other_param=other_value&key=value")
|
282
|
+
end
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "triton/internal"
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
# Enable flags like --only-failures and --next-failure
|
6
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
7
|
+
|
8
|
+
config.before do
|
9
|
+
Triton.test_mode = false
|
10
|
+
Triton.suffix = "test"
|
11
|
+
end
|
12
|
+
|
13
|
+
config.expect_with :rspec do |c|
|
14
|
+
c.syntax = :expect
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Triton do
|
4
|
+
it "has a version number" do
|
5
|
+
expect(Triton::VERSION).not_to be nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have a configurable suffix" do
|
9
|
+
expect(Triton.suffix).to eq("test")
|
10
|
+
Triton.suffix = "foo"
|
11
|
+
expect(Triton.suffix).to eq("foo")
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "socks config" do
|
15
|
+
it "should accept host:port" do
|
16
|
+
Triton.socks = "1.2.3.4:5678"
|
17
|
+
expect(TCPSocket.socks_server).to eq("1.2.3.4")
|
18
|
+
expect(TCPSocket.socks_port).to eq(5678)
|
19
|
+
end
|
20
|
+
it "should accept string 'port' and assume localhost" do
|
21
|
+
Triton.socks = "5678"
|
22
|
+
expect(TCPSocket.socks_server).to eq("127.0.0.1")
|
23
|
+
expect(TCPSocket.socks_port).to eq(5678)
|
24
|
+
end
|
25
|
+
it "should accept an integer port, and assume localhost" do
|
26
|
+
Triton.socks = 5678
|
27
|
+
expect(TCPSocket.socks_server).to eq("127.0.0.1")
|
28
|
+
expect(TCPSocket.socks_port).to eq(5678)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'triton/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "triton-internal"
|
8
|
+
spec.version = Triton::VERSION
|
9
|
+
spec.authors = ["Thomas Haggett"]
|
10
|
+
spec.email = ["thomas-tritongem@haggett.org"]
|
11
|
+
spec.licenses = ['MIT']
|
12
|
+
|
13
|
+
spec.summary = %q{Library to wrap the Triton internal APIs}
|
14
|
+
spec.description = %q{Library that wraps all of the Joyent Triton Internal APIs in a consistent ruby interface allowing easier calling and mocking.}
|
15
|
+
spec.homepage = "http://thomas.haggett.org/"
|
16
|
+
|
17
|
+
spec.files = Dir.glob(File.expand_path("../**/*", __FILE__)).reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
|
28
|
+
spec.add_dependency 'rest-client', "~> 1.8"
|
29
|
+
spec.add_dependency 'socksify', "~> 1.7"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: triton-internal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas Haggett
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rest-client
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: socksify
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.7'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.7'
|
83
|
+
description: Library that wraps all of the Joyent Triton Internal APIs in a consistent
|
84
|
+
ruby interface allowing easier calling and mocking.
|
85
|
+
email:
|
86
|
+
- thomas-tritongem@haggett.org
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- "/Users/thomas/tdh/triton/Gemfile"
|
92
|
+
- "/Users/thomas/tdh/triton/Gemfile.lock"
|
93
|
+
- "/Users/thomas/tdh/triton/LICENSE"
|
94
|
+
- "/Users/thomas/tdh/triton/README.md"
|
95
|
+
- "/Users/thomas/tdh/triton/Rakefile"
|
96
|
+
- "/Users/thomas/tdh/triton/bin/console"
|
97
|
+
- "/Users/thomas/tdh/triton/bin/setup"
|
98
|
+
- "/Users/thomas/tdh/triton/lib/triton.rb"
|
99
|
+
- "/Users/thomas/tdh/triton/lib/triton/api_base.rb"
|
100
|
+
- "/Users/thomas/tdh/triton/lib/triton/cnapi.rb"
|
101
|
+
- "/Users/thomas/tdh/triton/lib/triton/imgapi.rb"
|
102
|
+
- "/Users/thomas/tdh/triton/lib/triton/indifferent_hash.rb"
|
103
|
+
- "/Users/thomas/tdh/triton/lib/triton/internal.rb"
|
104
|
+
- "/Users/thomas/tdh/triton/lib/triton/napi.rb"
|
105
|
+
- "/Users/thomas/tdh/triton/lib/triton/papi.rb"
|
106
|
+
- "/Users/thomas/tdh/triton/lib/triton/remote_exception.rb"
|
107
|
+
- "/Users/thomas/tdh/triton/lib/triton/version.rb"
|
108
|
+
- "/Users/thomas/tdh/triton/lib/triton/vmapi.rb"
|
109
|
+
- "/Users/thomas/tdh/triton/pkg/triton-internal-0.1.0.gem"
|
110
|
+
- "/Users/thomas/tdh/triton/spec/api_base_spec.rb"
|
111
|
+
- "/Users/thomas/tdh/triton/spec/spec_helper.rb"
|
112
|
+
- "/Users/thomas/tdh/triton/spec/triton_spec.rb"
|
113
|
+
- "/Users/thomas/tdh/triton/triton-internal.gemspec"
|
114
|
+
homepage: http://thomas.haggett.org/
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.5.1
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Library to wrap the Triton internal APIs
|
138
|
+
test_files: []
|