gocardless_pro 1.1.0 → 2.0.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -4
  3. data/lib/gocardless_pro.rb +1 -0
  4. data/lib/gocardless_pro/api_service.rb +2 -0
  5. data/lib/gocardless_pro/client.rb +4 -3
  6. data/lib/gocardless_pro/error/invalid_state_error.rb +17 -0
  7. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +50 -0
  8. data/lib/gocardless_pro/request.rb +38 -1
  9. data/lib/gocardless_pro/resources/creditor.rb +2 -2
  10. data/lib/gocardless_pro/resources/creditor_bank_account.rb +11 -11
  11. data/lib/gocardless_pro/resources/customer_bank_account.rb +2 -2
  12. data/lib/gocardless_pro/resources/event.rb +2 -2
  13. data/lib/gocardless_pro/resources/mandate.rb +2 -2
  14. data/lib/gocardless_pro/resources/payment.rb +7 -7
  15. data/lib/gocardless_pro/resources/payout.rb +7 -6
  16. data/lib/gocardless_pro/resources/redirect_flow.rb +2 -2
  17. data/lib/gocardless_pro/resources/refund.rb +2 -2
  18. data/lib/gocardless_pro/resources/subscription.rb +2 -2
  19. data/lib/gocardless_pro/response.rb +2 -54
  20. data/lib/gocardless_pro/services/bank_details_lookups_service.rb +3 -0
  21. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +31 -2
  22. data/lib/gocardless_pro/services/creditors_service.rb +21 -1
  23. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +34 -2
  24. data/lib/gocardless_pro/services/customers_service.rb +21 -1
  25. data/lib/gocardless_pro/services/events_service.rb +5 -0
  26. data/lib/gocardless_pro/services/mandate_pdfs_service.rb +3 -0
  27. data/lib/gocardless_pro/services/mandates_service.rb +47 -3
  28. data/lib/gocardless_pro/services/payments_service.rb +47 -3
  29. data/lib/gocardless_pro/services/payouts_service.rb +5 -0
  30. data/lib/gocardless_pro/services/redirect_flows_service.rb +28 -2
  31. data/lib/gocardless_pro/services/refunds_service.rb +21 -1
  32. data/lib/gocardless_pro/services/subscriptions_service.rb +34 -2
  33. data/lib/gocardless_pro/version.rb +1 -1
  34. data/spec/api_service_spec.rb +106 -0
  35. data/spec/middlewares/raise_gocardless_errors_spec.rb +98 -0
  36. data/spec/resources/bank_details_lookup_spec.rb +102 -19
  37. data/spec/resources/creditor_bank_account_spec.rb +416 -40
  38. data/spec/resources/creditor_spec.rb +414 -53
  39. data/spec/resources/customer_bank_account_spec.rb +452 -40
  40. data/spec/resources/customer_spec.rb +457 -45
  41. data/spec/resources/event_spec.rb +171 -72
  42. data/spec/resources/mandate_pdf_spec.rb +100 -17
  43. data/spec/resources/mandate_spec.rb +501 -44
  44. data/spec/resources/payment_spec.rb +531 -48
  45. data/spec/resources/payout_spec.rb +189 -45
  46. data/spec/resources/redirect_flow_spec.rb +277 -43
  47. data/spec/resources/refund_spec.rb +349 -34
  48. data/spec/resources/subscription_spec.rb +531 -53
  49. data/spec/response_spec.rb +12 -79
  50. data/spec/services/bank_details_lookups_service_spec.rb +67 -2
  51. data/spec/services/creditor_bank_accounts_service_spec.rb +309 -31
  52. data/spec/services/creditors_service_spec.rb +343 -33
  53. data/spec/services/customer_bank_accounts_service_spec.rb +335 -32
  54. data/spec/services/customers_service_spec.rb +364 -36
  55. data/spec/services/events_service_spec.rb +185 -24
  56. data/spec/services/mandate_pdfs_service_spec.rb +66 -2
  57. data/spec/services/mandates_service_spec.rb +341 -33
  58. data/spec/services/payments_service_spec.rb +355 -35
  59. data/spec/services/payouts_service_spec.rb +206 -26
  60. data/spec/services/redirect_flows_service_spec.rb +137 -7
  61. data/spec/services/refunds_service_spec.rb +301 -27
  62. data/spec/services/subscriptions_service_spec.rb +377 -38
  63. metadata +6 -3
@@ -2,11 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Response do
4
4
  subject(:response) { described_class.new(raw_response) }
