gocardless_pro 2.24.0 → 2.29.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +23 -4
  3. data/lib/gocardless_pro/api_service.rb +4 -0
  4. data/lib/gocardless_pro/client.rb +46 -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 +81 -0
  10. data/lib/gocardless_pro/resources/billing_request.rb +108 -0
  11. data/lib/gocardless_pro/resources/billing_request_flow.rb +72 -0
  12. data/lib/gocardless_pro/resources/billing_request_template.rb +68 -0
  13. data/lib/gocardless_pro/resources/block.rb +66 -0
  14. data/lib/gocardless_pro/resources/creditor.rb +2 -3
  15. data/lib/gocardless_pro/resources/event.rb +20 -0
  16. data/lib/gocardless_pro/resources/institution.rb +47 -0
  17. data/lib/gocardless_pro/resources/payer_authorisation.rb +131 -0
  18. data/lib/gocardless_pro/resources/payout_item.rb +4 -0
  19. data/lib/gocardless_pro/resources/redirect_flow.rb +2 -0
  20. data/lib/gocardless_pro/resources/scenario_simulator.rb +42 -0
  21. data/lib/gocardless_pro/resources/webhook.rb +62 -0
  22. data/lib/gocardless_pro/services/bank_authorisations_service.rb +80 -0
  23. data/lib/gocardless_pro/services/billing_request_flows_service.rb +70 -0
  24. data/lib/gocardless_pro/services/billing_request_templates_service.rb +131 -0
  25. data/lib/gocardless_pro/services/billing_requests_service.rb +352 -0
  26. data/lib/gocardless_pro/services/blocks_service.rb +223 -0
  27. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +1 -5
  28. data/lib/gocardless_pro/services/creditors_service.rb +1 -3
  29. data/lib/gocardless_pro/services/currency_exchange_rates_service.rb +1 -1
  30. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +1 -5
  31. data/lib/gocardless_pro/services/customers_service.rb +1 -3
  32. data/lib/gocardless_pro/services/events_service.rb +1 -1
  33. data/lib/gocardless_pro/services/instalment_schedules_service.rb +1 -7
  34. data/lib/gocardless_pro/services/institutions_service.rb +56 -0
  35. data/lib/gocardless_pro/services/mandate_import_entries_service.rb +1 -1
  36. data/lib/gocardless_pro/services/mandate_imports_service.rb +0 -6
  37. data/lib/gocardless_pro/services/mandates_service.rb +1 -7
  38. data/lib/gocardless_pro/services/payer_authorisations_service.rb +202 -0
  39. data/lib/gocardless_pro/services/payments_service.rb +1 -7
  40. data/lib/gocardless_pro/services/payout_items_service.rb +1 -1
  41. data/lib/gocardless_pro/services/payouts_service.rb +1 -1
  42. data/lib/gocardless_pro/services/redirect_flows_service.rb +0 -4
  43. data/lib/gocardless_pro/services/refunds_service.rb +1 -3
  44. data/lib/gocardless_pro/services/scenario_simulators_service.rb +170 -0
  45. data/lib/gocardless_pro/services/subscriptions_service.rb +10 -13
  46. data/lib/gocardless_pro/services/tax_rates_service.rb +1 -1
  47. data/lib/gocardless_pro/services/webhooks_service.rb +111 -0
  48. data/lib/gocardless_pro/version.rb +1 -1
  49. data/lib/gocardless_pro.rb +30 -0
  50. data/spec/api_service_spec.rb +12 -1
  51. data/spec/middlewares/raise_gocardless_errors_spec.rb +30 -0
  52. data/spec/resources/bank_authorisation_spec.rb +259 -0
  53. data/spec/resources/billing_request_flow_spec.rb +219 -0
  54. data/spec/resources/billing_request_spec.rb +782 -0
  55. data/spec/resources/billing_request_template_spec.rb +502 -0
  56. data/spec/resources/block_spec.rb +560 -0
  57. data/spec/resources/institution_spec.rb +108 -0
  58. data/spec/resources/payer_authorisation_spec.rb +418 -0
  59. data/spec/resources/redirect_flow_spec.rb +9 -0
  60. data/spec/resources/scenario_simulator_spec.rb +63 -0
  61. data/spec/resources/webhook_spec.rb +323 -0
  62. data/spec/services/bank_authorisations_service_spec.rb +353 -0
  63. data/spec/services/billing_request_flows_service_spec.rb +253 -0
  64. data/spec/services/billing_request_templates_service_spec.rb +789 -0
  65. data/spec/services/billing_requests_service_spec.rb +1082 -0
  66. data/spec/services/blocks_service_spec.rb +823 -0
  67. data/spec/services/creditor_bank_accounts_service_spec.rb +0 -13
  68. data/spec/services/creditors_service_spec.rb +0 -13
  69. data/spec/services/customer_bank_accounts_service_spec.rb +0 -13
  70. data/spec/services/customers_service_spec.rb +0 -13
  71. data/spec/services/instalment_schedules_service_spec.rb +0 -26
  72. data/spec/services/institutions_service_spec.rb +232 -0
  73. data/spec/services/mandate_imports_service_spec.rb +0 -13
  74. data/spec/services/mandates_service_spec.rb +0 -13
  75. data/spec/services/payer_authorisations_service_spec.rb +559 -0
  76. data/spec/services/payments_service_spec.rb +0 -13
  77. data/spec/services/redirect_flows_service_spec.rb +9 -13
  78. data/spec/services/refunds_service_spec.rb +0 -13
  79. data/spec/services/scenario_simulators_service_spec.rb +74 -0
  80. data/spec/services/subscriptions_service_spec.rb +0 -13
  81. data/spec/services/webhooks_service_spec.rb +545 -0
  82. metadata +64 -7
