ddy_remote_resource 0.4.11 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Guardfile +3 -0
  4. data/lib/remote_resource.rb +77 -34
  5. data/lib/remote_resource/base.rb +20 -8
  6. data/lib/remote_resource/connection.rb +26 -5
  7. data/lib/remote_resource/connection_options.rb +5 -3
  8. data/lib/remote_resource/querying/finder_methods.rb +3 -3
  9. data/lib/remote_resource/querying/persistence_methods.rb +17 -12
  10. data/lib/remote_resource/request.rb +96 -62
  11. data/lib/remote_resource/response.rb +5 -1
  12. data/lib/remote_resource/rest.rb +13 -17
  13. data/lib/remote_resource/url_naming.rb +4 -10
  14. data/lib/remote_resource/url_naming_determination.rb +1 -3
  15. data/lib/remote_resource/util.rb +64 -0
  16. data/lib/remote_resource/version.rb +1 -1
  17. data/remote_resource.gemspec +2 -2
  18. data/spec/fixtures/text_file.txt +1 -0
  19. data/spec/integration/all_spec.rb +166 -0
  20. data/spec/integration/collection_prefix_spec.rb +99 -0
  21. data/spec/integration/create_spec.rb +181 -0
  22. data/spec/integration/destroy_spec.rb +252 -0
  23. data/spec/integration/find_by_spec.rb +168 -0
  24. data/spec/integration/find_spec.rb +139 -0
  25. data/spec/integration/headers_spec.rb +222 -0
  26. data/spec/integration/naming_spec.rb +138 -0
  27. data/spec/integration/save_spec.rb +320 -0
  28. data/spec/integration/update_attributes_spec.rb +221 -0
  29. data/spec/integration/where_spec.rb +152 -0
  30. data/spec/lib/extensions/ethon/easy/queryable_spec.rb +4 -4
  31. data/spec/lib/remote_resource/base_spec.rb +54 -110
  32. data/spec/lib/remote_resource/builder_spec.rb +1 -1
  33. data/spec/lib/remote_resource/collection_spec.rb +1 -1
  34. data/spec/lib/remote_resource/connection_options_spec.rb +20 -17
  35. data/spec/lib/remote_resource/connection_spec.rb +36 -27
  36. data/spec/lib/remote_resource/querying/finder_methods_spec.rb +199 -72
  37. data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +228 -220
  38. data/spec/lib/remote_resource/request_spec.rb +313 -342
  39. data/spec/lib/remote_resource/response_spec.rb +9 -3
  40. data/spec/lib/remote_resource/rest_spec.rb +11 -11
  41. data/spec/lib/remote_resource/url_naming_determination_spec.rb +1 -1
  42. data/spec/lib/remote_resource/url_naming_spec.rb +7 -22
  43. data/spec/lib/remote_resource/util_spec.rb +56 -0
  44. data/spec/lib/remote_resource/version_spec.rb +2 -3
  45. data/spec/spec_helper.rb +37 -0
  46. metadata +33 -22
  47. data/lib/remote_resource/http_errors.rb +0 -33
  48. data/lib/remote_resource/response_handeling.rb +0 -48
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe RemoteResource::Request do
3
+ RSpec.describe RemoteResource::Request do
4
4
 
5
5
  module RemoteResource
6
6
  class RequestDummy
@@ -21,185 +21,110 @@ describe RemoteResource::Request do
21
21
  let(:dummy) { dummy_class.new id: '12' }
22
22
 
23
23
  let(:resource) { dummy_class }
24
- let(:rest_action) { :get }
24
+ let(:http_action) { :get }
25
25
  let(:connection_options) { {} }
26
26
  let(:attributes) do
27
27
  { name: 'Mies' }
28
28
  end
29
29
 
30
- let(:request) { described_class.new resource, rest_action, attributes, connection_options.dup }
30
+ let(:request) { described_class.new(resource, http_action, attributes, connection_options) }
31
31
 
32
- specify { expect(described_class).to include RemoteResource::HTTPErrors }
33
-
34
- describe '#connection' do
35
- it 'uses the connection of the resource_klass' do
36
- expect(request.connection).to eql Typhoeus::Request
37
- end
38
- end
39
-
40
- describe '#connection_options' do
41
- let(:threaded_connection_options_thread_name) { 'remote_resource.request_dummy.threaded_connection_options' }
42
-
43
- before { Thread.current[threaded_connection_options_thread_name] = threaded_connection_options }
44
- after { Thread.current[threaded_connection_options_thread_name] = nil }
45
-
46
- context 'when the given connection_options contain other values than the resource threaded_connection_options or connection_options' do
47
- let(:connection_options) do
48
- {
49
- site: 'http://www.barbaz.com',
50
- collection: true,
51
- path_prefix: '/api',
52
- root_element: :bazbar
53
- }
54
- end
55
-
56
- let(:threaded_connection_options) do
57
- {
58
- site: 'http://www.bazbazbaz.com',
59
- path_prefix: '/registration',
60
- path_postfix: '/promotion',
61
- root_element: :bazbazbaz
62
- }
63
- end
32
+ describe '#resource_klass' do
33
+ context 'when the resource is a RemoteResource class' do
34
+ let(:resource) { dummy_class }
64
35
 