5
+
5
6
  let(:default_headers) do
6
7
  { 'Content-Type' => 'application/json' }
7
8
  end
8
9
 
9
- context 'when the response is not an error' do
10
+ describe '#body' do
11
+ subject(:body) { response.body }
12
+
10
13
  let(:raw_response) do
11
14
  double('response',
12
15
  headers: default_headers,
@@ -16,87 +19,17 @@ describe GoCardlessPro::Response do
16
19
  end
17
20
 
18
21
  it 'returns the body parsed into a hash' do
19
- expect(response.body).to eq('customers' => [])
22
+ expect(body).to eq('customers' => [])
20
23
  end
21
- end
22
24
 
23
- context 'when the response is empty' do
24
- let(:raw_response) do
25
- double('response', headers: default_headers, status: 204, body: '')
26
- end
27
-
28
- it 'returns nil' do
29
- expect(response.body).to be_nil
30
- end
31
- end
32
-
33
- context 'when the resonse is a validation error' do
34
- let(:raw_response) do
35
- double('response',
36
- headers: default_headers,
37
- status: 400,
38
- body: { error: { type: 'validation_failed' } }.to_json
39
- )
40
- end
41
-
42
- it 'raises a ValidationError' do
43
- expect { response.body }.to raise_error(GoCardlessPro::ValidationError)
44
- end
45
- end
46
-
47
- context 'when the resonse is a gocardless error' do
48
- let(:raw_response) do
49
- double('response',
50
- headers: default_headers,
51
- status: 400,
52
- body: { error: { type: 'gocardless' } }.to_json
53
- )
54
- end
55
-
56
- it 'raises a ValidationError' do
57
- expect { response.body }.to raise_error(GoCardlessPro::GoCardlessError)
58
- end
59
- end
60
-
61
- context 'when the resonse is an invalid api usage error' do
62
- let(:raw_response) do
63
- double('response',
64
- headers: default_headers,
65
- status: 400,
66
- body: { error: { type: 'invalid_api_usage' } }.to_json
67
- )
68
- end
69
-
70
- it 'raises a ValidationError' do
71
- expect { response.body }.to raise_error(GoCardlessPro::InvalidApiUsageError)
72
- end
73
- end
74
-
75
- context "when the response isn't JSON" do
76
- let(:raw_response) do
77
- double('response',
78
- headers: {},
79
- status: 400,
80
- body: ''
81
- )
82
- end
83
-
84
- it 'raises an ApiError' do
85
- expect { response.body }.to raise_error(GoCardlessPro::ApiError)
86
- end
87
- end
88
-
89
- context 'when the response is an invalid state error' do
90
- let(:raw_response) do
91
- double('response',
92
- headers: default_headers,
93
- status: 400,
94
- body: { error: { type: 'invalid_state' } }.to_json
95
- )
96
- end
25
+ context 'when the response is empty' do
26
+ let(:raw_response) do
27
+ double('response', headers: default_headers, status: 204, body: '')
28
+ end
97
29
 
98
- it 'raises a ValidationError' do
99
- expect { response.body }.to raise_error(GoCardlessPro::InvalidStateError)
30
+ it 'returns nil' do
31
+ expect(body).to be_nil
32
+ end
100
33
  end
101
34
  end
102
35
  end
@@ -7,6 +7,8 @@ describe GoCardlessPro::Services::BankDetailsLookupsService do
7
7
  )
8
8
  end
9
9
 
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
10
12
  describe '#create' do
11
13
  subject(:post_create_response) { client.bank_details_lookups.create(params: new_resource) }
12
14
  context 'with a valid request' do
@@ -43,13 +45,36 @@ describe GoCardlessPro::Services::BankDetailsLookupsService do
43
45
  }
44
46
 
45
47
  }.to_json,
46
- headers: { 'Content-Type' => 'application/json' }
48
+ headers: response_headers
47
49
  )
48
50
  end
49
51
 
50
52
  it 'creates and returns the resource' do
51
53
  expect(post_create_response).to be_a(GoCardlessPro::Resources::BankDetailsLookup)
52
54
  end