@@ -0,0 +1,823 @@
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
+ body: {
605
+ 'blocks' => {
606
+
607
+ 'active' => 'active-input',
608
+ 'block_type' => 'block_type-input',
609
+ 'created_at' => 'created_at-input',
610
+ 'id' => 'id-input',
611
+ 'reason_description' => 'reason_description-input',
612
+ 'reason_type' => 'reason_type-input',
613
+ 'resource_reference' => 'resource_reference-input',
614
+ 'updated_at' => 'updated_at-input',
615
+ },
616
+ }.to_json,
617
+ headers: response_headers
618
+ )
619
+ end
620
+
621
+ it 'wraps the response and calls the right endpoint' do
622
+ expect(post_response).to be_a(GoCardlessPro::Resources::Block)
623
+
624
+ expect(stub).to have_been_requested
625
+ end
626
+
627
+ describe 'retry behaviour' do
628
+ it "doesn't retry errors" do
629
+ stub_url = '/blocks/:identity/actions/disable'.gsub(':identity', resource_id)
630
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
631
+ to_timeout
632
+
633
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
634
+ expect(stub).to have_been_requested
635
+ end
636
+ end
637
+
638
+ context 'when the request needs a body and custom header' do
639
+ let(:body) { { foo: 'bar' } }
640
+ let(:headers) { { 'Foo' => 'Bar' } }
641
+ subject(:post_response) { client.blocks.disable(resource_id, body, headers) }
642
+
643
+ let(:resource_id) { 'ABC123' }
644
+
645
+ let!(:stub) do
646
+ # /blocks/%v/actions/disable
647
+ stub_url = '/blocks/:identity/actions/disable'.gsub(':identity', resource_id)
648
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
649
+ with(
650
+ body: { foo: 'bar' },
651
+ headers: { 'Foo' => 'Bar' }
652
+ ).to_return(
653
+ body: {
654
+ 'blocks' => {
655
+
656
+ 'active' => 'active-input',
657
+ 'block_type' => 'block_type-input',
658
+ 'created_at' => 'created_at-input',
659
+ 'id' => 'id-input',
660
+ 'reason_description' => 'reason_description-input',
661
+ 'reason_type' => 'reason_type-input',
662
+ 'resource_reference' => 'resource_reference-input',
663
+ 'updated_at' => 'updated_at-input',
664
+ },
665
+ }.to_json,
666
+ headers: response_headers
667
+ )
668
+ end
669
+ end
670
+ end
671
+
672
+ describe '#enable' do
673
+ subject(:post_response) { client.blocks.enable(resource_id) }
674
+
675
+ let(:resource_id) { 'ABC123' }
676
+
677
+ let!(:stub) do
678
+ # /blocks/%v/actions/enable
679
+ stub_url = '/blocks/:identity/actions/enable'.gsub(':identity', resource_id)
680
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
681
+ body: {
682
+ 'blocks' => {
683
+
684
+ 'active' => 'active-input',
685
+ 'block_type' => 'block_type-input',
686
+ 'created_at' => 'created_at-input',
687
+ 'id' => 'id-input',
688
+ 'reason_description' => 'reason_description-input',
689
+ 'reason_type' => 'reason_type-input',
690
+ 'resource_reference' => 'resource_reference-input',
691
+ 'updated_at' => 'updated_at-input',
692
+ },
693
+ }.to_json,
694
+ headers: response_headers
695
+ )
696
+ end
697
+
698
+ it 'wraps the response and calls the right endpoint' do
699
+ expect(post_response).to be_a(GoCardlessPro::Resources::Block)
700
+
701
+ expect(stub).to have_been_requested
702
+ end
703
+
704
+ describe 'retry behaviour' do
705
+ it "doesn't retry errors" do
706
+ stub_url = '/blocks/:identity/actions/enable'.gsub(':identity', resource_id)
707
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
708
+ to_timeout
709
+
710
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
711
+ expect(stub).to have_been_requested
712
+ end
713
+ end
714
+
715
+ context 'when the request needs a body and custom header' do
716
+ let(:body) { { foo: 'bar' } }
717
+ let(:headers) { { 'Foo' => 'Bar' } }
718
+ subject(:post_response) { client.blocks.enable(resource_id, body, headers) }
719
+
720
+ let(:resource_id) { 'ABC123' }
721
+
722
+ let!(:stub) do
723
+ # /blocks/%v/actions/enable
724
+ stub_url = '/blocks/:identity/actions/enable'.gsub(':identity', resource_id)
725
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
726
+ with(
727
+ body: { foo: 'bar' },
728
+ headers: { 'Foo' => 'Bar' }
729
+ ).to_return(
730
+ body: {
731
+ 'blocks' => {
732
+
733
+ 'active' => 'active-input',
734
+ 'block_type' => 'block_type-input',
735
+ 'created_at' => 'created_at-input',
736
+ 'id' => 'id-input',
737
+ 'reason_description' => 'reason_description-input',
738
+ 'reason_type' => 'reason_type-input',
739
+ 'resource_reference' => 'resource_reference-input',
740
+ 'updated_at' => 'updated_at-input',
741
+ },
742
+ }.to_json,
743
+ headers: response_headers
744
+ )
745
+ end
746
+ end
747
+ end
748
+
749
+ describe '#block_by_ref' do
750
+ subject(:post_response) { client.blocks.block_by_ref }
751
+
752
+ let(:resource_id) { 'ABC123' }
753
+
754
+ let!(:stub) do
755
+ # /block_by_ref
756
+ stub_url = '/block_by_ref'.gsub(':identity', resource_id)
757
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
758
+ body: {
759
+ 'blocks' => [{
760
+
761
+ 'active' => 'active-input',
762
+ 'block_type' => 'block_type-input',
763
+ 'created_at' => 'created_at-input',
764
+ 'id' => 'id-input',
765
+ 'reason_description' => 'reason_description-input',
766
+ 'reason_type' => 'reason_type-input',
767
+ 'resource_reference' => 'resource_reference-input',
768
+ 'updated_at' => 'updated_at-input',
769
+ }],
770
+ }.to_json,
771
+ headers: response_headers
772
+ )
773
+ end
774
+
775
+ it 'wraps the response and calls the right endpoint' do
776
+ expect(post_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Block)
777
+
778
+ expect(stub).to have_been_requested
779
+ end
780
+
781
+ describe 'retry behaviour' do
782
+ it "doesn't retry errors" do
783
+ stub_url = '/block_by_ref'.gsub(':identity', resource_id)
784
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
785
+ to_timeout
786
+
787
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
788
+ expect(stub).to have_been_requested
789
+ end
790
+ end
791
+
792
+ context 'when the request needs a body and custom header' do
793
+ subject(:post_response) { client.blocks.block_by_ref(body, headers) }
794
+
795
+ let(:resource_id) { 'ABC123' }
796
+
797
+ let!(:stub) do
798
+ # /block_by_ref
799
+ stub_url = '/block_by_ref'.gsub(':identity', resource_id)
800
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
801
+ with(
802
+ body: { foo: 'bar' },
803
+ headers: { 'Foo' => 'Bar' }
804
+ ).to_return(
805
+ body: {
806
+ 'blocks' => {
807
+
808
+ 'active' => 'active-input',
809
+ 'block_type' => 'block_type-input',
810
+ 'created_at' => 'created_at-input',
811
+ 'id' => 'id-input',
812
+ 'reason_description' => 'reason_description-input',
813
+ 'reason_type' => 'reason_type-input',
814
+ 'resource_reference' => 'resource_reference-input',
815
+ 'updated_at' => 'updated_at-input',
816
+ },
817
+ }.to_json,
818
+ headers: response_headers
819
+ )
820
+ end
821
+ end
822
+ end
823
+ end