65
- it 'merges the given connection_options with the resource connection_options while taking precedence over the resource connection_options after the threaded_connection_options' do
66
- expect(request.connection_options[:site]).to eql 'http://www.barbaz.com'
67
- expect(request.connection_options[:collection]).to eql true
68
- expect(request.connection_options[:path_prefix]).to eql '/api'
69
- expect(request.connection_options[:path_postfix]).to eql '/promotion'
70
- expect(request.connection_options[:root_element]).to eql :bazbar
36
+ it 'returns the resource' do
37
+ expect(request.resource_klass).to eql RemoteResource::RequestDummy
71
38
  end
72
39
  end
73
40
 
74
- context 'when the given connection_options do NOT contain other values than the resource threaded_connection_options or connection_options' do
75
- let(:connection_options) do
76
- {
77
- collection: true,
78
- path_prefix: '/api',
79
- root_element: :bazbar
80
- }
81
- end
82
-
83
- let(:threaded_connection_options) do
84
- {
85
- site: 'http://www.bazbazbaz.com',
86
- path_prefix: '/api',
87
- path_postfix: '/promotion'
88
- }
89
- end
41
+ context 'when the resource is a RemoteResource object' do
42
+ let(:resource) { dummy }
90
43
 
91
- it 'merges the given connection_options with the resource threaded_connection_options and connection_options' do
92
- expect(request.connection_options[:site]).to eql 'http://www.bazbazbaz.com'
93
- expect(request.connection_options[:collection]).to eql true
94
- expect(request.connection_options[:path_prefix]).to eql '/api'
95
- expect(request.connection_options[:path_postfix]).to eql '/promotion'
96
- expect(request.connection_options[:root_element]).to eql :bazbar
44
+ it 'returns the Class of the resource' do
45
+ expect(request.resource_klass).to eql RemoteResource::RequestDummy
97
46
  end
98
47
  end
99
48
  end
100
49
 
101
- describe '#original_connection_options' do
102
- let(:threaded_connection_options_thread_name) { 'remote_resource.request_dummy.threaded_connection_options' }
50
+ describe '#connection' do
51
+ it 'uses the connection of the resource_klass' do
52
+ expect(request.connection).to eql Typhoeus::Request
53
+ end
54
+ end
103
55
 
104
- before { Thread.current[threaded_connection_options_thread_name] = threaded_connection_options }
105
- after { Thread.current[threaded_connection_options_thread_name] = nil }
56
+ describe '#connection_options' do
57
+ around(:each) do |example|
58
+ dummy_class.site = 'From Klass.site'
59
+ dummy_class.version = 'From Klass.version'
106
60
 
107
- context 'when the given connection_options (original_connection_options) contain other values than the resource threaded_connection_options' do
108
- let(:connection_options) do
109
- {
110
- site: 'http://www.barbaz.com',
111
- collection: true,
112
- path_prefix: '/api',
113
- root_element: :bazbar
114
- }
61
+ dummy_class.with_connection_options(block_connection_options) do
62
+ example.run
115
63
  end
116
64
 
117
- let(:threaded_connection_options) do
118
- {
119
- site: 'http://www.bazbazbaz.com',
120
- path_prefix: '/registration',
121
- path_postfix: '/promotion',
122
- root_element: :bazbazbaz
123
- }
124
- end
65
+ dummy_class.site = 'http://www.foobar.com'
66
+ dummy_class.version = nil
67
+ end
125
68
 
126
- it 'merges the given connection_options (original_connection_options) with the resource threaded_connection_options while taking precedence over the resource threaded_connection_options' do
127
- expect(request.original_connection_options[:site]).to eql 'http://www.barbaz.com'
128
- expect(request.original_connection_options[:collection]).to eql true
129
- expect(request.original_connection_options[:path_prefix]).to eql '/api'
130
- expect(request.original_connection_options[:path_postfix]).to eql '/promotion'
131
- expect(request.original_connection_options[:root_element]).to eql :bazbar
132
- end
69
+ let(:block_connection_options) do
70
+ {
71
+ root_element: 'From .with_connection_options',
72
+ version: 'From .with_connection_options',
73
+ path_prefix: 'From .with_connection_options'
74
+ }
133
75
  end
134
76
 
135
- context 'when the given connection_options (original_connection_options) do NOT contain other values than the resource threaded_connection_options' do
136
- let(:connection_options) do
137
- {
138
- collection: true,
139
- path_prefix: '/api',
140
- root_element: :bazbar
141
- }
142
- end
77
+ let(:connection_options) do
78
+ {
79
+ root_element: 'From connection_options[]',
80
+ path_postfix: 'From connection_options[]'
81
+ }
82
+ end
143
83
 
144
- let(:threaded_connection_options) do
145
- {
146
- site: 'http://www.bazbazbaz.com',
147
- path_prefix: '/api',
148
- path_postfix: '/promotion'
149
- }
150
- end
84
+ let(:expected_connection_options) do
85
+ {
86
+ site: 'From Klass.site',
87
+ root_element: 'From connection_options[]',
88
+ version: 'From .with_connection_options',
89
+ path_prefix: 'From .with_connection_options',
90
+ path_postfix: 'From connection_options[]',
91
+ collection: false,
92
+ collection_name: nil,
93
+ collection_prefix: nil,
94
+ default_headers: {},
95
+ headers: {},
96
+ extension: nil,
97
+ }
98
+ end
151
99
 
