gocardless_pro 2.27.0 → 2.30.0

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +20 -1
  3. data/lib/gocardless_pro/api_service.rb +4 -0
  4. data/lib/gocardless_pro/client.rb +11 -1
  5. data/lib/gocardless_pro/error/authentication_error.rb +4 -0
  6. data/lib/gocardless_pro/error/permission_error.rb +4 -0
  7. data/lib/gocardless_pro/error/rate_limit_error.rb +4 -0
  8. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +12 -1
  9. data/lib/gocardless_pro/resources/bank_authorisation.rb +3 -9
  10. data/lib/gocardless_pro/resources/billing_request.rb +31 -7
  11. data/lib/gocardless_pro/resources/billing_request_flow.rb +14 -0
  12. data/lib/gocardless_pro/resources/billing_request_template.rb +68 -0
  13. data/lib/gocardless_pro/resources/block.rb +76 -0
  14. data/lib/gocardless_pro/resources/event.rb +20 -0
  15. data/lib/gocardless_pro/resources/institution.rb +7 -1
  16. data/lib/gocardless_pro/resources/payer_authorisation.rb +9 -0
  17. data/lib/gocardless_pro/resources/redirect_flow.rb +6 -0
  18. data/lib/gocardless_pro/services/bank_authorisations_service.rb +0 -2
  19. data/lib/gocardless_pro/services/billing_request_flows_service.rb +23 -0
  20. data/lib/gocardless_pro/services/billing_request_templates_service.rb +131 -0
  21. data/lib/gocardless_pro/services/billing_requests_service.rb +89 -24
  22. data/lib/gocardless_pro/services/blocks_service.rb +223 -0
  23. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +1 -5
  24. data/lib/gocardless_pro/services/creditors_service.rb +1 -3
  25. data/lib/gocardless_pro/services/currency_exchange_rates_service.rb +1 -1
  26. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +1 -5
  27. data/lib/gocardless_pro/services/customers_service.rb +1 -3
  28. data/lib/gocardless_pro/services/events_service.rb +1 -1
  29. data/lib/gocardless_pro/services/instalment_schedules_service.rb +1 -7
  30. data/lib/gocardless_pro/services/institutions_service.rb +2 -2
  31. data/lib/gocardless_pro/services/mandate_import_entries_service.rb +1 -1
  32. data/lib/gocardless_pro/services/mandate_imports_service.rb +0 -6
  33. data/lib/gocardless_pro/services/mandates_service.rb +1 -7
  34. data/lib/gocardless_pro/services/payer_authorisations_service.rb +0 -6
  35. data/lib/gocardless_pro/services/payments_service.rb +1 -7
  36. data/lib/gocardless_pro/services/payout_items_service.rb +1 -1
  37. data/lib/gocardless_pro/services/payouts_service.rb +1 -1
  38. data/lib/gocardless_pro/services/redirect_flows_service.rb +0 -4
  39. data/lib/gocardless_pro/services/refunds_service.rb +1 -3
  40. data/lib/gocardless_pro/services/scenario_simulators_service.rb +28 -6
  41. data/lib/gocardless_pro/services/subscriptions_service.rb +3 -11
  42. data/lib/gocardless_pro/services/tax_rates_service.rb +1 -1
  43. data/lib/gocardless_pro/services/webhooks_service.rb +1 -3
  44. data/lib/gocardless_pro/version.rb +1 -1
  45. data/lib/gocardless_pro.rb +9 -0
  46. data/spec/api_service_spec.rb +12 -1
  47. data/spec/middlewares/raise_gocardless_errors_spec.rb +30 -0
  48. data/spec/resources/bank_authorisation_spec.rb +7 -7
  49. data/spec/resources/billing_request_flow_spec.rb +104 -0
  50. data/spec/resources/billing_request_spec.rb +183 -29
  51. data/spec/resources/billing_request_template_spec.rb +502 -0
  52. data/spec/resources/block_spec.rb +577 -0
  53. data/spec/resources/creditor_bank_account_spec.rb +2 -0
  54. data/spec/resources/customer_bank_account_spec.rb +2 -0
  55. data/spec/resources/customer_notification_spec.rb +2 -0
  56. data/spec/resources/customer_spec.rb +2 -0
  57. data/spec/resources/instalment_schedule_spec.rb +2 -0
  58. data/spec/resources/institution_spec.rb +5 -0
  59. data/spec/resources/mandate_import_spec.rb +4 -0
  60. data/spec/resources/mandate_spec.rb +4 -0
  61. data/spec/resources/payer_authorisation_spec.rb +4 -0
  62. data/spec/resources/payment_spec.rb +4 -0
  63. data/spec/resources/redirect_flow_spec.rb +11 -0
  64. data/spec/resources/scenario_simulator_spec.rb +2 -0
  65. data/spec/resources/subscription_spec.rb +6 -0
  66. data/spec/resources/webhook_spec.rb +2 -0
  67. data/spec/services/bank_authorisations_service_spec.rb +7 -20
  68. data/spec/services/billing_request_flows_service_spec.rb +115 -0
  69. data/spec/services/billing_request_templates_service_spec.rb +789 -0
  70. data/spec/services/billing_requests_service_spec.rb +210 -47
  71. data/spec/services/blocks_service_spec.rb +840 -0
  72. data/spec/services/creditor_bank_accounts_service_spec.rb +2 -13
  73. data/spec/services/creditors_service_spec.rb +0 -13
  74. data/spec/services/customer_bank_accounts_service_spec.rb +2 -13
  75. data/spec/services/customer_notifications_service_spec.rb +2 -0
  76. data/spec/services/customers_service_spec.rb +2 -13
  77. data/spec/services/instalment_schedules_service_spec.rb +2 -26
  78. data/spec/services/institutions_service_spec.rb +9 -0
  79. data/spec/services/mandate_imports_service_spec.rb +4 -13
  80. data/spec/services/mandates_service_spec.rb +4 -13
  81. data/spec/services/payer_authorisations_service_spec.rb +4 -13
  82. data/spec/services/payments_service_spec.rb +4 -13
  83. data/spec/services/redirect_flows_service_spec.rb +11 -13
  84. data/spec/services/refunds_service_spec.rb +0 -13
  85. data/spec/services/scenario_simulators_service_spec.rb +2 -0
  86. data/spec/services/subscriptions_service_spec.rb +6 -13
  87. data/spec/services/webhooks_service_spec.rb +2 -0
  88. metadata +18 -3