55
+
56
+ describe 'retry behaviour' do
57
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
58
+
59
+ it 'retries timeouts' do
60
+ stub = stub_request(:post, %r{.*api.gocardless.com/bank_details_lookups})
61
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
62
+
63
+ post_create_response
64
+ expect(stub).to have_been_requested.twice
65
+ end
66
+
67
+ it 'retries 5XX errors' do
68
+ stub = stub_request(:post, %r{.*api.gocardless.com/bank_details_lookups})
69
+ .to_return(status: 502,
70
+ headers: { 'Content-Type' => 'text/html' },
71
+ body: '<html><body>Response from Cloudflare</body></html>')
72
+ .then.to_return(status: 200, headers: response_headers)
73
+
74
+ post_create_response
75
+ expect(stub).to have_been_requested.twice
76
+ end
77
+ end
53
78
  end
54
79
 
55
80
  context 'with a request that returns a validation error' do
@@ -66,7 +91,7 @@ describe GoCardlessPro::Services::BankDetailsLookupsService do
66
91
  ]
67
92
  }
68
93
  }.to_json,
69
- headers: { 'Content-Type' => 'application/json' },
94
+ headers: response_headers,
70
95
  status: 422
71
96
  )
72
97
  end
@@ -75,5 +100,45 @@ describe GoCardlessPro::Services::BankDetailsLookupsService do
75
100
  expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
76
101
  end
77
102
  end
103
+
104
+ context 'with a request that returns an idempotent creation conflict error' do
105
+ let(:id) { 'ID123' }
106
+
107
+ let(:new_resource) do
108
+ {
109
+
110
+ 'available_debit_schemes' => 'available_debit_schemes-input',
111
+ 'bank_name' => 'bank_name-input',
112
+ 'bic' => 'bic-input'
113
+ }
114
+ end
115
+
116
+ let!(:post_stub) do
117
+ stub_request(:post, %r{.*api.gocardless.com/bank_details_lookups}).to_return(
118
+ body: {
119
+ error: {
120
+ type: 'invalid_state',
121
+ code: 409,
122
+ errors: [
123
+ {
124
+ message: 'A resource has already been created with this idempotency key',
125
+ reason: 'idempotent_creation_conflict',
126
+ links: {
127
+ conflicting_resource_id: id
128
+ }
129
+ }
130
+ ]
131
+ }
132
+ }.to_json,
133
+ headers: response_headers,
134
+ status: 409
135
+ )
136
+ end
137
+
138
+ it 'raises an InvalidStateError' do
139
+ expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError)
140
+ expect(post_stub).to have_been_requested
141
+ end
142
+ end
78
143
  end
79
144
  end
@@ -7,6 +7,8 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
7
7
  )
8
8
  end
9
9
 
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
10
12
  describe '#create' do
11
13
  subject(:post_create_response) { client.creditor_bank_accounts.create(params: new_resource) }
12
14
  context 'with a valid request' do
@@ -64,13 +66,36 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
64
66
  }
65
67
 
66
68
  }.to_json,
67
- headers: { 'Content-Type' => 'application/json' }
69
+ headers: response_headers
68
70
  )
69
71
  end
70
72
 
71
73
  it 'creates and returns the resource' do
72
74
  expect(post_create_response).to be_a(GoCardlessPro::Resources::CreditorBankAccount)
73
75
  end
76
+
77
+ describe 'retry behaviour' do
78
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
79
+
80
+ it 'retries timeouts' do
81
+ stub = stub_request(:post, %r{.*api.gocardless.com/creditor_bank_accounts})
82
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
83
+
84
+ post_create_response
85
+ expect(stub).to have_been_requested.twice
86
+ end
87
+
88
+ it 'retries 5XX errors' do
89
+ stub = stub_request(:post, %r{.*api.gocardless.com/creditor_bank_accounts})
90
+ .to_return(status: 502,
91
+ headers: { 'Content-Type' => 'text/html' },
92
+ body: '<html><body>Response from Cloudflare</body></html>')
93
+ .then.to_return(status: 200, headers: response_headers)
94
+
95
+ post_create_response
96
+ expect(stub).to have_been_requested.twice
97
+ end
98
+ end
74
99
  end
75
100
 
76
101
  context 'with a request that returns a validation error' do
@@ -87,7 +112,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
87
112
  ]
88
113
  }
89
114
  }.to_json,
90
- headers: { 'Content-Type' => 'application/json' },
115
+ headers: response_headers,
91
116
  status: 422
92
117
  )
93
118
  end
@@ -96,36 +121,111 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
96
121
  expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
97
122
  end
98
123
  end