152
- it 'merges the given connection_options (original_connection_options) with the resource threaded_connection_options' do
153
- expect(request.original_connection_options[:site]).to eql 'http://www.bazbazbaz.com'
154
- expect(request.original_connection_options[:collection]).to eql true
155
- expect(request.original_connection_options[:path_prefix]).to eql '/api'
156
- expect(request.original_connection_options[:path_postfix]).to eql '/promotion'
157
- expect(request.original_connection_options[:root_element]).to eql :bazbar
158
- end
100
+ it 'returns default connection options with are defined on the resource while overwriting the connection options according to the correct precedence' do
101
+ expect(request.connection_options).to eql expected_connection_options
159
102
  end
160
103
  end
161
104
 
162
105
  describe '#perform' do
163
- let(:connection) { Typhoeus::Request }
164
- let(:determined_request_url) { 'http://www.foobar.com/request_dummy.json' }
165
- let(:determined_params) { attributes }
166
- let(:determined_attributes) { attributes }
167
- let(:determined_headers) { { "Accept"=>"application/json" } }
168
-
169
- let(:typhoeus_request) { Typhoeus::Request.new determined_request_url }
170
- let(:typhoeus_response) do
171
- response = Typhoeus::Response.new
172
- response.request = typhoeus_request
106
+ let(:connection) { Typhoeus::Request }
107
+ let(:connection_request) { Typhoeus::Request.new(expected_request_url) }
108
+ let(:connection_response) do
109
+ response = Typhoeus::Response.new({ mock: true, body: 'response_body', code: response_code, headers: { 'Content-Type' => 'application/json', 'Server' => 'nginx/1.4.6 (Ubuntu)' } })
110
+ response.request = connection_request
173
111
  response
174
112
  end
175
113
 
176
- let(:determined_connection_options) { request.connection_options }
114
+ let(:response_code) { 200 }
115
+ let(:expected_response) { RemoteResource::Response.new(connection_response, connection_options) }
177
116
 
178
- before do
179
- allow_any_instance_of(Typhoeus::Request).to receive(:run) { typhoeus_response }
180
- allow(typhoeus_response).to receive(:response_code)
181
- allow(typhoeus_response).to receive(:success?) { true }
182
- end
117
+ before { allow_any_instance_of(Typhoeus::Request).to receive(:run) { connection_response } }
183
118
 
184
119
  shared_examples 'a conditional construct for the response' do
185
- context 'when the response is successful' do
186
- it 'makes a RemoteResource::Response object with the Typhoeus::Response object and the connection_options' do
187
- expect(RemoteResource::Response).to receive(:new).with(typhoeus_response, determined_connection_options).and_call_original
188
- request.perform
189
- end
190
-
120
+ context 'when the response is #success?' do
191
121
  it 'returns a RemoteResource::Response object' do
192
122
  expect(request.perform).to be_a RemoteResource::Response
193
123
  end
194
124
  end
195
125
 
196
- context 'when the response_code of the response is 422' do
197
- before { allow(typhoeus_response).to receive(:response_code) { 422 } }
198
-
199
- it 'makes a RemoteResource::Response object with the Typhoeus::Response object and the connection_options' do
200
- expect(RemoteResource::Response).to receive(:new).with(typhoeus_response, determined_connection_options).and_call_original
201
- request.perform
202
- end
126
+ context 'when the response is #unprocessable_entity? (response_code=422)' do
127
+ let(:response_code) { 422 }
203
128
 
204
129
  it 'returns a RemoteResource::Response object' do
205
130
  expect(request.perform).to be_a RemoteResource::Response
@@ -207,146 +132,215 @@ describe RemoteResource::Request do
207
132
  end
208
133
 
209
134
  context 'when the response is NOT successful' do
210
- before { allow(typhoeus_response).to receive(:success?) { false } }
135
+ let(:response_code) { 500 }
211
136
 
212
- it 'calls #raise_http_errors to raise an error' do
213
- expect(request).to receive(:raise_http_errors).with typhoeus_response
214
- request.perform
137
+ it 'raises a RemoteResource::HTTPError' do
138
+ expect { request.perform }.to raise_error RemoteResource::HTTPError
215
139
  end
216
140
  end
217
141
  end
218
142
 
219
- context 'when the rest_action is :get' do
220
- let(:rest_action) { 'get' }
221
-
222
- it 'makes a GET request with the attributes as params' do
223
- expect(connection).to receive(:get).with(determined_request_url, params: determined_params, headers: determined_headers).and_call_original
224
- request.perform
143
+ context 'when the http_action is :get' do
144
+ let(:http_action) { 'get' }
145
+ let(:attributes) do
146
+ {}
147
+ end
148
+ let(:connection_options) do
149
+ { params: { pseudonym: 'pseudonym' } }
225
150
  end
226
151
 
227
- it_behaves_like 'a conditional construct for the response'
228
- end
229
-
230
- context 'when the rest_action is :put' do
231
- let(:rest_action) { 'put' }
152
+ let(:expected_request_url) { 'http://www.foobar.com/request_dummy.json' }
153
+ let(:expected_params) { RemoteResource::Util.encode_params_to_query({ pseudonym: 'pseudonym' }) }
154
+ let(:expected_headers) { described_class::DEFAULT_HEADERS }
155
+ let(:expected_body) { nil }
156
+ let(:expected_connection_options) { request.connection_options }
232
157
 
