ddy_remote_resource 0.4.11 → 1.0.0.rc1
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Guardfile +3 -0
- data/lib/remote_resource.rb +77 -34
- data/lib/remote_resource/base.rb +20 -8
- data/lib/remote_resource/connection.rb +26 -5
- data/lib/remote_resource/connection_options.rb +5 -3
- data/lib/remote_resource/querying/finder_methods.rb +3 -3
- data/lib/remote_resource/querying/persistence_methods.rb +17 -12
- data/lib/remote_resource/request.rb +96 -62
- data/lib/remote_resource/response.rb +5 -1
- data/lib/remote_resource/rest.rb +13 -17
- data/lib/remote_resource/url_naming.rb +4 -10
- data/lib/remote_resource/url_naming_determination.rb +1 -3
- data/lib/remote_resource/util.rb +64 -0
- data/lib/remote_resource/version.rb +1 -1
- data/remote_resource.gemspec +2 -2
- data/spec/fixtures/text_file.txt +1 -0
- data/spec/integration/all_spec.rb +166 -0
- data/spec/integration/collection_prefix_spec.rb +99 -0
- data/spec/integration/create_spec.rb +181 -0
- data/spec/integration/destroy_spec.rb +252 -0
- data/spec/integration/find_by_spec.rb +168 -0
- data/spec/integration/find_spec.rb +139 -0
- data/spec/integration/headers_spec.rb +222 -0
- data/spec/integration/naming_spec.rb +138 -0
- data/spec/integration/save_spec.rb +320 -0
- data/spec/integration/update_attributes_spec.rb +221 -0
- data/spec/integration/where_spec.rb +152 -0
- data/spec/lib/extensions/ethon/easy/queryable_spec.rb +4 -4
- data/spec/lib/remote_resource/base_spec.rb +54 -110
- data/spec/lib/remote_resource/builder_spec.rb +1 -1
- data/spec/lib/remote_resource/collection_spec.rb +1 -1
- data/spec/lib/remote_resource/connection_options_spec.rb +20 -17
- data/spec/lib/remote_resource/connection_spec.rb +36 -27
- data/spec/lib/remote_resource/querying/finder_methods_spec.rb +199 -72
- data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +228 -220
- data/spec/lib/remote_resource/request_spec.rb +313 -342
- data/spec/lib/remote_resource/response_spec.rb +9 -3
- data/spec/lib/remote_resource/rest_spec.rb +11 -11
- data/spec/lib/remote_resource/url_naming_determination_spec.rb +1 -1
- data/spec/lib/remote_resource/url_naming_spec.rb +7 -22
- data/spec/lib/remote_resource/util_spec.rb +56 -0
- data/spec/lib/remote_resource/version_spec.rb +2 -3
- data/spec/spec_helper.rb +37 -0
- metadata +33 -22
- data/lib/remote_resource/http_errors.rb +0 -33
- 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(:
|
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
|
30
|
+
let(:request) { described_class.new(resource, http_action, attributes, connection_options) }
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
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 '
|
66
|
-
expect(request.
|
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
|
75
|
-
let(:
|
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 '
|
92
|
-
expect(request.
|
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 '#
|
102
|
-
|
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
|
-
|
105
|
-
|
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
|
-
|
108
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
153
|
-
|
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)
|
164
|
-
let(:
|
165
|
-
let(:
|
166
|
-
|
167
|
-
|
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(:
|
114
|
+
let(:response_code) { 200 }
|
115
|
+
let(:expected_response) { RemoteResource::Response.new(connection_response, connection_options) }
|
177
116
|
|
178
|
-
before
|
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
|
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
|
197
|
-
|
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
|
-
|
135
|
+
let(:response_code) { 500 }
|
211
136
|
|
212
|
-
it '
|
213
|
-
expect
|
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
|
220
|
-
let(:
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
let(:
|
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
|
234
|
-
expect(connection).to receive(:
|
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
|
-
|
163
|
+
include_examples 'a conditional construct for the response'
|
239
164
|
end
|
240
165
|
|
241
|
-
context 'when the
|
242
|
-
let(:
|
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(
|
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
|
-
|
186
|
+
include_examples 'a conditional construct for the response'
|
250
187
|
end
|
251
188
|
|
252
|
-
context 'when the
|
253
|
-
let(:
|
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(
|
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
|
-
|
209
|
+
include_examples 'a conditional construct for the response'
|
261
210
|
end
|
262
211
|
|
263
|
-
context 'when the
|
264
|
-
let(:
|
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(
|
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
|
-
|
232
|
+
include_examples 'a conditional construct for the response'
|
272
233
|
end
|
273
234
|
|
274
|
-
context 'when the
|
275
|
-
let(:
|
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
|
-
|
278
|
-
|
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
|
-
|
255
|
+
include_examples 'a conditional construct for the response'
|
283
256
|
end
|
284
257
|
|
285
|
-
context 'when the
|
286
|
-
let(:
|
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::
|
289
|
-
expect{ request.perform }.to raise_error RemoteResource::
|
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 '#
|
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.
|
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
|
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.
|
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
|
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.
|
301
|
+
expect(request.request_url).to eql 'http://www.foo.com/api.json'
|
318
302
|
end
|
319
303
|
end
|
320
304
|
|
321
|
-
context 'the
|
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.
|
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
|
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.
|
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
|
321
|
+
context 'the connection_options contain a extension' do
|
338
322
|
let(:connection_options) do
|
339
|
-
{
|
323
|
+
{ extension: '.vnd+json' }
|
340
324
|
end
|
341
325
|
|
342
|
-
it 'uses the
|
343
|
-
expect(request.
|
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 '
|
349
|
-
expect(request.
|
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.
|
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.
|
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 '#
|
373
|
-
context '
|
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
|
-
|
382
|
-
|
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
|
-
|
402
|
-
|
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
|
-
|
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
|
-
{
|
383
|
+
{ root_element: :data }
|
421
384
|
end
|
422
385
|
|
423
|
-
it 'returns
|
424
|
-
expect(request.
|
386
|
+
it 'returns nil' do
|
387
|
+
expect(request.query).to be_nil
|
425
388
|
end
|
426
389
|
end
|
390
|
+
end
|
427
391
|
|
428
|
-
|
429
|
-
|
430
|
-
|
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
|
435
|
-
let(:
|
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(:
|
440
|
-
|
400
|
+
let(:expected_body) do
|
401
|
+
'{"name":"Mies","featured":true,"labels":[1,"2","three"]}'
|
441
402
|
end
|
442
403
|
|
443
|
-
it '
|
444
|
-
expect(request.
|
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
|
449
|
-
|
450
|
-
|
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 '#
|
456
|
-
|
457
|
-
|
458
|
-
'
|
459
|
-
|
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
|
-
|
464
|
-
|
424
|
+
let(:expected_attributes) do
|
425
|
+
{ name: 'Mies', featured: true, labels: [1, '2', 'three'] }
|
426
|
+
end
|
465
427
|
|
466
|
-
|
467
|
-
|
468
|
-
|
428
|
+
it 'returns the given attributes' do
|
429
|
+
expect(request.attributes).to eql expected_attributes
|
430
|
+
end
|
469
431
|
|
470
|
-
|
471
|
-
|
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 '
|
475
|
-
let(:
|
476
|
-
{
|
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
|
-
|
480
|
-
|
481
|
-
|
482
|
-
end
|
448
|
+
let(:attributes) do
|
449
|
+
{ name: 'Mies', featured: true, labels: [1, '2', 'three'] }
|
450
|
+
end
|
483
451
|
|
484
|
-
|
485
|
-
|
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
|
490
|
-
let(:
|
491
|
-
|
456
|
+
context 'and there are NO given attributes' do
|
457
|
+
let(:attributes) do
|
458
|
+
nil
|
492
459
|
end
|
493
460
|
|
494
|
-
it '
|
495
|
-
expect(request.
|
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
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
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
|
-
|
507
|
-
|
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
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
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
|
-
|
518
|
-
|
519
|
-
|
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
|
-
|
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
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
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
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
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
|
-
|
538
|
-
|
539
|
-
|
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
|
-
|
542
|
-
|
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
|
547
|
-
|
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
|
-
|
550
|
-
|
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 '#
|
556
|
-
let(:
|
557
|
-
let(: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{
|
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{
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|