heroics 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,221 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'minitest/autorun'
3
- require 'time'
4
-
5
- require 'heroics'
6
-
7
- module ExconHelper
8
- def setup
9
- super
10
- Excon.stubs.clear
11
- Excon.defaults[:mock] = true
12
- end
13
-
14
- def teardown
15
- # FIXME This is a bit ugly, but Excon doesn't provide a builtin way to
16
- # ensure that a request was invoked, so we have to do it ourselves.
17
- # Without this, and the Excon.stubs.pop calls in the tests that use this
18
- # helper, tests will pass if request logic is completely removed from
19
- # application code. -jkakar
20
- assert(Excon.stubs.empty?, 'Expected HTTP requests were not made.')
21
- super
22
- end
23
- end
24
-
25
- # A simple JSON schema for testing purposes.
26
- SAMPLE_SCHEMA = {
27
- 'description' => 'Sample schema for use in tests.',
28
- 'definitions' => {
29
- 'resource' => {
30
- 'description' => 'A sample resource to use in tests.',
31
- 'id' => 'schema/resource',
32
- '$schema' => 'http://json-schema.org/draft-04/hyper-schema',
33
- 'title' => 'Sample resource title',
34
- 'type' => ['object'],
35
-
36
- 'definitions' => {
37
- 'date_field' => {
38
- 'description' => 'A sample date field',
39
- 'example' => '2013-10-19 22:10:29Z',
40
- 'format' => 'date-time',
41
- 'readOnly' => true,
42
- 'type' => ['string']
43
- },
44
-
45
- 'string_field' => {
46
- 'description' => 'A sample string field',
47
- 'example' => 'Sample text.',
48
- 'readOnly' => true,
49
- 'type' => ['string']
50
- },
51
-
52
- 'boolean_field' => {
53
- 'description' => 'A sample boolean field',
54
- 'example' => true,
55
- 'type' => ['boolean']
56
- },
57
-
58
- 'uuid_field' => {
59
- 'description' => 'A sample UUID field',
60
- 'example' => '44724831-bf66-4bc2-865f-e2c4c2b14c78',
61
- 'format' => 'uuid',
62
- 'readOnly' => true,
63
- 'type' => ['string']
64
- },
65
-
66
- 'email_field' => {
67
- 'description' => 'A sample email address field',
68
- 'example' => 'username@example.com',
69
- 'format' => 'email',
70
- 'readOnly' => true,
71
- 'type' => ['string']
72
- },
73
-
74
- 'identity' => {
75
- 'oneOf' => [
76
- {'$ref' => '#/definitions/resource/definitions/uuid_field'},
77
- {'$ref' => '#/definitions/resource/definitions/email_field'}]
78
- }
79
- },
80
-
81
- 'properties' => {
82
- 'date_field' => {
83
- '$ref' => '#/definitions/resource/definitions/date_field'},
84
- 'string_field' => {
85
- '$ref' => '#/definitions/resource/definitions/string_field'},
86
- 'boolean_field' => {
87
- '$ref' => '#/definitions/resource/definitions/boolean_field'},
88
- 'uuid_field' => {
89
- '$ref' => '#/definitions/resource/definitions/uuid_field'},
90
- 'email_field' => {
91
- '$ref' => '#/definitions/resource/definitions/email_field'},
92
- },
93
-
94
- 'links' => [
95
- {'description' => 'Show all sample resources',
96
- 'href' => '/resource',
97
- 'method' => 'GET',
98
- 'rel' => 'instances',
99
- 'title' => 'List'},
100
-
101
- {'description' => 'Show a sample resource',
102
- 'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fuuid_field)}',
103
- 'method' => 'GET',
104
- 'rel' => 'self',
105
- 'title' => 'Info'},
106
-
107
- {'description' => 'Show a sample resource',
108
- 'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fidentity)}',
109
- 'method' => 'GET',
110
- 'rel' => 'self',
111
- 'title' => 'Identify resource'},
112
-
113
- {'description' => 'Create a sample resource',
114
- 'href' => '/resource',
115
- 'method' => 'POST',
116
- 'rel' => 'create',
117
- 'title' => 'Create',
118
- 'schema' => {
119
- 'properties' => {
120
- 'date_field' => {
121
- '$ref' => '#/definitions/resource/definitions/date_field'},
122
- 'string_field' => {
123
- '$ref' => '#/definitions/resource/definitions/string_field'},
124
- 'boolean_field' => {
125
- '$ref' => '#/definitions/resource/definitions/boolean_field'},
126
- 'uuid_field' => {
127
- '$ref' => '#/definitions/resource/definitions/uuid_field'},
128
- 'email_field' => {
129
- '$ref' => '#/definitions/resource/definitions/email_field'}}}},
130
-
131
- {'description' => 'Submit a sample resource as form data',
132
- 'encType' => 'application/x-www-form-urlencoded',
133
- 'href' => '/resource',
134
- 'method' => 'POST',
135
- 'rel' => 'submit',
136
- 'title' => 'Submit',
137
- 'schema' => {
138
- 'properties' => {
139
- 'date_field' => {
140
- '$ref' => '#/definitions/resource/definitions/date_field'},
141
- 'string_field' => {
142
- '$ref' => '#/definitions/resource/definitions/string_field'},
143
- 'boolean_field' => {
144
- '$ref' => '#/definitions/resource/definitions/boolean_field'},
145
- 'uuid_field' => {
146
- '$ref' => '#/definitions/resource/definitions/uuid_field'},
147
- 'email_field' => {
148
- '$ref' => '#/definitions/resource/definitions/email_field'}}}},
149
-
150
- {'description' => 'Update a sample resource',
151
- 'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fuuid_field)}',
152
- 'method' => 'PATCH',
153
- 'rel' => 'update',
154
- 'title' => 'Update',
155
- 'schema' => {
156
- 'properties' => {
157
- 'date_field' => {
158
- '$ref' => '#/definitions/resource/definitions/date_field'},
159
- 'string_field' => {
160
- '$ref' => '#/definitions/resource/definitions/string_field'},
161
- 'boolean_field' => {
162
- '$ref' => '#/definitions/resource/definitions/boolean_field'},
163
- 'uuid_field' => {
164
- '$ref' => '#/definitions/resource/definitions/uuid_field'},
165
- 'email_field' => {
166
- '$ref' => '#/definitions/resource/definitions/email_field'}}}},
167
-
168
- {'description' => 'Delete an existing sample resource at specific time',
169
- 'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fdate_field)}',
170
- 'method' => 'DELETE',
171
- 'rel' => 'destroy',
172
- 'title' => 'Delete'}
173
- ]
174
- },
175
-
176
- 'another-resource' => {
177
- 'description' => 'Another sample resource to use in tests.',
178
- 'id' => 'schema/another-resource',
179
- '$schema' => 'http://json-schema.org/draft-04/hyper-schema',
180
- 'title' => 'Another sample resource title',
181
- 'type' => ['object'],
182
-
183
- 'definitions' => {},
184
-
185
- 'properties' => {},
186
-
187
- 'links' => [
188
- {'description' => 'Show all sample resources',
189
- 'href' => '/another-resource',
190
- 'method' => 'GET',
191
- 'rel' => 'instances',
192
- 'title' => 'List'}
193
- ]
194
- },
195
-
196
- 'underscored_resource' => {
197
- 'description' => 'Underscores the importance of supporting underscored resources',
198
- 'id' => 'schema/underscored_resource',
199
- '$schema' => 'http://json-schema.org/draft-04/hyper-schema',
200
- 'title' => 'Another underscored resource to use in tests',
201
- 'type' => ['object'],
202
-
203
- 'definitions' => {},
204
-
205
- 'properties' => {},
206
-
207
- 'links' => [
208
- {'description' => 'Show all underscored resources',
209
- 'href' => '/underscored_resource',
210
- 'method' => 'GET',
211
- 'rel' => 'instances',
212
- 'title' => 'List'}
213
- ]
214
- },
215
- },
216
- 'properties' => {
217
- 'resource' => { '$ref' => '#/definitions/resource' },
218
- 'another-resource' => { '$ref' => '#/definitions/another-resource' },
219
- 'underscored_resource' => { '$ref' => '#/definitions/underscored_resource' }
220
- }
221
- }
@@ -1,444 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'helper'
3
-
4
- class LinkTest < MiniTest::Unit::TestCase
5
- include ExconHelper
6
-
7
- # Link.run invokes a request against the service identified by the URL. The
8
- # path is left unchanged when parameters aren't required and the username
9
- # and password from the URL are passed using HTTP basic auth.
10
- def test_run_without_parameters_and_with_empty_response
11
- Excon.stub(method: :get) do |request|
12
- assert_equal('Basic dXNlcm5hbWU6c2VjcmV0',
13
- request[:headers]['Authorization'])
14
- assert_equal('example.com', request[:host])
15
- assert_equal(443, request[:port])
16
- assert_equal('/resource', request[:path])
17
- Excon.stubs.pop
18
- {status: 200, body: ''}
19
- end
20
-
21
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
22
- link = Heroics::Link.new('https://username:secret@example.com',
23
- schema.resource('resource').link('list'))
24
- assert_equal(nil, link.run)
25
- end
26
-
27
- # Link.run injects parameters into the path in the order they were received.
28
- def test_run_with_parameters_and_empty_response
29
- Excon.stub(method: :get) do |request|
30
- assert_equal('/resource/44724831-bf66-4bc2-865f-e2c4c2b14c78',
31
- request[:path])
32
- Excon.stubs.pop
33
- {status: 200, body: ''}
34
- end
35
-
36
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
37
- link = Heroics::Link.new('https://example.com',
38
- schema.resource('resource').link('info'))
39
- assert_equal(nil, link.run('44724831-bf66-4bc2-865f-e2c4c2b14c78'))
40
- end
41
-
42
- # Link.run URL-escapes special characters in parameters.
43
- def test_run_with_parameters_needing_escaping
44
- Excon.stub(method: :get) do |request|
45
- assert_equal('/resource/foo%23bar', request[:path])
46
- Excon.stubs.pop
47
- {status: 200, body: ''}
48
- end
49
-
50
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
51
- link = Heroics::Link.new('https://example.com',
52
- schema.resource('resource').link('info'))
53
- assert_equal(nil, link.run('foo#bar'))
54
- end
55
-
56
- # Link.run converts Time parameters to UTC before sending them to the
57
- # server.
58
- def test_run_converts_time_parameters_to_utc
59
- Excon.stub(method: :delete) do |request|
60
- assert_equal("/resource/2013-01-01T08:00:00Z", request[:path])
61
- Excon.stubs.pop
62
- {status: 200, body: ''}
63
- end
64
-
65
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
66
- link = Heroics::Link.new('https://example.com',
67
- schema.resource('resource').link('delete'))
68
- assert_equal(nil, link.run(Time.parse('2013-01-01 00:00:00-0800')))
69
- end
70
-
71
- # Link.run optionally takes an extra parameter to send in the request body.
72
- # It automatically converts the specified object to JSON and includes a
73
- # Content-Type header in the request.
74
- def test_run_without_parameters_and_with_request_body
75
- body = {'Hello' => 'world!'}
76
- Excon.stub(method: :post) do |request|
77
- assert_equal('application/json', request[:headers]['Content-Type'])
78
- assert_equal(body, MultiJson.load(request[:body]))
79
- Excon.stubs.pop
80
- {status: 200, body: ''}
81
- end
82
-
83
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
84
- link = Heroics::Link.new('https://example.com',
85
- schema.resource('resource').link('create'))
86
- assert_equal(nil, link.run(body))
87
- end
88
-
89
- # Link.run optionally takes an extra parameter to send in the request body.
90
- # It automatically converts the specified object to the specified encoding
91
- # type and includes a Content-Type header in the request
92
- def test_run_without_parameters_and_with_non_json_request_body
93
- body = {'Hello' => 'world!'}
94
- Excon.stub(method: :post) do |request|
95
- assert_equal('application/x-www-form-urlencoded', request[:headers]['Content-Type'])
96
- assert_equal('Hello=world%21', request[:body])
97
- Excon.stubs.pop
98
- {status: 200, body: ''}
99
- end
100
-
101
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
102
- link = Heroics::Link.new('https://example.com',
103
- schema.resource('resource').link('submit'))
104
- assert_equal(nil, link.run(body))
105
- end
106
-
107
-
108
- # Link.run passes custom headers to the server when they've been provided.
109
- def test_run_with_custom_request_headers
110
- Excon.stub(method: :get) do |request|
111
- assert_equal('application/vnd.heroku+json; version=3',
112
- request[:headers]['Accept'])
113
- Excon.stubs.pop
114
- {status: 200}
115
- end
116
-
117
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
118
- link = Heroics::Link.new(
119
- 'https://example.com', schema.resource('resource').link('list'),
120
- {default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}})
121
- assert_equal(nil, link.run())
122
- end
123
-
124
- # Link.run passes custom headers to the server when they've been provided.
125
- # It merges in the Content-Type when a body is included in the request.
126
- def test_run_with_custom_request_headers_and_with_request_body
127
- body = {'Hello' => 'world!'}
128
- Excon.stub(method: :post) do |request|
129
- assert_equal('application/json', request[:headers]['Content-Type'])
130
- assert_equal('application/vnd.heroku+json; version=3',
131
- request[:headers]['Accept'])
132
- assert_equal(body, MultiJson.load(request[:body]))
133
- Excon.stubs.pop
134
- {status: 200}
135
- end
136
-
137
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
138
- link = Heroics::Link.new(
139
- 'https://example.com', schema.resource('resource').link('create'),
140
- default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'})
141
- assert_equal(nil, link.run(body))
142
- end
143
-
144
- # Link.run doesn't mutate the default headers.
145
- def test_run_never_overwrites_default_headers
146
- body = {'Hello' => 'world!'}
147
- Excon.stub(method: :post) do |request|
148
- assert_equal('application/json', request[:headers]['Content-Type'])
149
- assert_equal('application/vnd.heroku+json; version=3',
150
- request[:headers]['Accept'])
151
- assert_equal(body, MultiJson.load(request[:body]))
152
- Excon.stubs.pop
153
- {status: 200}
154
- end
155
-
156
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
157
- link = Heroics::Link.new(
158
- 'https://example.com', schema.resource('resource').link('create'),
159
- {default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}})
160
- assert_equal(nil, link.run(body))
161
-
162
- # The second time we use the link, without providing a request body, the
163
- # Content-Type set during the first run is not present, as expected.
164
- Excon.stub(method: :post) do |request|
165
- assert_equal(nil, request[:headers]['Content-Type'])
166
- assert_equal('application/vnd.heroku+json; version=3',
167
- request[:headers]['Accept'])
168
- Excon.stubs.pop
169
- {status: 200}
170
- end
171
- assert_equal(nil, link.run)
172
- end
173
-
174
- # Link.run returns text responses sent by the server without processing them
175
- # in any way.
176
- def test_run_with_text_response
177
- Excon.stub(method: :get) do |request|
178
- assert_equal('/resource', request[:path])
179
- Excon.stubs.pop
180
- {status: 200, headers: {'Content-Type' => 'application/text'},
181
- body: "Hello, world!\r\n"}
182
- end
183
-
184
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
185
- link = Heroics::Link.new('https://example.com',
186
- schema.resource('resource').link('list'))
187
- assert_equal("Hello, world!\r\n", link.run)
188
- end
189
-
190
- # Link.run automatically decodes JSON responses sent by the server into Ruby
191
- # objects.
192
- def test_run_with_json_response
193
- body = {'Hello' => 'World!'}
194
- Excon.stub(method: :post) do |request|
195
- assert_equal('/resource', request[:path])
196
- Excon.stubs.pop
197
- {status: 201, headers: {'Content-Type' => 'application/json'},
198
- body: MultiJson.dump(body)}
199
- end
200
-
201
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
202
- link = Heroics::Link.new('https://example.com',
203
- schema.resource('resource').link('create'))
204
- assert_equal(body, link.run)
205
- end
206
-
207
- # Link.run automatically decodes JSON responses with a complex Content-Type
208
- # header sent by the server into Ruby objects.
209
- def test_run_with_json_response_and_complex_content_type
210
- body = {'Hello' => 'World!'}
211
- Excon.stub(method: :get) do |request|
212
- assert_equal('/resource', request[:path])
213
- Excon.stubs.pop
214
- {status: 200,
215
- headers: {'Content-Type' => 'application/vnd.api+json;charset=utf-8'},
216
- body: MultiJson.dump(body)}
217
- end
218
-
219
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
220
- link = Heroics::Link.new('https://example.com',
221
- schema.resource('resource').link('list'))
222
- assert_equal(body, link.run)
223
- end
224
-
225
- # Link.run considers HTTP 202 Accepted responses as successful.
226
- def test_run_with_accepted_request
227
- body = {'Hello' => 'World!'}
228
- Excon.stub(method: :post) do |request|
229
- assert_equal('/resource', request[:path])
230
- Excon.stubs.pop
231
- {status: 202, headers: {'Content-Type' => 'application/json'},
232
- body: MultiJson.dump(body)}
233
- end
234
-
235
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
236
- link = Heroics::Link.new('https://example.com',
237
- schema.resource('resource').link('create'))
238
- assert_equal(body, link.run)
239
- end
240
-
241
- # Link.run considers HTTP 204 No Content responses as successful.
242
- def test_run_with_no_content_response
243
- Excon.stub(method: :delete) do |request|
244
- assert_equal("/resource/2013-01-01T08:00:00Z", request[:path])
245
- Excon.stubs.pop
246
- {status: 204, body: ''}
247
- end
248
-
249
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
250
- link = Heroics::Link.new('https://example.com',
251
- schema.resource('resource').link('delete'))
252
- assert_equal(nil, link.run(Time.parse('2013-01-01 00:00:00-0800')))
253
- end
254
-
255
- # Link.run raises an Excon error if anything other than a 200 or 201 HTTP
256
- # status code was returned by the server.
257
- def test_run_with_failed_request
258
- Excon.stub(method: :get) do |request|
259
- assert_equal('/resource', request[:path])
260
- Excon.stubs.pop
261
- {status: 400}
262
- end
263
-
264
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
265
- link = Heroics::Link.new('https://example.com',
266
- schema.resource('resource').link('list'))
267
- assert_raises Excon::Errors::BadRequest do
268
- link.run
269
- end
270
- end
271
-
272
- # Link.run raises an ArgumentError if too few parameters are provided.
273
- def test_run_with_missing_parameters
274
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
275
- link = Heroics::Link.new('https://example.com',
276
- schema.resource('resource').link('info'))
277
- error = assert_raises ArgumentError do
278
- link.run
279
- end
280
- assert_equal('wrong number of arguments (0 for 1)', error.message)
281
- end
282
-
283
- # Link.run raises an ArgumentError if too many parameters are provided.
284
- def test_run_with_too_many_parameters
285
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
286
- link = Heroics::Link.new('https://example.com',
287
- schema.resource('resource').link('info'))
288
- error = assert_raises ArgumentError do
289
- link.run('too', 'many', 'parameters')
290
- end
291
- assert_equal('wrong number of arguments (3 for 1)', error.message)
292
- end
293
-
294
- # Link.run passes ETags from the cache to the server with GET requests.
295
- def test_run_passes_cached_etags_in_get_requests
296
- Excon.stub(method: :get) do |request|
297
- assert_equal('etag-contents', request[:headers]['If-None-Match'])
298
- Excon.stubs.pop
299
- {status: 200}
300
- end
301
-
302
- headers = {}
303
- cache = Moneta.new(:Memory)
304
- cache["etag:/resource:#{headers.hash}"] = 'etag-contents'
305
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
306
- link = Heroics::Link.new('https://example.com',
307
- schema.resource('resource').link('list'),
308
- cache: cache)
309
- link.run
310
- end
311
-
312
- # Link.run will not pas ETags from the cache for non-GET requests.
313
- def test_run_ignores_etags_for_non_get_requests
314
- Excon.stub(method: :post) do |request|
315
- assert_equal(nil, request[:headers]['If-None-Match'])
316
- Excon.stubs.pop
317
- {status: 201}
318
- end
319
-
320
- cache = Moneta.new(:Memory)
321
- cache['etag:/resource:0'] = 'etag-contents'
322
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
323
- link = Heroics::Link.new('https://example.com',
324
- schema.resource('resource').link('create'),
325
- cache: cache)
326
- link.run({'Hello' => 'World'})
327
- end
328
-
329
- # Link.run returns JSON content loaded from the cache when a GET request
330
- # with an ETag yields a 304 Not Modified response.
331
- def test_run_returns_cached_json_content_for_not_modified_response
332
- body = {'Hello' => 'World!'}
333
- Excon.stub(method: :get) do |request|
334
- assert_equal('etag-contents', request[:headers]['If-None-Match'])
335
- Excon.stubs.pop
336
- {status: 304, headers: {'Content-Type' => 'application/json'}}
337
- end
338
-
339
- headers = {}
340
- cache = Moneta.new(:Memory)
341
- cache["etag:/resource:#{headers.hash}"] = 'etag-contents'
342
- cache["data:/resource:#{headers.hash}"] = MultiJson.dump(body)
343
- cache["status:/resource:#{headers.hash}"] = 200
344
- cache["headers:/resource:#{headers.hash}"] = {'Content-Type' => 'application/json'}
345
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
346
- link = Heroics::Link.new('https://example.com',
347
- schema.resource('resource').link('list'),
348
- cache: cache)
349
- assert_equal(body, link.run)
350
- end
351
-
352
- # Link.run caches JSON content received from the server when an ETag is
353
- # included in the response.
354
- def test_run_caches_json_body_when_an_etag_is_received
355
- body = {'Hello' => 'World!'}
356
- Excon.stub(method: :get) do |request|
357
- Excon.stubs.pop
358
- {status: 200, headers: {'Content-Type' => 'application/json',
359
- 'ETag' => 'etag-contents'},
360
- body: MultiJson.dump(body)}
361
- end
362
-
363
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
364
- link = Heroics::Link.new('https://example.com',
365
- schema.resource('resource').link('list'),
366
- cache: Moneta.new(:Memory))
367
- assert_equal(body, link.run)
368
-
369
- Excon.stub(method: :get) do |request|
370
- assert_equal('etag-contents', request[:headers]['If-None-Match'])
371
- Excon.stubs.pop
372
- {status: 304, headers: {'Content-Type' => 'application/json'}}
373
- end
374
- assert_equal(body, link.run)
375
- end
376
-
377
- # Link.run returns an enumerator when a 206 Partial Content status code and
378
- # Content-Range header is included in a server response. The enumerator
379
- # makes requests to fetch missing pages as its iterated.
380
- def test_run_with_range_response
381
- Excon.stub(method: :get) do |request|
382
- Excon.stubs.shift
383
- {status: 206, headers: {'Content-Type' => 'application/json',
384
- 'Content-Range' => 'id 1..2; max=200'},
385
- body: MultiJson.dump([2])}
386
- end
387
-
388
- Excon.stub(method: :get) do |request|
389
- Excon.stubs.shift
390
- {status: 206, headers: {'Content-Type' => 'application/json',
391
- 'Content-Range' => 'id 0..1; max=200',
392
- 'Next-Range' => '201'},
393
- body: MultiJson.dump([1])}
394
- end
395
-
396
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
397
- link = Heroics::Link.new('https://example.com',
398
- schema.resource('resource').link('list'))
399
- assert_equal([1, 2], link.run.to_a)
400
- end
401
-
402
- # Ensure that caching does not prevent pagination from working correctly.
403
- # See https://github.com/heroku/platform-api/issues/16
404
- def test_run_with_range_response_and_cache
405
- Excon.stub(method: :get) do |request|
406
- Excon.stubs.shift
407
- {status: 206, headers: {'Content-Type' => 'application/json',
408
- 'Content-Range' => 'id 1..2; max=200',
409
- 'ETag' => 'second-page'},
410
- body: MultiJson.dump([2])}
411
- end
412
-
413
- Excon.stub(method: :get) do |request|
414
- Excon.stubs.shift
415
- {status: 206, headers: {'Content-Type' => 'application/json',
416
- 'Content-Range' => 'id 0..1; max=200',
417
- 'Next-Range' => '201',
418
- 'ETag' => 'first-page'},
419
- body: MultiJson.dump([1])}
420
- end
421
-
422
- schema = Heroics::Schema.new(SAMPLE_SCHEMA)
423
- link = Heroics::Link.new('https://example.com',
424
- schema.resource('resource').link('list'),
425
- cache: Moneta.new(:Memory))
426
- assert_equal([1, 2], link.run.to_a)
427
-
428
- Excon.stub(method: :get) do |request|
429
- assert_equal('second-page', request[:headers]['If-None-Match'])
430
- assert_equal('201', request[:headers]['Range'])
431
- Excon.stubs.shift
432
- {status: 304, headers: {'Content-Type' => 'application/json'}}
433
- end
434
-
435
- Excon.stub(method: :get) do |request|
436
- assert_equal('first-page', request[:headers]['If-None-Match'])
437
- assert_equal(nil, request[:headers]['Range'])
438
- Excon.stubs.shift
439
- {status: 304, headers: {'Content-Type' => 'application/json'}}
440
- end
441
-
442
- assert_equal([1, 2], link.run.to_a)
443
- end
444
- end