233
- it 'makes a PUT request with the attributes as body' do
234
- expect(connection).to receive(:put).with(determined_request_url, body: determined_attributes, headers: determined_headers).and_call_original
158
+ it 'makes a GET request with the connection_options[:params] as query' do
159
+ expect(connection).to receive(:get).with(expected_request_url, params: expected_params, body: expected_body, headers: expected_headers).and_call_original
235
160
  request.perform
236
161
  end
237
162
 
238
- it_behaves_like 'a conditional construct for the response'
163
+ include_examples 'a conditional construct for the response'
239
164
  end
240
165
 
241
- context 'when the rest_action is :put' do
242
- let(:rest_action) { 'put' }
166
+ context 'when the http_action is :put' do
167
+ let(:http_action) { 'put' }
168
+ let(:attributes) do
169
+ { id: 15, name: 'Mies', famous: true }
170
+ end
171
+ let(:connection_options) do
172
+ {}
173
+ end
174
+
175
+ let(:expected_request_url) { 'http://www.foobar.com/request_dummy/15.json' }
176
+ let(:expected_params) { nil }
177
+ let(:expected_headers) { described_class::DEFAULT_HEADERS.merge(described_class::DEFAULT_CONTENT_TYPE) }
178
+ let(:expected_body) { JSON.generate(attributes) }
179
+ let(:expected_connection_options) { request.connection_options }
243
180
 
244
181
  it 'makes a PUT request with the attributes as body' do
245
- expect(connection).to receive(:put).with(determined_request_url, body: determined_attributes, headers: determined_headers).and_call_original
182
+ expect(connection).to receive(:put).with(expected_request_url, params: expected_params, body: expected_body, headers: expected_headers).and_call_original
246
183
  request.perform
247
184
  end
248
185
 
249
- it_behaves_like 'a conditional construct for the response'
186
+ include_examples 'a conditional construct for the response'
250
187
  end
251
188
 
252
- context 'when the rest_action is :patch' do
253
- let(:rest_action) { 'patch' }
189
+ context 'when the http_action is :patch' do
190
+ let(:http_action) { 'patch' }
191
+ let(:attributes) do
192
+ { id: 15, name: 'Mies', famous: true }
193
+ end
194
+ let(:connection_options) do
195
+ {}
196
+ end
197
+
198
+ let(:expected_request_url) { 'http://www.foobar.com/request_dummy/15.json' }
199
+ let(:expected_params) { nil }
200
+ let(:expected_headers) { described_class::DEFAULT_HEADERS.merge(described_class::DEFAULT_CONTENT_TYPE) }
201
+ let(:expected_body) { JSON.generate(attributes) }
202
+ let(:expected_connection_options) { request.connection_options }
254
203
 
255
204
  it 'makes a PATCH request with the attributes as body' do
256
- expect(connection).to receive(:patch).with(determined_request_url, body: determined_attributes, headers: determined_headers).and_call_original
205
+ expect(connection).to receive(:patch).with(expected_request_url, params: expected_params, body: expected_body, headers: expected_headers).and_call_original
257
206
  request.perform
258
207
  end
259
208
 
260
- it_behaves_like 'a conditional construct for the response'
209
+ include_examples 'a conditional construct for the response'
261
210
  end
262
211
 
263
- context 'when the rest_action is :post' do
264
- let(:rest_action) { 'post' }
212
+ context 'when the http_action is :post' do
213
+ let(:http_action) { 'post' }
214
+ let(:attributes) do
215
+ { name: 'Mies', famous: true }
216
+ end
217
+ let(:connection_options) do
218
+ {}
219
+ end
220
+
221
+ let(:expected_request_url) { 'http://www.foobar.com/request_dummy.json' }
222
+ let(:expected_params) { nil }
223
+ let(:expected_headers) { described_class::DEFAULT_HEADERS.merge(described_class::DEFAULT_CONTENT_TYPE) }
224
+ let(:expected_body) { JSON.generate(attributes) }
225
+ let(:expected_connection_options) { request.connection_options }
265
226
 
266
227
  it 'makes a POST request with the attributes as body' do
267
- expect(connection).to receive(:post).with(determined_request_url, body: determined_attributes, headers: determined_headers).and_call_original
228
+ expect(connection).to receive(:post).with(expected_request_url, params: expected_params, body: expected_body, headers: expected_headers).and_call_original
268
229
  request.perform
269
230
  end
270
231
 
271
- it_behaves_like 'a conditional construct for the response'
232
+ include_examples 'a conditional construct for the response'
272
233
  end
273
234
 
274
- context 'when the rest_action is :delete' do
275
- let(:rest_action) { 'delete' }
235
+ context 'when the http_action is :delete' do
236
+ let(:http_action) { 'delete' }
237
+ let(:attributes) do
238
+ { id: 15 }
239
+ end
240
+ let(:connection_options) do
241
+ { params: { pseudonym: 'pseudonym' } }
242
+ end
276
243
 
277
- it 'makes a DELETE request with the attributes as body' do
278
- expect(connection).to receive(:delete).with(determined_request_url, params: determined_params, headers: determined_headers).and_call_original
244
+ let(:expected_request_url) { 'http://www.foobar.com/request_dummy/15.json' }
245
+ let(:expected_params) { RemoteResource::Util.encode_params_to_query({ pseudonym: 'pseudonym' }) }
246
+ let(:expected_headers) { described_class::DEFAULT_HEADERS }
247
+ let(:expected_body) { nil }
248
+ let(:expected_connection_options) { request.connection_options }
249
+
250
+ it 'makes a DELETE request with the connection_options[:params] as query' do
251
+ expect(connection).to receive(:delete).with(expected_request_url, params: expected_params, body: expected_body, headers: expected_headers).and_call_original
279
252
  request.perform