124
+
125
+ context 'with a request that returns an idempotent creation conflict error' do
126
+ let(:id) { 'ID123' }
127
+
128
+ let(:new_resource) do
129
+ {
130
+
131
+ 'account_holder_name' => 'account_holder_name-input',
132
+ 'account_number_ending' => 'account_number_ending-input',
133
+ 'bank_name' => 'bank_name-input',
134
+ 'country_code' => 'country_code-input',
135
+ 'created_at' => 'created_at-input',
136
+ 'currency' => 'currency-input',
137
+ 'enabled' => 'enabled-input',
138
+ 'id' => 'id-input',
139
+ 'links' => 'links-input',
140
+ 'metadata' => 'metadata-input'
141
+ }
142
+ end
143
+
144
+ let!(:post_stub) do
145
+ stub_request(:post, %r{.*api.gocardless.com/creditor_bank_accounts}).to_return(
146
+ body: {
147
+ error: {
148
+ type: 'invalid_state',
149
+ code: 409,
150
+ errors: [
151
+ {
152
+ message: 'A resource has already been created with this idempotency key',
153
+ reason: 'idempotent_creation_conflict',
154
+ links: {
155
+ conflicting_resource_id: id
156
+ }
157
+ }
158
+ ]
159
+ }
160
+ }.to_json,
161
+ headers: response_headers,
162
+ status: 409
163
+ )
164
+ end
165
+
166
+ let!(:get_stub) do
167
+ stub_url = "/creditor_bank_accounts/#{id}"
168
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
169
+ .to_return(
170
+ body: {
171
+ 'creditor_bank_accounts' => {
172
+
173
+ 'account_holder_name' => 'account_holder_name-input',
174
+ 'account_number_ending' => 'account_number_ending-input',
175
+ 'bank_name' => 'bank_name-input',
176
+ 'country_code' => 'country_code-input',
177
+ 'created_at' => 'created_at-input',
178
+ 'currency' => 'currency-input',
179
+ 'enabled' => 'enabled-input',
180
+ 'id' => 'id-input',
181
+ 'links' => 'links-input',
182
+ 'metadata' => 'metadata-input'
183
+ }
184
+ }.to_json,
185
+ headers: response_headers
186
+ )
187
+ end
188
+
189
+ it 'fetches the already-created resource' do
190
+ post_create_response
191
+ expect(post_stub).to have_been_requested
192
+ expect(get_stub).to have_been_requested
193
+ end
194
+ end
99
195
  end
100
196
 
101
197
  describe '#list' do
102
198
  describe 'with no filters' do
103
199
  subject(:get_list_response) { client.creditor_bank_accounts.list }
104
200
 
105
- before do
106
- stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts}).to_return(
107
- body: {
108
- 'creditor_bank_accounts' => [{
201
+ let(:body) do
202
+ {
203
+ 'creditor_bank_accounts' => [{
109
204
 
110
- 'account_holder_name' => 'account_holder_name-input',
111
- 'account_number_ending' => 'account_number_ending-input',
112
- 'bank_name' => 'bank_name-input',
113
- 'country_code' => 'country_code-input',
114
- 'created_at' => 'created_at-input',
115
- 'currency' => 'currency-input',
116
- 'enabled' => 'enabled-input',
117
- 'id' => 'id-input',
118
- 'links' => 'links-input',
119
- 'metadata' => 'metadata-input'
120
- }],
121
- meta: {
122
- cursors: {
123
- before: nil,
124
- after: 'ABC123'
125
- }
205
+ 'account_holder_name' => 'account_holder_name-input',
206
+ 'account_number_ending' => 'account_number_ending-input',
207
+ 'bank_name' => 'bank_name-input',
208
+ 'country_code' => 'country_code-input',
209
+ 'created_at' => 'created_at-input',
210
+ 'currency' => 'currency-input',
211
+ 'enabled' => 'enabled-input',
212
+ 'id' => 'id-input',
213
+ 'links' => 'links-input',
214
+ 'metadata' => 'metadata-input'
215
+ }],
216
+ meta: {
217
+ cursors: {
218
+ before: nil,
219
+ after: 'ABC123'
126
220
  }
127
- }.to_json,
128
- headers: { 'Content-Type' => 'application/json' }
221
+ }
222
+ }.to_json
223
+ end
224
+
225
+ before do
226
+ stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts}).to_return(
227
+ body: body,
228
+ headers: response_headers
129
229
  )
130
230
  end
131
231
 
@@ -157,6 +257,29 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
157
257
  end
158
258
 
159
259
  specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
