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.
@@ -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