280
253
  end
281
254
 
282
- it_behaves_like 'a conditional construct for the response'
255
+ include_examples 'a conditional construct for the response'
283
256
  end
284
257
 
285
- context 'when the rest_action is unknown' do
286
- let(:rest_action) { 'foo' }
258
+ context 'when the http_action is unknown' do
259
+ let(:http_action) { 'foo' }
260
+ let(:expected_request_url) { '' }
287
261
 
288
- it 'raises the RemoteResource::RESTActionUnknown error' do
289
- expect{ request.perform }.to raise_error RemoteResource::RESTActionUnknown, "for action: 'foo'"
262
+ it 'raises the RemoteResource::HTTPMethodUnsupported error' do
263
+ expect{ request.perform }.to raise_error RemoteResource::HTTPMethodUnsupported, 'Requested HTTP method=foo is NOT supported, the HTTP action MUST be a supported HTTP action=get, put, patch, post, delete'
290
264
  end
291
265
  end
292
266
  end
293
267
 
294
- describe '#determined_request_url' do
268
+ describe '#request_url' do
295
269
  context 'the attributes contain an id' do
296
270
  let(:attributes) do
297
271
  { id: 12, name: 'Mies' }
298
272
  end
299
273
 
300
274
  it 'uses the id for the request url' do
301
- expect(request.determined_request_url).to eql 'http://www.foobar.com/request_dummy/12.json'
275
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy/12.json'
302
276
  end
303
277
  end
304
278
 
305
- context 'the attributes do NOT contain an id' do
279
+ context 'the connection_options contain an id' do
280
+ let(:connection_options) do
281
+ { id: 12 }
282
+ end
283
+
284
+ it 'uses the id for the request url' do
285
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy/12.json'
286
+ end
287
+ end
288
+
289
+ context 'the attributes or connection_options do NOT contain an id' do
306
290
  it 'does NOT use the id for the request url' do
307
- expect(request.determined_request_url).to eql 'http://www.foobar.com/request_dummy.json'
291
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy.json'
308
292
  end
309
293
  end
310
294
 
311
- context 'the given connection_options (original_connection_options) contain a base_url' do
295
+ context 'the connection_options contain a base_url' do
312
296
  let(:connection_options) do
313
297
  { base_url: 'http://www.foo.com/api' }
314
298
  end
315
299
 
316
300
  it 'uses the base_url for the request url' do
317
- expect(request.determined_request_url).to eql 'http://www.foo.com/api.json'
301
+ expect(request.request_url).to eql 'http://www.foo.com/api.json'
318
302
  end
319
303
  end
320
304
 
321
- context 'the given connection_options (original_connection_options) do NOT contain a base_url' do
305
+ context 'the connection_options do NOT contain a base_url' do
322
306
  it 'does NOT use the base_url for the request url' do
323
- expect(request.determined_request_url).to eql 'http://www.foobar.com/request_dummy.json'
307
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy.json'
324
308
  end
325
309
  end
326
310
 
327
- context 'the given connection_options contain a collection' do
311
+ context 'the connection_options contain a collection' do
328
312
  let(:connection_options) do
329
313
  { collection: true }
330
314
  end
331
315
 
332
316
  it 'uses the collection to determine the base_url for the request url' do
333
- expect(request.determined_request_url).to eql 'http://www.foobar.com/request_dummies.json'
317
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummies.json'
334
318
  end
335
319
  end
336
320
 
337
- context 'the connection_options contain a content_type' do
321
+ context 'the connection_options contain a extension' do
338
322
  let(:connection_options) do
339
- { content_type: '' }
323
+ { extension: '.vnd+json' }
340
324
  end
341
325
 
342
- it 'uses the content_type for the request url' do
343
- expect(request.determined_request_url).to eql 'http://www.foobar.com/request_dummy'
326
+ it 'uses the extension for the request url' do
327
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy.vnd+json'
328
+ end
329
+ end
330
+
331
+ context 'the connection_options contain a blank extension' do
332
+ let(:connection_options) do
333
+ { extension: '' }
334
+ end
335
+
336
+ it 'does NOT use a extension for the request url' do
337
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy'
344
338
  end
345
339
  end
346
340
 
347
341
  context 'the connection_options do NOT contain a content_type' do
348
- it 'does NOT use the content_type for the request url' do
349
- expect(request.determined_request_url).to eql 'http://www.foobar.com/request_dummy.json'
342
+ it 'uses the DEFAULT_EXTENSION for the request url' do
343
+ expect(request.request_url).to eql 'http://www.foobar.com/request_dummy.json'
350
344
  end
351
345
  end
352
346
 
@@ -358,218 +352,196 @@ describe RemoteResource::Request do
358
352
  { collection_options: { parent_id: 23 } }
359
353
  end
360
354
 
361
- it { expect(request.determined_request_url).to eql 'http://www.foobar.com/parent/23/request_dummy_with_collection_prefix.json' }
355
+ it { expect(request.request_url).to eql 'http://www.foobar.com/parent/23/request_dummy_with_collection_prefix.json' }
362
356
  end