260
+
261
+ describe 'retry behaviour' do
262
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
263
+
264
+ it 'retries timeouts' do
265
+ stub = stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts})
266
+ .to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
267
+
268
+ get_list_response
269
+ expect(stub).to have_been_requested.twice
270
+ end
271
+
272
+ it 'retries 5XX errors' do
273
+ stub = stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts})
274
+ .to_return(status: 502,
275
+ headers: { 'Content-Type' => 'text/html' },
276
+ body: '<html><body>Response from Cloudflare</body></html>')
277
+ .then.to_return(status: 200, headers: response_headers, body: body)
278
+
279
+ get_list_response
280
+ expect(stub).to have_been_requested.twice
281
+ end
282
+ end
160
283
  end
161
284
  end
162
285
 
@@ -182,7 +305,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
182
305
  limit: 1
183
306
  }
184
307
  }.to_json,
185
- headers: { 'Content-Type' => 'application/json' }
308
+ headers: response_headers
186
309
  )
187
310
  end
188
311
 
@@ -207,7 +330,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
207
330
  cursors: {}
208
331
  }
209
332
  }.to_json,
210
- headers: { 'Content-Type' => 'application/json' }
333
+ headers: response_headers
211
334
  )
212
335
  end
213
336
 
@@ -216,6 +339,123 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
216
339
  expect(first_response_stub).to have_been_requested
217
340
  expect(second_response_stub).to have_been_requested
218
341
  end
342
+
343
+ describe 'retry behaviour' do
344
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
345
+
346
+ it 'retries timeouts' do
347
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts$}).to_return(
348
+ body: {
349
+ 'creditor_bank_accounts' => [{
350
+
351
+ 'account_holder_name' => 'account_holder_name-input',
352
+ 'account_number_ending' => 'account_number_ending-input',
353
+ 'bank_name' => 'bank_name-input',
354
+ 'country_code' => 'country_code-input',
355
+ 'created_at' => 'created_at-input',
356
+ 'currency' => 'currency-input',
357
+ 'enabled' => 'enabled-input',
358
+ 'id' => 'id-input',
359
+ 'links' => 'links-input',
360
+ 'metadata' => 'metadata-input'
361
+ }],
362
+ meta: {
363
+ cursors: { after: 'AB345' },
364
+ limit: 1
365
+ }
366
+ }.to_json,
367
+ headers: response_headers
368
+ )
369
+
370
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts\?after=AB345})
371
+ .to_timeout.then
372
+ .to_return(
373
+ body: {
374
+ 'creditor_bank_accounts' => [{
375
+
376
+ 'account_holder_name' => 'account_holder_name-input',
377
+ 'account_number_ending' => 'account_number_ending-input',
378
+ 'bank_name' => 'bank_name-input',
379
+ 'country_code' => 'country_code-input',
380
+ 'created_at' => 'created_at-input',
381
+ 'currency' => 'currency-input',
382
+ 'enabled' => 'enabled-input',
383
+ 'id' => 'id-input',
384
+ 'links' => 'links-input',
385
+ 'metadata' => 'metadata-input'
386
+ }],
387
+ meta: {
388
+ limit: 2,
389
+ cursors: {}
390
+ }
391
+ }.to_json,
392
+ headers: response_headers
393
+ )
394
+
395
+ client.creditor_bank_accounts.all.to_a
396
+
397
+ expect(first_response_stub).to have_been_requested
398
+ expect(second_response_stub).to have_been_requested.twice
399
+ end
400
+
401
+ it 'retries 5XX errors' do
402
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts$}).to_return(
403
+ body: {
404
+ 'creditor_bank_accounts' => [{
405
+
406
+ 'account_holder_name' => 'account_holder_name-input',
407
+ 'account_number_ending' => 'account_number_ending-input',
408
+ 'bank_name' => 'bank_name-input',
409
+ 'country_code' => 'country_code-input',
410
+ 'created_at' => 'created_at-input',
411
+ 'currency' => 'currency-input',
412
+ 'enabled' => 'enabled-input',
413
+ 'id' => 'id-input',
414
+ 'links' => 'links-input',
415
+ 'metadata' => 'metadata-input'
416
+ }],
417
+ meta: {
418
+ cursors: { after: 'AB345' },
419
+ limit: 1
420
+ }
421
+ }.to_json,
422
+ headers: response_headers
423
+ )
424
+
425
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditor_bank_accounts\?after=AB345})
426
+ .to_return(
427
+ status: 502,
428
+ body: '<html><body>Response from Cloudflare</body></html>',
429
+ headers: { 'Content-Type' => 'text/html' }
430
+ ).then.to_return(
431
+ body: {
432
+ 'creditor_bank_accounts' => [{
433
+
434
+ 'account_holder_name' => 'account_holder_name-input',
435
+ 'account_number_ending' => 'account_number_ending-input',
436
+ 'bank_name' => 'bank_name-input',
437
+ 'country_code' => 'country_code-input',
438
+ 'created_at' => 'created_at-input',
439
+ 'currency' => 'currency-input',
440
+ 'enabled' => 'enabled-input',
441
+ 'id' => 'id-input',
442
+ 'links' => 'links-input',
443
+ 'metadata' => 'metadata-input'
444
+ }],
445
+ meta: {
446
+ limit: 2,
447
+ cursors: {}
448
+ }
449
+ }.to_json,
450
+ headers: response_headers
451
+ )
452
+
453
+ client.creditor_bank_accounts.all.to_a
454
+
455
+ expect(first_response_stub).to have_been_requested
456
+ expect(second_response_stub).to have_been_requested.twice
457
+ end
458
+ end
219
459
  end
