cfoundry 0.4.18 → 0.4.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 "REQUEST: #{request.method} #{request.path}"
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 "RESPONSE: [#{response.code}]"
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
- when Net::HTTPSuccess, Net::HTTPRedirection
326
- if accept == :json
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
- when Net::HTTPNotFound
339
- raise CFoundry::NotFound.new(response.code, response.body)
316
+ when Net::HTTPNotFound
317
+ raise CFoundry::NotFound.new(request, response)
340
318
 
341
- when Net::HTTPForbidden
342
- raise CFoundry::Denied.new(response.code, response.body)
319
+ when Net::HTTPForbidden
320
+ raise CFoundry::Denied.new(request, response)
343
321
 
344
- else
345
- raise CFoundry::BadResponse.new(response.code, response.body)
322
+ else
323
+ raise CFoundry::BadResponse.new(request, response)
346
324
  end
347
325
  end
348
326
 
@@ -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 error code and description.
59
- def initialize(error_code = nil, description = nil)
60
- @error_code = error_code
61
- @description = description
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
- if error_code
67
- "#{error_code}: #{description}"
68
- elsif description
69
- description
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
- super
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
@@ -32,15 +32,13 @@ module CFoundry
32
32
  :accept => :json,
33
33
  :params => query)
34
34
 
35
- case auth
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
- if accept == :json
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.code, info[:error_description])
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.code, info[:message])
86
+ raise CFoundry::Denied.new(request, response, info[:message])
100
87
 
101
88
  else
102
- raise BadResponse.new(response.code, response.body)
89
+ raise BadResponse.new(request, response)
103
90
  end
104
91
  end
105
92
 
@@ -101,38 +101,18 @@ module CFoundry::V1
101
101
 
102
102
  private
103
103
 
104
- def handle_response(response, accept)
105
- case response
106
- when Net::HTTPSuccess, Net::HTTPRedirection
107
- if accept == :json
108
- if response.is_a?(Net::HTTPNoContent)
109
- raise CFoundry::BadResponse.new(
110
- 204,
111
- "Expected JSON response, got 204 No Content")
112
- end
113
-
114
- parse_json(response.body)
115
- else
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
@@ -118,41 +118,18 @@ module CFoundry::V2
118
118
 
119
119
  private
120
120
 
121
- def handle_response(response, accept)
122
- case response
123
- when Net::HTTPSuccess, Net::HTTPRedirection
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
- when Net::HTTPBadRequest, Net::HTTPUnauthorized, Net::HTTPNotFound,
141
- Net::HTTPNotImplemented, Net::HTTPServiceUnavailable
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
- cls = CFoundry::APIError.error_classes[info[:code]]
128
+ cls = CFoundry::APIError.error_classes[info[:code]]
147
129
 
148
- raise (cls || CFoundry::APIError).new(info[:code], info[:description])
149
- rescue MultiJson::DecodeError
150
- super
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)
@@ -145,6 +145,8 @@ module CFoundry::V2
145
145
  json)
146
146
  end
147
147
  end
148
+
149
+ has_summary
148
150
  end
149
151
 
150
152
  def attribute(name, type, opts = {})
@@ -12,7 +12,5 @@ module CFoundry::V2
12
12
 
13
13
  queryable_by :name, :space_guid, :user_guid, :manager_guid,
14
14
  :billing_manager_guid, :auditor_guid
15
-
16
- has_summary
17
15
  end
18
16
  end
@@ -14,7 +14,5 @@ module CFoundry::V2
14
14
  scoped_to_organization
15
15
 
16
16
  queryable_by :name, :organization_guid, :developer_guid, :app_guid
17
-
18
- has_summary
19
17
  end
20
18
  end
@@ -1,4 +1,4 @@
1
1
  module CFoundry # :nodoc:
2
2
  # CFoundry library version number.
3
- VERSION = "0.4.18".freeze
3
+ VERSION = "0.4.19".freeze
4
4
  end
@@ -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: 43
4
+ hash: 41
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 18
10
- version: 0.4.18
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-08 00:00:00 Z
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