363
357
 
364
358
  context 'when connection_options does NOT include collection_options' do
365
359
  it 'raises error' do
366
- expect{ request.determined_request_url }.to raise_error(RemoteResource::CollectionOptionKeyError)
360
+ expect{ request.request_url }.to raise_error(RemoteResource::CollectionOptionKeyError)
367
361
  end
368
362
  end
369
363
  end
370
364
  end
371
365
 
372
- describe '#determined_params' do
373
- context 'the connection_options contain no_params' do
366
+ describe '#query' do
367
+ context 'when connection_options[:params] are present' do
374
368
  let(:connection_options) do
375
- {
376
- params: { page: 5, limit: 15 },
377
- no_params: true
378
- }
369
+ { root_element: :data, params: { pseudonym: 'pseudonym', labels: [1, '2', 'three'], pagination: { page: 5, limit: 15, ordered: true } } }
379
370
  end
380
371
 
381
- it 'returns nil' do
382
- expect(request.determined_params).to be_nil
383
- end
384
- end
385
-
386
- context 'the connection_options do NOT contain a no_params' do
387
- context 'and the connection_options contain no_attributes' do
388
- let(:connection_options) do
389
- {
390
- params: { page: 5, limit: 15 },
391
- no_params: false,
392
- no_attributes: true
393
- }
394
- end
395
-
396
- it 'returns the params' do
397
- expect(request.determined_params).to eql({ page: 5, limit: 15 })
398
- end
372
+ let(:expected_query) do
373
+ 'pseudonym=pseudonym&labels[]=1&labels[]=2&labels[]=three&pagination[page]=5&pagination[limit]=15&pagination[ordered]=true'
399
374
  end
400
375
 
401
- context 'and the connection_options do NOT contain no_attributes' do
402
- let(:connection_options) do
403
- {
404
- params: { page: 5, limit: 15 },
405
- no_params: false,
406
- no_attributes: false
407
- }
408
- end
409
-
410
- it 'returns the params merge with the attributes' do
411
- expect(request.determined_params).to eql({ name: 'Mies', page: 5, limit: 15 })
412
- end
376
+ it 'returns the URL-encoded params' do
377
+ expect(CGI.unescape(request.query)).to eql expected_query
413
378
  end
414
379
  end
415
- end
416
380
 
417
- describe '#determined_attributes' do
418
- context 'the connection_options contain no_attributes' do
381
+ context 'when connection_options[:params] are NOT present' do
419
382
  let(:connection_options) do
420
- { no_attributes: true }
383
+ { root_element: :data }
421
384
  end
422
385
 
423
- it 'returns an empty Hash' do
424
- expect(request.determined_attributes).to eql({})
386
+ it 'returns nil' do
387
+ expect(request.query).to be_nil
425
388
  end
426
389
  end
390
+ end
427
391
 
428
- context 'the connection_options do NOT contain a no_attributes' do
429
- it 'does NOT return an empty Hash' do
430
- expect(request.determined_attributes).not_to eql({})
431
- end
392
+ describe '#body' do
393
+ let(:attributes) do
394
+ { name: 'Mies', featured: true, labels: [1, '2', 'three'] }
432
395
  end
433
396
 
434
- context 'the connection_options contain a root_element' do
435
- let(:connection_options) do
436
- { root_element: :foobar }
437
- end
397
+ context 'when the http_action is :put, :patch or :post' do
398
+ let(:http_action) { :post }
438
399
 
439
- let(:packed_up_attributes) do
440
- { 'foobar' => { name: 'Mies' } }
400
+ let(:expected_body) do
401
+ '{"name":"Mies","featured":true,"labels":[1,"2","three"]}'
441
402
  end
442
403
 
443
- it 'packs up the attributes with the root_element' do
444
- expect(request.determined_attributes).to eql packed_up_attributes
404
+ it 'returns the JSON-encoded attributes' do
405
+ expect(request.body).to eql expected_body
445
406
  end
446
407
  end
447
408
 
448
- context 'the connection_options do NOT contain a root_element' do
449
- it 'does NOT pack up the attributes with the root_element' do
450
- expect(request.determined_attributes).to eql attributes
409
+ context 'when the http_action is NOT :put, :patch or :post' do
410
+ let(:http_action) { :get }
411
+
412
+ it 'returns nil' do
413
+ expect(request.body).to be_nil
451
414
  end
452
415
  end
453
416
  end
454
417
 
455
- describe '#determined_headers' do
456
- let(:global_headers) do
457
- {
458
- 'X-Locale' => 'en',
459
- 'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
460
- }
461
- end
418
+ describe '#attributes' do
419
+ context 'default behaviour' do
420
+ let(:attributes) do
421
+ { name: 'Mies', featured: true, labels: [1, '2', 'three'] }
422
+ end
462
423
 
463
- before { RemoteResource::Base.global_headers = global_headers }
464
- after { RemoteResource::Base.global_headers = nil }
424
+ let(:expected_attributes) do
425
+ { name: 'Mies', featured: true, labels: [1, '2', 'three'] }
426
+ end
465
427
 
466
- let(:headers) do
467
- { 'Baz' => 'FooBar' }
468
- end
428
+ it 'returns the given attributes' do
429
+ expect(request.attributes).to eql expected_attributes
430
+ end
469
431
 
