cfoundry 0.4.18 → 0.4.19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|