@@ -0,0 +1,840 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::BlocksService do
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
9
+
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
12
+ describe '#create' do
13
+ subject(:post_create_response) { client.blocks.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'active' => 'active-input',
19
+ 'block_type' => 'block_type-input',
20
+ 'created_at' => 'created_at-input',
21
+ 'id' => 'id-input',
22
+ 'reason_description' => 'reason_description-input',
23
+ 'reason_type' => 'reason_type-input',
24
+ 'resource_reference' => 'resource_reference-input',
25
+ 'updated_at' => 'updated_at-input',
26
+ }
27
+ end
28
+
29
+ before do
30
+ stub_request(:post, %r{.*api.gocardless.com/blocks}).
31
+ with(
32
+ body: {
33
+ 'blocks' => {
34
+
35
+ 'active' => 'active-input',
36
+ 'block_type' => 'block_type-input',
37
+ 'created_at' => 'created_at-input',
38
+ 'id' => 'id-input',
39
+ 'reason_description' => 'reason_description-input',
40
+ 'reason_type' => 'reason_type-input',
41
+ 'resource_reference' => 'resource_reference-input',
42
+ 'updated_at' => 'updated_at-input',
43
+ },
44
+ }
45
+ ).
46
+ to_return(
47
+ body: {
48
+ 'blocks' =>
49
+
50
+ {
51
+
52
+ 'active' => 'active-input',
53
+ 'block_type' => 'block_type-input',
54
+ 'created_at' => 'created_at-input',
55
+ 'id' => 'id-input',
56
+ 'reason_description' => 'reason_description-input',
57
+ 'reason_type' => 'reason_type-input',
58
+ 'resource_reference' => 'resource_reference-input',
59
+ 'updated_at' => 'updated_at-input',
60
+ },
61
+
62
+ }.to_json,
63
+ headers: response_headers
64
+ )
65
+ end
66
+
67
+ it 'creates and returns the resource' do
68
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::Block)
69
+ end
70
+
71
+ describe 'retry behaviour' do
72
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
73
+
74
+ it 'retries timeouts' do
75
+ stub = stub_request(:post, %r{.*api.gocardless.com/blocks}).
76
+ to_timeout.then.to_return(status: 200, headers: response_headers)
77
+
78
+ post_create_response
79
+ expect(stub).to have_been_requested.twice
80
+ end
81
+
82
+ it 'retries 5XX errors' do
83
+ stub = stub_request(:post, %r{.*api.gocardless.com/blocks}).
84
+ to_return(status: 502,
85
+ headers: { 'Content-Type' => 'text/html' },
86
+ body: '<html><body>Response from Cloudflare</body></html>').
87
+ then.to_return(status: 200, headers: response_headers)
88
+
89
+ post_create_response
90
+ expect(stub).to have_been_requested.twice
91
+ end
92
+ end
93
+ end
94
+
95
+ context 'with a request that returns a validation error' do
96
+ let(:new_resource) { {} }
97
+
98
+ before do
99
+ stub_request(:post, %r{.*api.gocardless.com/blocks}).to_return(
100
+ body: {
101
+ error: {
102
+ type: 'validation_failed',
103
+ code: 422,
104
+ errors: [
105
+ { message: 'test error message', field: 'test_field' },
106
+ ],
107
+ },
108
+ }.to_json,
109
+ headers: response_headers,
110
+ status: 422
111
+ )
112
+ end
113
+
114
+ it 'throws the correct error' do
115
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
116
+ end
117
+ end
118
+
119
+ context 'with a request that returns an idempotent creation conflict error' do
120
+ let(:id) { 'ID123' }
121
+
122
+ let(:new_resource) do
123
+ {
124
+
125
+ 'active' => 'active-input',
126
+ 'block_type' => 'block_type-input',
127
+ 'created_at' => 'created_at-input',
128
+ 'id' => 'id-input',
129
+ 'reason_description' => 'reason_description-input',
130
+ 'reason_type' => 'reason_type-input',
131
+ 'resource_reference' => 'resource_reference-input',
132
+ 'updated_at' => 'updated_at-input',
133
+ }
134
+ end
135
+
136
+ let!(:post_stub) do
137
+ stub_request(:post, %r{.*api.gocardless.com/blocks}).to_return(
138
+ body: {
139
+ error: {
140
+ type: 'invalid_state',
141
+ code: 409,
142
+ errors: [
143
+ {
144
+ message: 'A resource has already been created with this idempotency key',
145
+ reason: 'idempotent_creation_conflict',
146
+ links: {
147
+ conflicting_resource_id: id,
148
+ },
149
+ },
150
+ ],
151
+ },
152
+ }.to_json,
153
+ headers: response_headers,
154
+ status: 409
155
+ )
156
+ end
157
+
158
+ let!(:get_stub) do
159
+ stub_url = "/blocks/#{id}"
160
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
161
+ to_return(
162
+ body: {
163
+ 'blocks' => {
164
+
165
+ 'active' => 'active-input',
166
+ 'block_type' => 'block_type-input',
167
+ 'created_at' => 'created_at-input',
168
+ 'id' => 'id-input',
169
+ 'reason_description' => 'reason_description-input',
170
+ 'reason_type' => 'reason_type-input',
171
+ 'resource_reference' => 'resource_reference-input',
172
+ 'updated_at' => 'updated_at-input',
173
+ },
174
+ }.to_json,
175
+ headers: response_headers
176
+ )
177
+ end
178
+
179
+ context 'with default behaviour' do
180
+ it 'fetches the already-created resource' do
181
+ post_create_response
182
+ expect(post_stub).to have_been_requested
183
+ expect(get_stub).to have_been_requested
184
+ end
185
+ end
186
+
187
+ context 'with on_idempotency_conflict: :raise' do
188
+ let(:client) do
189
+ GoCardlessPro::Client.new(
190
+ access_token: 'SECRET_TOKEN',
191
+ on_idempotency_conflict: :raise
192
+ )
193
+ end
194
+
195
+ it 'raises an IdempotencyConflict error' do
196
+ expect { post_create_response }.
197
+ to raise_error(GoCardlessPro::IdempotencyConflict)
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ describe '#get' do
204
+ let(:id) { 'ID123' }
205
+
206
+ subject(:get_response) { client.blocks.get(id) }
207
+
208
+ context 'passing in a custom header' do
209
+ let!(:stub) do
210
+ stub_url = '/blocks/:identity'.gsub(':identity', id)
211
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
212
+ with(headers: { 'Foo' => 'Bar' }).
213
+ to_return(
214
+ body: {
215
+ 'blocks' => {
216
+
217
+ 'active' => 'active-input',
218
+ 'block_type' => 'block_type-input',
219
+ 'created_at' => 'created_at-input',
220
+ 'id' => 'id-input',
221
+ 'reason_description' => 'reason_description-input',
222
+ 'reason_type' => 'reason_type-input',
223
+ 'resource_reference' => 'resource_reference-input',
224
+ 'updated_at' => 'updated_at-input',
225
+ },
226
+ }.to_json,
227
+ headers: response_headers
228
+ )
229
+ end
230
+
231
+ subject(:get_response) do
232
+ client.blocks.get(id, headers: {
233
+ 'Foo' => 'Bar',
234
+ })
235
+ end
236
+
237
+ it 'includes the header' do
238
+ get_response
239
+ expect(stub).to have_been_requested
240
+ end
241
+ end
242
+
243
+ context 'when there is a block to return' do
244
+ before do
245
+ stub_url = '/blocks/:identity'.gsub(':identity', id)
246
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
247
+ body: {
248
+ 'blocks' => {
249
+
250
+ 'active' => 'active-input',
251
+ 'block_type' => 'block_type-input',
252
+ 'created_at' => 'created_at-input',
253
+ 'id' => 'id-input',
254
+ 'reason_description' => 'reason_description-input',
255
+ 'reason_type' => 'reason_type-input',
256
+ 'resource_reference' => 'resource_reference-input',
257
+ 'updated_at' => 'updated_at-input',
258
+ },
259
+ }.to_json,
260
+ headers: response_headers
261
+ )
262
+ end
263
+
264
+ it 'wraps the response in a resource' do
265
+ expect(get_response).to be_a(GoCardlessPro::Resources::Block)
266
+ end
267
+ end
268
+
269
+ context 'when nothing is returned' do
270
+ before do
271
+ stub_url = '/blocks/:identity'.gsub(':identity', id)
272
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
273
+ body: '',
274
+ headers: response_headers
275
+ )
276
+ end
277
+
278
+ it 'returns nil' do
279
+ expect(get_response).to be_nil
280
+ end
281
+ end
282
+
283
+ context "when an ID is specified which can't be included in a valid URI" do
284
+ let(:id) { '`' }
285
+
286
+ it "doesn't raise an error" do
287
+ expect { get_response }.to_not raise_error(/bad URI/)
288
+ end
289
+ end
290
+
291
+ describe 'retry behaviour' do
292
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
293
+
294
+ it 'retries timeouts' do
295
+ stub_url = '/blocks/:identity'.gsub(':identity', id)
296
+
297
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
298
+ to_timeout.then.to_return(status: 200, headers: response_headers)
299
+
300
+ get_response
301
+ expect(stub).to have_been_requested.twice
302
+ end
303
+
304
+ it 'retries 5XX errors, other than 500s' do
305
+ stub_url = '/blocks/:identity'.gsub(':identity', id)
306
+
307
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
308
+ to_return(status: 502,
309
+ headers: { 'Content-Type' => 'text/html' },
310
+ body: '<html><body>Response from Cloudflare</body></html>').
311
+ then.to_return(status: 200, headers: response_headers)
312
+
313
+ get_response
314
+ expect(stub).to have_been_requested.twice
315
+ end
316
+
317
+ it 'retries 500 errors returned by the API' do
318
+ stub_url = '/blocks/:identity'.gsub(':identity', id)
319
+
320
+ gocardless_error = {
321
+ 'error' => {
322
+ 'message' => 'Internal server error',
323
+ 'documentation_url' => 'https://developer.gocardless.com/#gocardless',
324
+ 'errors' => [{
325
+ 'message' => 'Internal server error',
326
+ 'reason' => 'internal_server_error',
327
+ }],
328
+ 'type' => 'gocardless',
329
+ 'code' => 500,
330
+ 'request_id' => 'dummy_request_id',
331
+ 'id' => 'dummy_exception_id',
332
+ },
333
+ }
334
+
335
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
336
+ to_return(status: 500,
337
+ headers: response_headers,
338
+ body: gocardless_error.to_json).
339
+ then.to_return(status: 200, headers: response_headers)
340
+
341
+ get_response
342
+ expect(stub).to have_been_requested.twice
343
+ end
344
+ end
345
+ end
346
+
347
+ describe '#list' do
348
+ describe 'with no filters' do
349
+ subject(:get_list_response) { client.blocks.list }
350
+
351
+ let(:body) do
352
+ {
353
+ 'blocks' => [{
354
+
355
+ 'active' => 'active-input',
356
+ 'block_type' => 'block_type-input',
357
+ 'created_at' => 'created_at-input',
358
+ 'id' => 'id-input',
359
+ 'reason_description' => 'reason_description-input',
360
+ 'reason_type' => 'reason_type-input',
361
+ 'resource_reference' => 'resource_reference-input',
362
+ 'updated_at' => 'updated_at-input',
363
+ }],
364
+ meta: {
365
+ cursors: {
366
+ before: nil,
367
+ after: 'ABC123',
368
+ },
369
+ },
370
+ }.to_json
371
+ end
372
+
373
+ before do
374
+ stub_request(:get, %r{.*api.gocardless.com/blocks}).to_return(
375
+ body: body,
376
+ headers: response_headers
377
+ )
378
+ end
379
+
380
+ it 'wraps each item in the resource class' do
381
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Block)
382
+
383
+ expect(get_list_response.records.first.active).to eq('active-input')
384
+
385
+ expect(get_list_response.records.first.block_type).to eq('block_type-input')
386
+
387
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
388
+
389
+ expect(get_list_response.records.first.id).to eq('id-input')
390
+
391
+ expect(get_list_response.records.first.reason_description).to eq('reason_description-input')
392
+
393
+ expect(get_list_response.records.first.reason_type).to eq('reason_type-input')
394
+
395
+ expect(get_list_response.records.first.resource_reference).to eq('resource_reference-input')
396
+
397
+ expect(get_list_response.records.first.updated_at).to eq('updated_at-input')
398
+ end
399
+
400
+ it 'exposes the cursors for before and after' do
401
+ expect(get_list_response.before).to eq(nil)
402
+ expect(get_list_response.after).to eq('ABC123')
403
+ end
404
+
405
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
406
+
407
+ describe 'retry behaviour' do
408
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
409
+
410
+ it 'retries timeouts' do
411
+ stub = stub_request(:get, %r{.*api.gocardless.com/blocks}).
412
+ to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
413
+
414
+ get_list_response
415
+ expect(stub).to have_been_requested.twice
416
+ end
417
+
418
+ it 'retries 5XX errors' do
419
+ stub = stub_request(:get, %r{.*api.gocardless.com/blocks}).
420
+ to_return(status: 502,
421
+ headers: { 'Content-Type' => 'text/html' },
422
+ body: '<html><body>Response from Cloudflare</body></html>').
423
+ then.to_return(status: 200, headers: response_headers, body: body)
424
+
425
+ get_list_response
426
+ expect(stub).to have_been_requested.twice
427
+ end
428
+ end
429
+ end
430
+ end
431
+
432
+ describe '#all' do
433
+ let!(:first_response_stub) do
434
+ stub_request(:get, %r{.*api.gocardless.com/blocks$}).to_return(
435
+ body: {
436
+ 'blocks' => [{
437
+
438
+ 'active' => 'active-input',
439
+ 'block_type' => 'block_type-input',
440
+ 'created_at' => 'created_at-input',
441
+ 'id' => 'id-input',
442
+ 'reason_description' => 'reason_description-input',
443
+ 'reason_type' => 'reason_type-input',
444
+ 'resource_reference' => 'resource_reference-input',
445
+ 'updated_at' => 'updated_at-input',
446
+ }],
447
+ meta: {
448
+ cursors: { after: 'AB345' },
449
+ limit: 1,
450
+ },
451
+ }.to_json,
452
+ headers: response_headers
453
+ )
454
+ end
455
+
456
+ let!(:second_response_stub) do
457
+ stub_request(:get, %r{.*api.gocardless.com/blocks\?after=AB345}).to_return(
458
+ body: {
459
+ 'blocks' => [{
460
+
461
+ 'active' => 'active-input',
462
+ 'block_type' => 'block_type-input',
463
+ 'created_at' => 'created_at-input',
464
+ 'id' => 'id-input',
465
+ 'reason_description' => 'reason_description-input',
466
+ 'reason_type' => 'reason_type-input',
467
+ 'resource_reference' => 'resource_reference-input',
468
+ 'updated_at' => 'updated_at-input',
469
+ }],
470
+ meta: {
471
+ limit: 2,
472
+ cursors: {},
473
+ },
474
+ }.to_json,
475
+ headers: response_headers
476
+ )
477
+ end
478
+
479
+ it 'automatically makes the extra requests' do
480
+ expect(client.blocks.all.to_a.length).to eq(2)
481
+ expect(first_response_stub).to have_been_requested
482
+ expect(second_response_stub).to have_been_requested
483
+ end
484
+
485
+ describe 'retry behaviour' do
486
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
487
+
488
+ it 'retries timeouts' do
489
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/blocks$}).to_return(
490
+ body: {
491
+ 'blocks' => [{
492
+
493
+ 'active' => 'active-input',
494
+ 'block_type' => 'block_type-input',
495
+ 'created_at' => 'created_at-input',
496
+ 'id' => 'id-input',
497
+ 'reason_description' => 'reason_description-input',
498
+ 'reason_type' => 'reason_type-input',
499
+ 'resource_reference' => 'resource_reference-input',
500
+ 'updated_at' => 'updated_at-input',
501
+ }],
502
+ meta: {
503
+ cursors: { after: 'AB345' },
504
+ limit: 1,
505
+ },
506
+ }.to_json,
507
+ headers: response_headers
508
+ )
509
+
510
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/blocks\?after=AB345}).
511
+ to_timeout.then.
512
+ to_return(
513
+ body: {
514
+ 'blocks' => [{
515
+
516
+ 'active' => 'active-input',
517
+ 'block_type' => 'block_type-input',
518
+ 'created_at' => 'created_at-input',
519
+ 'id' => 'id-input',
520
+ 'reason_description' => 'reason_description-input',
521
+ 'reason_type' => 'reason_type-input',
522
+ 'resource_reference' => 'resource_reference-input',
523
+ 'updated_at' => 'updated_at-input',
524
+ }],
525
+ meta: {
526
+ limit: 2,
527
+ cursors: {},
528
+ },
529
+ }.to_json,
530
+ headers: response_headers
531
+ )
532
+
533
+ client.blocks.all.to_a
534
+
535
+ expect(first_response_stub).to have_been_requested
536
+ expect(second_response_stub).to have_been_requested.twice
537
+ end
538
+
539
+ it 'retries 5XX errors' do
540
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/blocks$}).to_return(
541
+ body: {
542
+ 'blocks' => [{
543
+
544
+ 'active' => 'active-input',
545
+ 'block_type' => 'block_type-input',
546
+ 'created_at' => 'created_at-input',
547
+ 'id' => 'id-input',
548
+ 'reason_description' => 'reason_description-input',
549
+ 'reason_type' => 'reason_type-input',
550
+ 'resource_reference' => 'resource_reference-input',
551
+ 'updated_at' => 'updated_at-input',
552
+ }],
553
+ meta: {
554
+ cursors: { after: 'AB345' },
555
+ limit: 1,
556
+ },
557
+ }.to_json,
558
+ headers: response_headers
559
+ )
560
+
561
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/blocks\?after=AB345}).
562
+ to_return(
563
+ status: 502,
564
+ body: '<html><body>Response from Cloudflare</body></html>',
565
+ headers: { 'Content-Type' => 'text/html' }
566
+ ).then.to_return(
567
+ body: {
568
+ 'blocks' => [{
569
+
570
+ 'active' => 'active-input',
571
+ 'block_type' => 'block_type-input',
572
+ 'created_at' => 'created_at-input',
573
+ 'id' => 'id-input',
574
+ 'reason_description' => 'reason_description-input',
575
+ 'reason_type' => 'reason_type-input',
576
+ 'resource_reference' => 'resource_reference-input',
577
+ 'updated_at' => 'updated_at-input',
578
+ }],
579
+ meta: {
580
+ limit: 2,
581
+ cursors: {},
582
+ },
583
+ }.to_json,
584
+ headers: response_headers
585
+ )
586
+
587
+ client.blocks.all.to_a
588
+
589
+ expect(first_response_stub).to have_been_requested
590
+ expect(second_response_stub).to have_been_requested.twice
591
+ end
592
+ end
593
+ end
594
+
595
+ describe '#disable' do
596
+ subject(:post_response) { client.blocks.disable(resource_id) }
597
+
598
+ let(:resource_id) { 'ABC123' }
599
+
600
+ let!(:stub) do
601
+ # /blocks/%v/actions/disable
602
+ stub_url = '/blocks/:identity/actions/disable'.gsub(':identity', resource_id)
603
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
604
+
605
+ body: {
606
+ 'blocks' => {
607
+
608
+ 'active' => 'active-input',
609
+ 'block_type' => 'block_type-input',
610
+ 'created_at' => 'created_at-input',
611
+ 'id' => 'id-input',
612
+ 'reason_description' => 'reason_description-input',
613
+ 'reason_type' => 'reason_type-input',
614
+ 'resource_reference' => 'resource_reference-input',
615
+ 'updated_at' => 'updated_at-input',
616
+ },
617
+ }.to_json,
618
+
619
+ headers: response_headers
620
+ )
621
+ end
622
+
623
+ it 'wraps the response and calls the right endpoint' do
624
+ expect(post_response).to be_a(GoCardlessPro::Resources::Block)
625
+
626
+ expect(stub).to have_been_requested
627
+ end
628
+
629
+ describe 'retry behaviour' do
630
+ it "doesn't retry errors" do
631
+ stub_url = '/blocks/:identity/actions/disable'.gsub(':identity', resource_id)
632
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
633
+ to_timeout
634
+
635
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
636
+ expect(stub).to have_been_requested
637
+ end
638
+ end
639
+
640
+ context 'when the request needs a body and custom header' do
641
+ let(:body) { { foo: 'bar' } }
642
+ let(:headers) { { 'Foo' => 'Bar' } }
643
+ subject(:post_response) { client.blocks.disable(resource_id, body, headers) }
644
+
645
+ let(:resource_id) { 'ABC123' }
646
+
647
+ let!(:stub) do
648
+ # /blocks/%v/actions/disable
649
+ stub_url = '/blocks/:identity/actions/disable'.gsub(':identity', resource_id)
650
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
651
+ with(
652
+ body: { foo: 'bar' },
653
+ headers: { 'Foo' => 'Bar' }
654
+ ).to_return(
655
+ body: {
656
+ 'blocks' => {
657
+
658
+ 'active' => 'active-input',
659
+ 'block_type' => 'block_type-input',
660
+ 'created_at' => 'created_at-input',
661
+ 'id' => 'id-input',
662
+ 'reason_description' => 'reason_description-input',
663
+ 'reason_type' => 'reason_type-input',
664
+ 'resource_reference' => 'resource_reference-input',
665
+ 'updated_at' => 'updated_at-input',
666
+ },
667
+ }.to_json,
668
+ headers: response_headers
669
+ )
670
+ end
671
+ end
672
+ end
673
+
674
+ describe '#enable' do
675
+ subject(:post_response) { client.blocks.enable(resource_id) }
676
+
677
+ let(:resource_id) { 'ABC123' }
678
+
679
+ let!(:stub) do
680
+ # /blocks/%v/actions/enable
681
+ stub_url = '/blocks/:identity/actions/enable'.gsub(':identity', resource_id)
682
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
683
+
684
+ body: {
685
+ 'blocks' => {
686
+
687
+ 'active' => 'active-input',
688
+ 'block_type' => 'block_type-input',
689
+ 'created_at' => 'created_at-input',
690
+ 'id' => 'id-input',
691
+ 'reason_description' => 'reason_description-input',
692
+ 'reason_type' => 'reason_type-input',
693
+ 'resource_reference' => 'resource_reference-input',
694
+ 'updated_at' => 'updated_at-input',
695
+ },
696
+ }.to_json,
697
+
698
+ headers: response_headers
699
+ )
700
+ end
701
+
702
+ it 'wraps the response and calls the right endpoint' do
703
+ expect(post_response).to be_a(GoCardlessPro::Resources::Block)
704
+
705
+ expect(stub).to have_been_requested
706
+ end
707
+
708
+ describe 'retry behaviour' do
709
+ it "doesn't retry errors" do
710
+ stub_url = '/blocks/:identity/actions/enable'.gsub(':identity', resource_id)
711
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
712
+ to_timeout
713
+
714
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
715
+ expect(stub).to have_been_requested
716
+ end
717
+ end
718
+
719
+ context 'when the request needs a body and custom header' do
720
+ let(:body) { { foo: 'bar' } }
721
+ let(:headers) { { 'Foo' => 'Bar' } }
722
+ subject(:post_response) { client.blocks.enable(resource_id, body, headers) }
723
+
724
+ let(:resource_id) { 'ABC123' }
725
+
726
+ let!(:stub) do
727
+ # /blocks/%v/actions/enable
728
+ stub_url = '/blocks/:identity/actions/enable'.gsub(':identity', resource_id)
729
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
730
+ with(
731
+ body: { foo: 'bar' },
732
+ headers: { 'Foo' => 'Bar' }
733
+ ).to_return(
734
+ body: {
735
+ 'blocks' => {
736
+
737
+ 'active' => 'active-input',
738
+ 'block_type' => 'block_type-input',
739
+ 'created_at' => 'created_at-input',
740
+ 'id' => 'id-input',
741
+ 'reason_description' => 'reason_description-input',
742
+ 'reason_type' => 'reason_type-input',
743
+ 'resource_reference' => 'resource_reference-input',
744
+ 'updated_at' => 'updated_at-input',
745
+ },
746
+ }.to_json,
747
+ headers: response_headers
748
+ )
749
+ end
750
+ end
751
+ end
752
+
753
+ describe '#block_by_ref' do
754
+ subject(:post_response) { client.blocks.block_by_ref }
755
+
756
+ let(:resource_id) { 'ABC123' }
757
+
758
+ let!(:stub) do
759
+ # /block_by_ref
760
+ stub_url = '/block_by_ref'.gsub(':identity', resource_id)
761
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
762
+
763
+ body: {
764
+ 'blocks' => [{
765
+
766
+ 'active' => 'active-input',
767
+ 'block_type' => 'block_type-input',
768
+ 'created_at' => 'created_at-input',
769
+ 'id' => 'id-input',
770
+ 'reason_description' => 'reason_description-input',
771
+ 'reason_type' => 'reason_type-input',
772
+ 'resource_reference' => 'resource_reference-input',
773
+ 'updated_at' => 'updated_at-input',
774
+ }],
775
+ meta: {
776
+ cursors: {
777
+ before: nil,
778
+ after: 'ABC123',
779
+ },
780
+ },
781
+ }.to_json,
782
+
783
+ headers: response_headers
784
+ )
785
+ end
786
+
787
+ it 'wraps the response and calls the right endpoint' do
788
+ expect(post_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Block)
789
+
790
+ expect(stub).to have_been_requested
791
+ end
792
+
793
+ it 'exposes the cursors for before and after' do
794
+ expect(post_response.before).to eq(nil)
795
+ expect(post_response.after).to eq('ABC123')
796
+ end
797
+
798
+ describe 'retry behaviour' do
799
+ it "doesn't retry errors" do
800
+ stub_url = '/block_by_ref'.gsub(':identity', resource_id)
801
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
802
+ to_timeout
803
+
804
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
805
+ expect(stub).to have_been_requested
806
+ end
807
+ end
808
+
809
+ context 'when the request needs a body and custom header' do
810
+ subject(:post_response) { client.blocks.block_by_ref(body, headers) }
811
+
812
+ let(:resource_id) { 'ABC123' }
813
+
814
+ let!(:stub) do
815
+ # /block_by_ref
816
+ stub_url = '/block_by_ref'.gsub(':identity', resource_id)
817
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
818
+ with(
819
+ body: { foo: 'bar' },
820
+ headers: { 'Foo' => 'Bar' }
821
+ ).to_return(
822
+ body: {
823
+ 'blocks' => {
824
+
825
+ 'active' => 'active-input',
826
+ 'block_type' => 'block_type-input',
827
+ 'created_at' => 'created_at-input',
828
+ 'id' => 'id-input',
829
+ 'reason_description' => 'reason_description-input',
830
+ 'reason_type' => 'reason_type-input',
831
+ 'resource_reference' => 'resource_reference-input',
832
+ 'updated_at' => 'updated_at-input',
833
+ },
834
+ }.to_json,
835
+ headers: response_headers
836
+ )
837
+ end
838
+ end
839
+ end
840
+ end