470
- let(:default_headers) do
471
- dummy_class.default_headers
432
+ context 'and there are NO given attributes' do
433
+ let(:attributes) do
434
+ nil
435
+ end
436
+
437
+ it 'returns an empty Hash' do
438
+ expect(request.attributes).to eql({})
439
+ end
440
+ end
472
441
  end
473
442
 
474
- context 'the connection_options contain a default_headers' do
475
- let(:default_headers) do
476
- { 'Foo' => 'Bar' }
443
+ context 'when connection_options[:root_element] is present' do
444
+ let(:connection_options) do
445
+ { root_element: :data }
477
446
  end
478
447
 
479
- context 'and the given connection_options (original_connection_options) contain a headers' do
480
- let(:connection_options) do
481
- { default_headers: default_headers, headers: headers }
482
- end
448
+ let(:attributes) do
449
+ { name: 'Mies', featured: true, labels: [1, '2', 'three'] }
450
+ end
483
451
 
484
- it 'uses the default_headers for the request headers' do
485
- expect(request.determined_headers).to eql default_headers.merge(global_headers)
486
- end
452
+ it 'returns the given attributes wrapped in the connection_options[:root_element]' do
453
+ expect(request.attributes).to eql({ data: { name: 'Mies', featured: true, labels: [1, '2', 'three'] } })
487
454
  end
488
455
 
489
- context 'and the given connection_options (original_connection_options) do NOT contain a headers' do
490
- let(:connection_options) do
491
- { default_headers: default_headers }
456
+ context 'and there are NO given attributes' do
457
+ let(:attributes) do
458
+ nil
492
459
  end
493
460
 
494
- it 'uses the default_headers for the request headers' do
495
- expect(request.determined_headers).to eql default_headers.merge(global_headers)
461
+ it 'returns nil wrapped in the connection_options[:root_element]' do
462
+ expect(request.attributes).to eql({ data: nil })
496
463
  end
497
464
  end
498
465
  end
466
+ end
499
467
 
500
- context 'the connection_options do NOT contain a default_headers' do
501
- context 'and the given connection_options (original_connection_options) contain a headers' do
502
- let(:connection_options) do
503
- { headers: headers }
504
- end
468
+ describe '#headers' do
469
+ context 'default behaviour' do
470
+ let(:expected_headers) do
471
+ { 'Accept' => 'application/json', 'User-Agent' => "RemoteResource #{RemoteResource::VERSION}" }
472
+ end
505
473
 
506
- it 'uses the headers for the request headers' do
507
- expect(request.determined_headers).to eql default_headers.merge(headers).merge(global_headers)
508
- end
474
+ it 'returns the default headers' do
475
+ expect(request.headers).to eql expected_headers
509
476
  end
477
+ end
510
478
 
511
- context 'and the given connection_options (original_connection_options) do NOT contain a headers' do
512
- context 'and the resource contains a extra_headers' do
513
- let(:extra_headers) do
514
- { 'BarBaz' => 'Baz' }
515
- end
479
+ context 'when connection_options[:default_headers] are present' do
480
+ let(:connection_options) do
481
+ { default_headers: { 'User-Agent' => 'From connection_options[:default_headers]', 'X-Locale' => 'From connection_options[:default_headers]' } }
482
+ end
516
483
 
517
- it 'uses the headers of the resource for the request headers' do
518
- dummy_class.extra_headers = extra_headers
519
- dummy_class.connection_options.reload!
484
+ let(:expected_headers) do
485
+ { 'User-Agent' => 'From connection_options[:default_headers]', 'X-Locale' => 'From connection_options[:default_headers]' }
486
+ end
520
487
 
521
- expect(request.determined_headers).to eql default_headers.merge(extra_headers).merge(global_headers)
488
+ it 'returns the default headers while overwriting the headers according to the correct precedence' do
489
+ expect(request.headers).to eql expected_headers
490
+ end
491
+ end
522
492
 
523
- dummy_class.extra_headers = nil
524
- dummy_class.connection_options.reload!
525
- end
526
- end
493
+ context 'when RemoteResource::Base.global_headers are present' do
494
+ let(:expected_headers) do
495
+ { 'Accept' => 'application/json', 'User-Agent' => 'From RemoteResource::Base.global_headers', 'X-Locale' => 'From RemoteResource::Base.global_headers' }
496
+ end
527
497
 
528
- context 'and the resource does NOT contain a extra_headers' do
529
- it 'does NOT use the headers for the request headers' do
530
- expect(request.determined_headers).to eql default_headers.merge(global_headers)
531
- end
532
- end
498
+ before { RemoteResource::Base.global_headers = { 'User-Agent' => 'From RemoteResource::Base.global_headers', 'X-Locale' => 'From RemoteResource::Base.global_headers' } }
499
+ after { RemoteResource::Base.global_headers = nil }
500
+
501
+ it 'returns the default headers while overwriting the headers according to the correct precedence' do
502
+ expect(request.headers).to eql expected_headers
533
503
  end
534
504
  end
535
- end
536
505
 
537
- describe '#resource_klass' do
538
- context 'when the resource is a RemoteResource class' do
539
- let(:resource) { dummy_class }
506
+ context 'when connection_options[:headers] are present' do
507
+ let(:connection_options) do
508
+ { headers: { 'User-Agent' => 'From connection_options[:headers]', 'X-Locale' => 'From connection_options[:headers]' } }
509
+ end
540
510
 
