cfoundry 0.4.18 → 0.4.19
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.
- data/lib/cfoundry/baseclient.rb +15 -37
- data/lib/cfoundry/errors.rb +36 -10
- data/lib/cfoundry/trace_helpers.rb +40 -0
- data/lib/cfoundry/uaaclient.rb +9 -22
- data/lib/cfoundry/v1/base.rb +12 -32
- data/lib/cfoundry/v2/base.rb +9 -32
- data/lib/cfoundry/v2/model_magic.rb +2 -0
- data/lib/cfoundry/v2/organization.rb +0 -2
- data/lib/cfoundry/v2/space.rb +0 -2
- data/lib/cfoundry/version.rb +1 -1
- data/spec/cfoundry/baseclient_spec.rb +35 -0
- data/spec/cfoundry/errors_spec.rb +61 -0
- data/spec/cfoundry/trace_helpers_spec.rb +67 -0
- data/spec/cfoundry/uaaclient_spec.rb +66 -0
- data/spec/cfoundry/v1/base_spec.rb +58 -0
- data/spec/cfoundry/v2/base_spec.rb +59 -0
- data/spec/cfoundry/v2/model_magic_spec.rb +9 -0
- data/spec/cfoundry/v2/organization_spec.rb +13 -0
- data/spec/cfoundry/v2/space_spec.rb +13 -0
- data/spec/support/summaries.rb +34 -0
- metadata +17 -4
data/lib/cfoundry/baseclient.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "cfoundry/trace_helpers"
|
1
2
|
require "net/https"
|
2
3
|
require "net/http/post/multipart"
|
3
4
|
require "multi_json"
|
@@ -6,6 +7,8 @@ require "base64"
|
|
6
7
|
|
7
8
|
module CFoundry
|
8
9
|
class BaseClient # :nodoc:
|
10
|
+
include CFoundry::TraceHelpers
|
11
|
+
|
9
12
|
LOG_LENGTH = 10
|
10
13
|
|
11
14
|
attr_reader :target
|
@@ -140,7 +143,7 @@ module CFoundry
|
|
140
143
|
Net::HTTP::Get,
|
141
144
|
original_options)
|
142
145
|
else
|
143
|
-
handle_response(response, accept)
|
146
|
+
handle_response(response, accept, request)
|
144
147
|
end
|
145
148
|
end
|
146
149
|
rescue ::Timeout::Error => e
|
@@ -277,26 +280,11 @@ module CFoundry
|
|
277
280
|
|
278
281
|
def print_request(request)
|
279
282
|
$stderr.puts ">>>"
|
280
|
-
$stderr.puts
|
281
|
-
$stderr.puts "REQUEST_HEADERS:"
|
282
|
-
request.each_header do |key, value|
|
283
|
-
$stderr.puts " #{key} : #{value}"
|
284
|
-
end
|
285
|
-
$stderr.puts "REQUEST_BODY: #{request.body}" if request.body
|
283
|
+
$stderr.puts request_trace(request)
|
286
284
|
end
|
287
285
|
|
288
286
|
def print_response(response)
|
289
|
-
$stderr.puts
|
290
|
-
$stderr.puts "RESPONSE_HEADERS:"
|
291
|
-
response.each_header do |key, value|
|
292
|
-
$stderr.puts " #{key} : #{value}"
|
293
|
-
end
|
294
|
-
begin
|
295
|
-
parsed_body = MultiJson.load(response.body)
|
296
|
-
$stderr.puts MultiJson.dump(parsed_body, :pretty => true)
|
297
|
-
rescue
|
298
|
-
$stderr.puts "#{response.body}"
|
299
|
-
end
|
287
|
+
$stderr.puts response_trace(response)
|
300
288
|
$stderr.puts "<<<"
|
301
289
|
end
|
302
290
|
|
@@ -320,29 +308,19 @@ module CFoundry
|
|
320
308
|
$stderr.puts "... (trimmed)" unless trimmed_locs == interesting_locs
|
321
309
|
end
|
322
310
|
|
323
|
-
def handle_response(response, accept)
|
311
|
+
def handle_response(response, accept, request)
|
324
312
|
case response
|
325
|
-
|
326
|
-
|
327
|
-
if response.is_a?(Net::HTTPNoContent)
|
328
|
-
raise CFoundry::BadResponse.new(
|
329
|
-
204,
|
330
|
-
"Expected JSON response, got 204 No Content")
|
331
|
-
end
|
332
|
-
|
333
|
-
parse_json(response.body)
|
334
|
-
else
|
335
|
-
response.body
|
336
|
-
end
|
313
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
314
|
+
accept == :json ? parse_json(response.body) : response.body
|
337
315
|
|
338
|
-
|
339
|
-
|
316
|
+
when Net::HTTPNotFound
|
317
|
+
raise CFoundry::NotFound.new(request, response)
|
340
318
|
|
341
|
-
|
342
|
-
|
319
|
+
when Net::HTTPForbidden
|
320
|
+
raise CFoundry::Denied.new(request, response)
|
343
321
|
|
344
|
-
|
345
|
-
|
322
|
+
else
|
323
|
+
raise CFoundry::BadResponse.new(request, response)
|
346
324
|
end
|
347
325
|
end
|
348
326
|
|
data/lib/cfoundry/errors.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "multi_json"
|
3
|
+
|
1
4
|
module CFoundry
|
2
5
|
# Base class for CFoundry errors (not from the server).
|
3
6
|
class Error < RuntimeError; end
|
@@ -47,28 +50,51 @@ module CFoundry
|
|
47
50
|
|
48
51
|
# Exception representing errors returned by the API.
|
49
52
|
class APIError < RuntimeError
|
53
|
+
include TraceHelpers
|
54
|
+
|
50
55
|
class << self
|
51
56
|
def error_classes
|
52
57
|
@error_classes ||= {}
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
56
|
-
attr_reader :error_code, :description
|
61
|
+
attr_reader :error_code, :description, :request, :response
|
57
62
|
|
58
|
-
# Create an APIError with a given
|
59
|
-
def initialize(
|
60
|
-
@
|
61
|
-
@
|
63
|
+
# Create an APIError with a given request and response.
|
64
|
+
def initialize(request, response, description = nil, error_code = nil)
|
65
|
+
@response = response
|
66
|
+
@request = request
|
67
|
+
@error_code = error_code || response.code
|
68
|
+
@description = description || parse_description
|
62
69
|
end
|
63
70
|
|
64
71
|
# Exception message.
|
65
72
|
def to_s
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
73
|
+
"#{error_code}: #{description}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def request_trace
|
77
|
+
super(request)
|
78
|
+
end
|
79
|
+
|
80
|
+
def response_trace
|
81
|
+
super(response)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def parse_description
|
86
|
+
begin
|
87
|
+
parse_json(response.body)[:description]
|
88
|
+
rescue MultiJson::DecodeError
|
89
|
+
response.body
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_json(x)
|
94
|
+
if x.empty?
|
95
|
+
raise MultiJson::DecodeError.new("Empty JSON string", [], "")
|
70
96
|
else
|
71
|
-
|
97
|
+
MultiJson.load(x, :symbolize_keys => true)
|
72
98
|
end
|
73
99
|
end
|
74
100
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "multi_json"
|
3
|
+
|
4
|
+
module CFoundry
|
5
|
+
module TraceHelpers
|
6
|
+
|
7
|
+
def request_trace(request)
|
8
|
+
return nil unless request
|
9
|
+
info = ["REQUEST: #{request.method} #{request.path}"]
|
10
|
+
info << "REQUEST_HEADERS:"
|
11
|
+
info << header_trace(request)
|
12
|
+
info << "REQUEST_BODY: #{request.body}" if request.body
|
13
|
+
info.join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def response_trace(response)
|
18
|
+
return nil unless response
|
19
|
+
info = ["RESPONSE: [#{response.code}]"]
|
20
|
+
info << "RESPONSE_HEADERS:"
|
21
|
+
info << header_trace(response)
|
22
|
+
info << "RESPONSE_BODY:"
|
23
|
+
begin
|
24
|
+
parsed_body = MultiJson.load(response.body)
|
25
|
+
info << MultiJson.dump(parsed_body, :pretty => true)
|
26
|
+
rescue
|
27
|
+
info << "#{response.body}"
|
28
|
+
end
|
29
|
+
info.join("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def header_trace(headers)
|
35
|
+
headers.to_hash.sort.map do |key, value|
|
36
|
+
" #{key} : #{value.join(", ")}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/cfoundry/uaaclient.rb
CHANGED
@@ -32,15 +32,13 @@ module CFoundry
|
|
32
32
|
:accept => :json,
|
33
33
|
:params => query)
|
34
34
|
|
35
|
-
|
36
|
-
when Net::HTTPRedirection
|
35
|
+
if auth.is_a? Net::HTTPRedirection
|
37
36
|
extract_token(auth["location"])
|
38
37
|
else
|
39
38
|
json = parse_json(auth.body)
|
40
|
-
raise CFoundry::Denied.new(
|
41
|
-
auth.code.to_i,
|
42
|
-
json[:error_description])
|
39
|
+
raise CFoundry::Denied.new(nil, nil, json[:error_description], auth.code)
|
43
40
|
end
|
41
|
+
|
44
42
|
end
|
45
43
|
|
46
44
|
def users
|
@@ -72,34 +70,23 @@ module CFoundry
|
|
72
70
|
|
73
71
|
private
|
74
72
|
|
75
|
-
def handle_response(response, accept)
|
73
|
+
def handle_response(response, accept, request)
|
76
74
|
case response
|
77
75
|
when Net::HTTPSuccess, Net::HTTPRedirection
|
78
|
-
|
79
|
-
if response.is_a?(Net::HTTPNoContent)
|
80
|
-
raise CFoundry::BadResponse.new(
|
81
|
-
204,
|
82
|
-
"Expected JSON response, got 204 No Content")
|
83
|
-
end
|
84
|
-
|
85
|
-
parse_json(response.body)
|
86
|
-
else
|
87
|
-
response.body
|
88
|
-
end
|
89
|
-
|
76
|
+
accept == :json ? parse_json(response.body) : response.body
|
90
77
|
when Net::HTTPBadRequest, Net::HTTPUnauthorized, Net::HTTPForbidden
|
91
78
|
info = parse_json(response.body)
|
92
|
-
raise Denied.new(response
|
79
|
+
raise Denied.new(request, response, info[:error_description])
|
93
80
|
|
94
81
|
when Net::HTTPNotFound
|
95
|
-
raise NotFound
|
82
|
+
raise CFoundry::NotFound.new(request, response)
|
96
83
|
|
97
84
|
when Net::HTTPConflict
|
98
85
|
info = parse_json(response.body)
|
99
|
-
raise CFoundry::Denied.new(response
|
86
|
+
raise CFoundry::Denied.new(request, response, info[:message])
|
100
87
|
|
101
88
|
else
|
102
|
-
raise BadResponse.new(
|
89
|
+
raise BadResponse.new(request, response)
|
103
90
|
end
|
104
91
|
end
|
105
92
|
|
data/lib/cfoundry/v1/base.rb
CHANGED
@@ -101,38 +101,18 @@ module CFoundry::V1
|
|
101
101
|
|
102
102
|
private
|
103
103
|
|
104
|
-
def handle_response(response, accept)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
response.body
|
117
|
-
end
|
118
|
-
|
119
|
-
when Net::HTTPBadRequest, Net::HTTPForbidden, Net::HTTPNotFound,
|
120
|
-
Net::HTTPInternalServerError, Net::HTTPNotImplemented,
|
121
|
-
Net::HTTPBadGateway
|
122
|
-
begin
|
123
|
-
info = parse_json(response.body)
|
124
|
-
return super unless info[:code]
|
125
|
-
|
126
|
-
cls = CFoundry::APIError.error_classes[info[:code]]
|
127
|
-
|
128
|
-
raise (cls || CFoundry::APIError).new(info[:code], info[:description])
|
129
|
-
rescue MultiJson::DecodeError
|
130
|
-
super
|
131
|
-
end
|
132
|
-
|
133
|
-
else
|
134
|
-
super
|
135
|
-
end
|
104
|
+
def handle_response(response, accept, request)
|
105
|
+
# this is a copy paste of v2
|
106
|
+
return super if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
|
107
|
+
|
108
|
+
info = parse_json(response.body)
|
109
|
+
return super unless info[:code]
|
110
|
+
|
111
|
+
cls = CFoundry::APIError.error_classes[info[:code]]
|
112
|
+
|
113
|
+
raise (cls || CFoundry::APIError).new(request, response, info[:description], info[:code])
|
114
|
+
rescue MultiJson::DecodeError
|
115
|
+
super
|
136
116
|
end
|
137
117
|
end
|
138
118
|
end
|
data/lib/cfoundry/v2/base.rb
CHANGED
@@ -118,41 +118,18 @@ module CFoundry::V2
|
|
118
118
|
|
119
119
|
private
|
120
120
|
|
121
|
-
def handle_response(response, accept)
|
122
|
-
|
123
|
-
|
124
|
-
if accept == :headers
|
125
|
-
return sane_headers(response)
|
126
|
-
end
|
127
|
-
|
128
|
-
if accept == :json
|
129
|
-
if response.is_a?(Net::HTTPNoContent)
|
130
|
-
raise CFoundry::BadResponse.new(
|
131
|
-
204,
|
132
|
-
"Expected JSON response, got 204 No Content")
|
133
|
-
end
|
134
|
-
|
135
|
-
parse_json(response.body)
|
136
|
-
else
|
137
|
-
response.body
|
138
|
-
end
|
121
|
+
def handle_response(response, accept, request)
|
122
|
+
# this is a copy paste of v1
|
123
|
+
return super if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
|
139
124
|
|
140
|
-
|
141
|
-
|
142
|
-
begin
|
143
|
-
info = parse_json(response.body)
|
144
|
-
return super unless info[:code]
|
125
|
+
info = parse_json(response.body)
|
126
|
+
return super unless info[:code]
|
145
127
|
|
146
|
-
|
128
|
+
cls = CFoundry::APIError.error_classes[info[:code]]
|
147
129
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
|
153
|
-
else
|
154
|
-
super
|
155
|
-
end
|
130
|
+
raise (cls || CFoundry::APIError).new(request, response, info[:description], info[:code])
|
131
|
+
rescue MultiJson::DecodeError
|
132
|
+
super
|
156
133
|
end
|
157
134
|
|
158
135
|
def log_line(io, data)
|
data/lib/cfoundry/v2/space.rb
CHANGED
data/lib/cfoundry/version.rb
CHANGED
@@ -13,5 +13,40 @@ describe CFoundry::BaseClient do
|
|
13
13
|
expect { subject }.to raise_error CFoundry::Timeout, "GET https://api.cloudfoundry.com/foo timed out"
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
context 'when an HTTPNotFound error occurs' do
|
18
|
+
before {
|
19
|
+
|
20
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 404,
|
21
|
+
:body => "NOT FOUND"
|
22
|
+
}
|
23
|
+
|
24
|
+
it 'raises the correct error' do
|
25
|
+
expect {subject}.to raise_error CFoundry::NotFound, "404: NOT FOUND"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
context 'when an HTTPForbidden error occurs' do
|
31
|
+
before {
|
32
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 403,
|
33
|
+
:body => "NONE SHALL PASS"
|
34
|
+
}
|
35
|
+
|
36
|
+
it 'raises the correct error' do
|
37
|
+
expect {subject}.to raise_error CFoundry::Denied, "403: NONE SHALL PASS"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when any other type of error occurs" do
|
42
|
+
before {
|
43
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 411,
|
44
|
+
:body => "NOT LONG ENOUGH"
|
45
|
+
}
|
46
|
+
|
47
|
+
it 'raises the correct error' do
|
48
|
+
expect {subject}.to raise_error CFoundry::BadResponse, "411: NOT LONG ENOUGH"
|
49
|
+
end
|
50
|
+
end
|
16
51
|
end
|
17
52
|
end
|
@@ -11,4 +11,65 @@ describe 'Errors' do
|
|
11
11
|
its(:uri) { should eq '/blah' }
|
12
12
|
its(:parent) { should eq parent }
|
13
13
|
end
|
14
|
+
|
15
|
+
describe CFoundry::APIError do
|
16
|
+
let(:request) { Net::HTTP::Get.new("http://api.cloudfoundry.com/foo") }
|
17
|
+
let(:response) { Net::HTTPNotFound.new("foo", 404, "bar")}
|
18
|
+
let(:response_body) { "NOT FOUND" }
|
19
|
+
subject { CFoundry::APIError.new(request, response) }
|
20
|
+
|
21
|
+
before do
|
22
|
+
stub(response).body {response_body}
|
23
|
+
end
|
24
|
+
|
25
|
+
its(:to_s) { should eq "404: NOT FOUND" }
|
26
|
+
|
27
|
+
its(:request) { should eq request }
|
28
|
+
|
29
|
+
its(:response) { should eq response }
|
30
|
+
|
31
|
+
describe "#initialize" do
|
32
|
+
|
33
|
+
context "Response body is JSON" do
|
34
|
+
|
35
|
+
let(:response_body) { "{\"description\":\"Something went wrong\"}"}
|
36
|
+
|
37
|
+
it "sets description to description field in parsed JSON" do
|
38
|
+
CFoundry::APIError.new(request, response).description.should == "Something went wrong"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
context "Response body is not JSON" do
|
44
|
+
|
45
|
+
let(:response_body) { "Some plain text"}
|
46
|
+
|
47
|
+
it "sets description to body text" do
|
48
|
+
CFoundry::APIError.new(request, response).description.should == "Some plain text"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "allows override of description" do
|
53
|
+
CFoundry::APIError.new(request, response, "My description").description.should == "My description"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#request_trace" do
|
59
|
+
its(:request_trace) { should include "REQUEST: " }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#response_trace" do
|
63
|
+
its(:response_trace) { should include "RESPONSE: " }
|
64
|
+
end
|
65
|
+
|
66
|
+
it "sets error code to response error code by default" do
|
67
|
+
CFoundry::APIError.new(request, response).error_code.should == 404
|
68
|
+
end
|
69
|
+
|
70
|
+
it "allows override of error code" do
|
71
|
+
CFoundry::APIError.new(request, response, nil, 303).error_code.should == 303
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
14
75
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CFoundry::TraceHelpers do
|
4
|
+
let(:fake_class) { Class.new { include CFoundry::TraceHelpers } }
|
5
|
+
let(:request) { Net::HTTP::Get.new("http://api.cloudfoundry.com/foo", "bb-FOO" => "bar") }
|
6
|
+
let(:response) { Net::HTTPNotFound.new("foo", 404, "bar") }
|
7
|
+
|
8
|
+
shared_examples "request_trace tests" do
|
9
|
+
it { should include request_trace }
|
10
|
+
it { should include header_trace }
|
11
|
+
it { should include body_trace }
|
12
|
+
end
|
13
|
+
|
14
|
+
shared_examples "response_trace tests" do
|
15
|
+
before { stub(response).body { response_body } }
|
16
|
+
|
17
|
+
it "traces the provided response" do
|
18
|
+
fake_class.new.response_trace(response).should == response_trace
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#request_trace" do
|
23
|
+
let(:request_trace) { "REQUEST: GET http://api.cloudfoundry.com/foo" }
|
24
|
+
let(:header_trace) { "REQUEST_HEADERS:\n accept : */*\n bb-foo : bar" }
|
25
|
+
let(:body_trace) { "" }
|
26
|
+
|
27
|
+
subject { fake_class.new.request_trace(request) }
|
28
|
+
|
29
|
+
context "without a request body" do
|
30
|
+
include_examples "request_trace tests"
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with a request body" do
|
34
|
+
let(:body_trace) { "REQUEST_BODY: Some body text" }
|
35
|
+
|
36
|
+
before { request.body = "Some body text" }
|
37
|
+
|
38
|
+
include_examples "request_trace tests"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns nil if request is nil" do
|
42
|
+
fake_class.new.request_trace(nil).should == nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
describe "#response_trace" do
|
48
|
+
context "with a non-JSON response body" do
|
49
|
+
let(:response_trace) { "RESPONSE: [404]\nRESPONSE_HEADERS:\n\nRESPONSE_BODY:\nSome body" }
|
50
|
+
let(:response_body) { "Some body"}
|
51
|
+
|
52
|
+
include_examples "response_trace tests"
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with a JSON response body" do
|
56
|
+
|
57
|
+
let(:response_body) { "{\"name\": \"vcap\",\"build\": 2222,\"support\": \"http://support.cloudfoundry.com\"}" }
|
58
|
+
let(:response_trace) { "RESPONSE: [404]\nRESPONSE_HEADERS:\n\nRESPONSE_BODY:\n#{MultiJson.dump(MultiJson.load(response_body), :pretty => true)}" }
|
59
|
+
|
60
|
+
include_examples "response_trace tests"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns nil if response is nil" do
|
64
|
+
fake_class.new.response_trace(nil).should == nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -197,4 +197,70 @@ EOF
|
|
197
197
|
it { should == :weak }
|
198
198
|
end
|
199
199
|
end
|
200
|
+
|
201
|
+
describe '#request_uri' do
|
202
|
+
subject { uaa.request_uri URI.parse(uaa.target + "/foo"), Net::HTTP::Get }
|
203
|
+
|
204
|
+
context 'when an HTTPNotFound error occurs' do
|
205
|
+
before {
|
206
|
+
|
207
|
+
stub_request(:get, 'https://uaa.example.com/foo').to_return :status => 404,
|
208
|
+
:body => "NOT FOUND"
|
209
|
+
}
|
210
|
+
|
211
|
+
it 'raises the correct error' do
|
212
|
+
expect {subject}.to raise_error CFoundry::NotFound, "404: NOT FOUND"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
shared_examples "Denied tests" do
|
218
|
+
before {
|
219
|
+
stub_request(:get, 'https://uaa.example.com/foo').to_return :status => error_code,
|
220
|
+
:body => "{\"error_description\":\"Something detailed\"}"
|
221
|
+
}
|
222
|
+
|
223
|
+
it 'raises the correct error' do
|
224
|
+
expect {subject}.to raise_error CFoundry::Denied, "#{error_code}: Something detailed"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
context 'when an HTTPForbidden error occurs' do
|
230
|
+
let(:error_code) { 403 }
|
231
|
+
include_examples "Denied tests"
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'when an HTTPUnauthorized error occurs' do
|
235
|
+
let(:error_code) { 401 }
|
236
|
+
include_examples "Denied tests"
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'when an HTTPBadRequest error occurs' do
|
240
|
+
let(:error_code) { 400 }
|
241
|
+
include_examples "Denied tests"
|
242
|
+
end
|
243
|
+
|
244
|
+
context "when an HTTPConflict error occurs" do
|
245
|
+
before {
|
246
|
+
stub_request(:get, 'https://uaa.example.com/foo').to_return :status => 409,
|
247
|
+
:body => "{\"message\":\"There was a conflict\"}"
|
248
|
+
}
|
249
|
+
|
250
|
+
it 'raises the correct error' do
|
251
|
+
expect {subject}.to raise_error CFoundry::Denied, "409: There was a conflict"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context "when any other type of error occurs" do
|
256
|
+
before {
|
257
|
+
stub_request(:get, 'https://uaa.example.com/foo').to_return :status => 411,
|
258
|
+
:body => "NOT LONG ENOUGH"
|
259
|
+
}
|
260
|
+
|
261
|
+
it 'raises the correct error' do
|
262
|
+
expect {subject}.to raise_error CFoundry::BadResponse, "411: NOT LONG ENOUGH"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
200
266
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CFoundry::V1::Base do
|
4
|
+
let(:base) { CFoundry::V1::Base.new("https://api.cloudfoundry.com") }
|
5
|
+
|
6
|
+
describe '#request_uri' do
|
7
|
+
let(:options) { {} }
|
8
|
+
subject { base.request_uri URI.parse(base.target + "/foo"), Net::HTTP::Get, options }
|
9
|
+
|
10
|
+
context 'when successful' do
|
11
|
+
context 'and the accept type is JSON' do
|
12
|
+
let(:options) { {:accept => :json} }
|
13
|
+
|
14
|
+
it 'returns the parsed JSON' do
|
15
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 201, :body => "{\"hello\": \"there\"}"
|
16
|
+
expect(subject).to eq(:hello => "there")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'and the accept type is not JSON' do
|
21
|
+
let(:options) { {:accept => :form} }
|
22
|
+
|
23
|
+
it 'returns the body' do
|
24
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 201, :body => "body"
|
25
|
+
expect(subject).to eq "body"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when an error occurs' do
|
31
|
+
let(:response_code) { 404 }
|
32
|
+
|
33
|
+
it 'raises the correct error if JSON is parsed successfully' do
|
34
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
35
|
+
:body => "{\"code\": 111, \"description\": \"Something bad happened\"}"
|
36
|
+
expect {subject}.to raise_error CFoundry::SystemError, "111: Something bad happened"
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'raises the correct error if code is missing from response' do
|
40
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
41
|
+
:body => "{\"description\": \"Something bad happened\"}"
|
42
|
+
expect {subject}.to raise_error CFoundry::NotFound
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'raises the correct error if response body is not JSON' do
|
46
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
47
|
+
:body => "Error happened"
|
48
|
+
expect {subject}.to raise_error CFoundry::NotFound
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'raises a generic APIError if code is not recognized' do
|
52
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
53
|
+
:body => "{\"code\": 6932, \"description\": \"Something bad happened\"}"
|
54
|
+
expect {subject}.to raise_error CFoundry::APIError, "6932: Something bad happened"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CFoundry::V2::Base do
|
4
|
+
let(:base) { CFoundry::V2::Base.new("https://api.cloudfoundry.com") }
|
5
|
+
|
6
|
+
describe '#request_uri' do
|
7
|
+
let(:options) { {} }
|
8
|
+
subject { base.request_uri URI.parse(base.target + "/foo"), Net::HTTP::Get, options }
|
9
|
+
|
10
|
+
context 'when successful' do
|
11
|
+
context 'and the accept type is JSON' do
|
12
|
+
let(:options) { {:accept => :json} }
|
13
|
+
|
14
|
+
it 'returns the parsed JSON' do
|
15
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 200, :body => "{\"hello\": \"there\"}"
|
16
|
+
expect(subject).to eq(:hello => "there")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'and the accept type is not JSON' do
|
21
|
+
let(:options) { {:accept => :form} }
|
22
|
+
|
23
|
+
it 'returns the body' do
|
24
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => 200, :body => "body"
|
25
|
+
expect(subject).to eq "body"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when an error occurs' do
|
32
|
+
let(:response_code) { 404 }
|
33
|
+
|
34
|
+
it 'raises the correct error if JSON is parsed successfully' do
|
35
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
36
|
+
:body => "{\"code\": 111, \"description\": \"Something bad happened\"}"
|
37
|
+
expect {subject}.to raise_error CFoundry::SystemError, "111: Something bad happened"
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises the correct error if code is missing from response' do
|
41
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
42
|
+
:body => "{\"description\": \"Something bad happened\"}"
|
43
|
+
expect {subject}.to raise_error CFoundry::NotFound
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises the correct error if response body is not JSON' do
|
47
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
48
|
+
:body => "Error happened"
|
49
|
+
expect {subject}.to raise_error CFoundry::NotFound
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises a generic APIError if code is not recognized' do
|
53
|
+
stub_request(:get, 'https://api.cloudfoundry.com/foo').to_return :status => response_code,
|
54
|
+
:body => "{\"code\": 6932, \"description\": \"Something bad happened\"}"
|
55
|
+
expect {subject}.to raise_error CFoundry::APIError, "6932: Something bad happened"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -112,4 +112,13 @@ describe CFoundry::V2::ModelMagic do
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
115
|
+
|
116
|
+
describe 'summarization for an arbitrary model' do
|
117
|
+
let(:mymodel) { fake_model { attribute :foo, :string } }
|
118
|
+
let(:summary_attributes) { { :foo => "abcd" } }
|
119
|
+
|
120
|
+
subject { myobject }
|
121
|
+
|
122
|
+
it_behaves_like 'a summarizeable model'
|
123
|
+
end
|
115
124
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe CFoundry::V2::Organization do
|
2
|
+
let(:client) { fake_client }
|
3
|
+
|
4
|
+
describe 'summarization' do
|
5
|
+
let(:mymodel) { CFoundry::V2::Organization }
|
6
|
+
let(:myobject) { fake(:organization) }
|
7
|
+
let(:summary_attributes) { { :name => "fizzbuzz" } }
|
8
|
+
|
9
|
+
subject { myobject }
|
10
|
+
|
11
|
+
it_behaves_like 'a summarizeable model'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe CFoundry::V2::Space do
|
2
|
+
let(:client) { fake_client }
|
3
|
+
|
4
|
+
describe 'summarization' do
|
5
|
+
let(:mymodel) { CFoundry::V2::Space }
|
6
|
+
let(:myobject) { fake(:space) }
|
7
|
+
let(:summary_attributes) { { :name => "fizzbuzz" } }
|
8
|
+
|
9
|
+
subject { myobject }
|
10
|
+
|
11
|
+
it_behaves_like 'a summarizeable model'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "multi_json"
|
2
|
+
|
3
|
+
shared_examples_for 'a summarizeable model' do
|
4
|
+
describe '#summary' do
|
5
|
+
let(:summary_endpoint) {
|
6
|
+
[ client.target,
|
7
|
+
"v2",
|
8
|
+
mymodel.plural_object_name,
|
9
|
+
myobject.guid,
|
10
|
+
"summary"
|
11
|
+
].join("/")
|
12
|
+
}
|
13
|
+
|
14
|
+
it 'returns the summary endpoint payload' do
|
15
|
+
req = stub_request(:get, summary_endpoint).to_return :status => 200,
|
16
|
+
:body => MultiJson.encode(summary_attributes)
|
17
|
+
|
18
|
+
expect(subject.summary).to eq(summary_attributes)
|
19
|
+
expect(req).to have_been_requested
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#summarize!' do
|
24
|
+
it 'defines basic attributes via #summary' do
|
25
|
+
stub(subject).summary { summary_attributes }
|
26
|
+
|
27
|
+
subject.summarize!
|
28
|
+
|
29
|
+
summary_attributes.each do |k, v|
|
30
|
+
expect(subject.send(k)).to eq v
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfoundry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 41
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 19
|
10
|
+
version: 0.4.19
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alex Suraci
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-01-
|
18
|
+
date: 2013-01-10 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: multipart-post
|
@@ -139,6 +139,7 @@ files:
|
|
139
139
|
- lib/cfoundry/client.rb
|
140
140
|
- lib/cfoundry/errors.rb
|
141
141
|
- lib/cfoundry/spec_helper.rb
|
142
|
+
- lib/cfoundry/trace_helpers.rb
|
142
143
|
- lib/cfoundry/uaaclient.rb
|
143
144
|
- lib/cfoundry/upload_helpers.rb
|
144
145
|
- lib/cfoundry/v1/app.rb
|
@@ -174,8 +175,13 @@ files:
|
|
174
175
|
- lib/cfoundry.rb
|
175
176
|
- spec/cfoundry/baseclient_spec.rb
|
176
177
|
- spec/cfoundry/errors_spec.rb
|
178
|
+
- spec/cfoundry/trace_helpers_spec.rb
|
177
179
|
- spec/cfoundry/uaaclient_spec.rb
|
180
|
+
- spec/cfoundry/v1/base_spec.rb
|
181
|
+
- spec/cfoundry/v2/base_spec.rb
|
178
182
|
- spec/cfoundry/v2/model_magic_spec.rb
|
183
|
+
- spec/cfoundry/v2/organization_spec.rb
|
184
|
+
- spec/cfoundry/v2/space_spec.rb
|
179
185
|
- spec/fakes/app_fake.rb
|
180
186
|
- spec/fakes/domain_fake.rb
|
181
187
|
- spec/fakes/framework_fake.rb
|
@@ -189,6 +195,7 @@ files:
|
|
189
195
|
- spec/fakes/user_fake.rb
|
190
196
|
- spec/spec_helper.rb
|
191
197
|
- spec/support/fake_helper.rb
|
198
|
+
- spec/support/summaries.rb
|
192
199
|
homepage: http://cloudfoundry.com/
|
193
200
|
licenses: []
|
194
201
|
|
@@ -225,8 +232,13 @@ summary: High-level library for working with the Cloud Foundry API.
|
|
225
232
|
test_files:
|
226
233
|
- spec/cfoundry/baseclient_spec.rb
|
227
234
|
- spec/cfoundry/errors_spec.rb
|
235
|
+
- spec/cfoundry/trace_helpers_spec.rb
|
228
236
|
- spec/cfoundry/uaaclient_spec.rb
|
237
|
+
- spec/cfoundry/v1/base_spec.rb
|
238
|
+
- spec/cfoundry/v2/base_spec.rb
|
229
239
|
- spec/cfoundry/v2/model_magic_spec.rb
|
240
|
+
- spec/cfoundry/v2/organization_spec.rb
|
241
|
+
- spec/cfoundry/v2/space_spec.rb
|
230
242
|
- spec/fakes/app_fake.rb
|
231
243
|
- spec/fakes/domain_fake.rb
|
232
244
|
- spec/fakes/framework_fake.rb
|
@@ -240,3 +252,4 @@ test_files:
|
|
240
252
|
- spec/fakes/user_fake.rb
|
241
253
|
- spec/spec_helper.rb
|
242
254
|
- spec/support/fake_helper.rb
|
255
|
+
- spec/support/summaries.rb
|