220
460
 
221
461
  describe '#get' do
@@ -244,7 +484,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
244
484
  'metadata' => 'metadata-input'
245
485
  }
246
486
  }.to_json,
247
- headers: { 'Content-Type' => 'application/json' }
487
+ headers: response_headers
248
488
  )
249
489
  end
250
490
 
@@ -279,7 +519,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
279
519
  'metadata' => 'metadata-input'
280
520
  }
281
521
  }.to_json,
282
- headers: { 'Content-Type' => 'application/json' }
522
+ headers: response_headers
283
523
  )
284
524
  end
285
525
 
@@ -293,7 +533,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
293
533
  stub_url = '/creditor_bank_accounts/:identity'.gsub(':identity', id)
294
534
  stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
295
535
  body: '',
296
- headers: { 'Content-Type' => 'application/json' }
536
+ headers: response_headers
297
537
  )
298
538
  end
299
539
 
@@ -309,6 +549,33 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
309
549
  expect { get_response }.to_not raise_error(/bad URI/)
310
550
  end
311
551
  end
552
+
553
+ describe 'retry behaviour' do
554
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
555
+
556
+ it 'retries timeouts' do
557
+ stub_url = '/creditor_bank_accounts/:identity'.gsub(':identity', id)
558
+
559
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
560
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
561
+
562
+ get_response
563
+ expect(stub).to have_been_requested.twice
564
+ end
565
+
566
+ it 'retries 5XX errors' do
567
+ stub_url = '/creditor_bank_accounts/:identity'.gsub(':identity', id)
568
+
569
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
570
+ .to_return(status: 502,
571
+ headers: { 'Content-Type' => 'text/html' },
572
+ body: '<html><body>Response from Cloudflare</body></html>')
573
+ .then.to_return(status: 200, headers: response_headers)
574
+
575
+ get_response
576
+ expect(stub).to have_been_requested.twice
577
+ end
578
+ end
312
579
  end
313
580
 
314
581
  describe '#disable' do
@@ -335,7 +602,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
335
602
  'metadata' => 'metadata-input'
336
603
  }
337
604
  }.to_json,
338
- headers: { 'Content-Type' => 'application/json' }
605
+ headers: response_headers
339
606
  )
340
607
  end
341
608
 
@@ -345,6 +612,17 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
345
612
  expect(stub).to have_been_requested
346
613
  end
347
614
 
615
+ describe 'retry behaviour' do
616
+ it "doesn't retry errors" do
617
+ stub_url = '/creditor_bank_accounts/:identity/actions/disable'.gsub(':identity', resource_id)
618
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/)
619
+ .to_timeout
620
+
621
+ expect { post_response }.to raise_error(Faraday::TimeoutError)
622
+ expect(stub).to have_been_requested
623
+ end
624
+ end
625
+
348
626
  context 'when the request needs a body and custom header' do
349
627
  let(:body) { { foo: 'bar' } }
350
628
  let(:headers) { { 'Foo' => 'Bar' } }
@@ -375,7 +653,7 @@ describe GoCardlessPro::Services::CreditorBankAccountsService do
375
653
  'metadata' => 'metadata-input'
376
654
  }
377
655
  }.to_json,
378
- headers: { 'Content-Type' => 'application/json' }
656
+ headers: response_headers
379
657
  )
380
658
  end
381
659
  end