541
- it 'returns the resource' do
542
- expect(request.send :resource_klass).to eql RemoteResource::RequestDummy
511
+ let(:expected_headers) do
512
+ { 'Accept' => 'application/json', 'User-Agent' => 'From connection_options[:headers]', 'X-Locale' => 'From connection_options[:headers]' }
513
+ end
514
+
515
+ it 'returns the default headers while overwriting the headers according to the correct precedence' do
516
+ expect(request.headers).to eql expected_headers
543
517
  end
544
518
  end
545
519
 
546
- context 'when the resource is a RemoteResource object' do
547
- let(:resource) { dummy }
520
+ context 'when conditional_headers are present' do
521
+ context 'when a body is present' do
522
+ let(:http_action) { 'post' }
523
+ let(:expected_headers) do
524
+ { 'Accept' => 'application/json', 'User-Agent' => "RemoteResource #{RemoteResource::VERSION}", 'Content-Type' => 'application/json' }
525
+ end
548
526
 
549
- it 'returns the Class of the resource' do
550
- expect(request.send :resource_klass).to eql RemoteResource::RequestDummy
527
+ it 'returns the default headers with the conditional_headers' do
528
+ expect(request.headers).to eql expected_headers
529
+ end
551
530
  end
552
531
  end
553
532
  end
554
533
 
555
- describe '#raise_http_errors' do
556
- let(:effective_url) { 'http://www.foobar.com/request_dummy.json' }
557
- let(:response) { instance_double Typhoeus::Response }
558
- let(:raise_http_errors) { request.send :raise_http_errors, response }
559
-
560
- before do
561
- allow(response).to receive(:response_code) { response_code }
562
- allow(response).to receive(:effective_url) { effective_url }
563
- end
534
+ describe '#raise_http_error' do
535
+ let(:connection_response) { instance_double(Typhoeus::Response, request: instance_double(Typhoeus::Request)) }
536
+ let(:response) { RemoteResource::Response.new(connection_response, connection_options) }
564
537
 
565
538
  context 'when the response code is 301, 302, 303 or 307' do
566
539
  response_codes = [301, 302, 303, 307]
567
540
  response_codes.each do |response_code|
568
-
569
541
  it "raises a RemoteResource::HTTPRedirectionError with response code #{response_code}" do
570
542
  allow(response).to receive(:response_code) { response_code }
571
543
 
572
- expect{ raise_http_errors }.to raise_error RemoteResource::HTTPRedirectionError, "for url: #{effective_url} with HTTP response status: #{response_code} and response: #{response.inspect}"
544
+ expect { request.send(:raise_http_error, request, response) }.to raise_error RemoteResource::HTTPRedirectionError
573
545
  end
574
546
  end
575
547
  end
@@ -594,36 +566,35 @@ describe RemoteResource::Request do
594
566
  499 => RemoteResource::HTTPClientClosedRequest,
595
567
  }
596
568
  response_codes_with_error_class.each do |response_code, error_class|
597
-
598
569
  it "raises a #{error_class} with response code #{response_code}" do
599
570
  allow(response).to receive(:response_code) { response_code }
600
571
 
601
- expect{ raise_http_errors }.to raise_error error_class, "for url: #{effective_url} with HTTP response status: #{response_code} and response: #{response.inspect}"
572
+ expect { request.send(:raise_http_error, request, response) }.to raise_error error_class
602
573
  end
603
574
  end
604
575
  end
605
576
 
606
577
  context 'when the response code is in the 4xx range and no other error is raised' do
607
- let(:response_code) { 430 }
608
-
609
578
  it 'raises a RemoteResource::HTTPClientError' do
610
- expect{ raise_http_errors }.to raise_error RemoteResource::HTTPClientError, "for url: #{effective_url} with HTTP response status: #{response_code} and response: #{response.inspect}"
579
+ allow(response).to receive(:response_code) { 430 }
580
+
581
+ expect { request.send(:raise_http_error, request, response) }.to raise_error RemoteResource::HTTPClientError
611
582
  end
612
583
  end
613
584
 
614
585
  context 'when the response code is in the 5xx range and no other error is raised' do
615
- let(:response_code) { 501 }
616
-
617
586
  it 'raises a RemoteResource::HTTPServerError' do
618
- expect{ raise_http_errors }.to raise_error RemoteResource::HTTPServerError, "for url: #{effective_url} with HTTP response status: #{response_code} and response: #{response.inspect}"
587
+ allow(response).to receive(:response_code) { 501 }
588
+
589
+ expect { request.send(:raise_http_error, request, response) }.to raise_error RemoteResource::HTTPServerError
619
590
  end
620
591
  end
621
592
 
622
593
  context 'when the response code is nothing and no other error is raised' do
623
- let(:response_code) { nil }
624
-
625
594
  it 'raises a RemoteResource::HTTPError' do
626
- expect{ raise_http_errors }.to raise_error RemoteResource::HTTPError, "for url: #{effective_url} with HTTP response: #{response.inspect}"
595
+ allow(response).to receive(:response_code) { nil }
596
+
597
+ expect { request.send(:raise_http_error, request, response) }.to raise_error RemoteResource::HTTPError
627
598
  end
628
599
  end
629
600
  end