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.
- checksums.yaml +4 -4
- data/README.md +13 -4
- data/lib/gocardless_pro.rb +1 -0
- data/lib/gocardless_pro/api_service.rb +2 -0
- data/lib/gocardless_pro/client.rb +4 -3
- data/lib/gocardless_pro/error/invalid_state_error.rb +17 -0
- data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +50 -0
- data/lib/gocardless_pro/request.rb +38 -1
- data/lib/gocardless_pro/resources/creditor.rb +2 -2
- data/lib/gocardless_pro/resources/creditor_bank_account.rb +11 -11
- data/lib/gocardless_pro/resources/customer_bank_account.rb +2 -2
- data/lib/gocardless_pro/resources/event.rb +2 -2
- data/lib/gocardless_pro/resources/mandate.rb +2 -2
- data/lib/gocardless_pro/resources/payment.rb +7 -7
- data/lib/gocardless_pro/resources/payout.rb +7 -6
- data/lib/gocardless_pro/resources/redirect_flow.rb +2 -2
- data/lib/gocardless_pro/resources/refund.rb +2 -2
- data/lib/gocardless_pro/resources/subscription.rb +2 -2
- data/lib/gocardless_pro/response.rb +2 -54
- data/lib/gocardless_pro/services/bank_details_lookups_service.rb +3 -0
- data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +31 -2
- data/lib/gocardless_pro/services/creditors_service.rb +21 -1
- data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +34 -2
- data/lib/gocardless_pro/services/customers_service.rb +21 -1
- data/lib/gocardless_pro/services/events_service.rb +5 -0
- data/lib/gocardless_pro/services/mandate_pdfs_service.rb +3 -0
- data/lib/gocardless_pro/services/mandates_service.rb +47 -3
- data/lib/gocardless_pro/services/payments_service.rb +47 -3
- data/lib/gocardless_pro/services/payouts_service.rb +5 -0
- data/lib/gocardless_pro/services/redirect_flows_service.rb +28 -2
- data/lib/gocardless_pro/services/refunds_service.rb +21 -1
- data/lib/gocardless_pro/services/subscriptions_service.rb +34 -2
- data/lib/gocardless_pro/version.rb +1 -1
- data/spec/api_service_spec.rb +106 -0
- data/spec/middlewares/raise_gocardless_errors_spec.rb +98 -0
- data/spec/resources/bank_details_lookup_spec.rb +102 -19
- data/spec/resources/creditor_bank_account_spec.rb +416 -40
- data/spec/resources/creditor_spec.rb +414 -53
- data/spec/resources/customer_bank_account_spec.rb +452 -40
- data/spec/resources/customer_spec.rb +457 -45
- data/spec/resources/event_spec.rb +171 -72
- data/spec/resources/mandate_pdf_spec.rb +100 -17
- data/spec/resources/mandate_spec.rb +501 -44
- data/spec/resources/payment_spec.rb +531 -48
- data/spec/resources/payout_spec.rb +189 -45
- data/spec/resources/redirect_flow_spec.rb +277 -43
- data/spec/resources/refund_spec.rb +349 -34
- data/spec/resources/subscription_spec.rb +531 -53
- data/spec/response_spec.rb +12 -79
- data/spec/services/bank_details_lookups_service_spec.rb +67 -2
- data/spec/services/creditor_bank_accounts_service_spec.rb +309 -31
- data/spec/services/creditors_service_spec.rb +343 -33
- data/spec/services/customer_bank_accounts_service_spec.rb +335 -32
- data/spec/services/customers_service_spec.rb +364 -36
- data/spec/services/events_service_spec.rb +185 -24
- data/spec/services/mandate_pdfs_service_spec.rb +66 -2
- data/spec/services/mandates_service_spec.rb +341 -33
- data/spec/services/payments_service_spec.rb +355 -35
- data/spec/services/payouts_service_spec.rb +206 -26
- data/spec/services/redirect_flows_service_spec.rb +137 -7
- data/spec/services/refunds_service_spec.rb +301 -27
- data/spec/services/subscriptions_service_spec.rb +377 -38
- metadata +6 -3
@@ -7,6 +7,8 @@ describe GoCardlessPro::Services::RefundsService 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.refunds.create(params: new_resource) }
|
12
14
|
context 'with a valid request' do
|
@@ -55,13 +57,36 @@ describe GoCardlessPro::Services::RefundsService do
|
|
55
57
|
}
|
56
58
|
|
57
59
|
}.to_json,
|
58
|
-
headers:
|
60
|
+
headers: response_headers
|
59
61
|
)
|
60
62
|
end
|
61
63
|
|
62
64
|
it 'creates and returns the resource' do
|
63
65
|
expect(post_create_response).to be_a(GoCardlessPro::Resources::Refund)
|
64
66
|
end
|
67
|
+
|
68
|
+
describe 'retry behaviour' do
|
69
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
70
|
+
|
71
|
+
it 'retries timeouts' do
|
72
|
+
stub = stub_request(:post, %r{.*api.gocardless.com/refunds})
|
73
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers)
|
74
|
+
|
75
|
+
post_create_response
|
76
|
+
expect(stub).to have_been_requested.twice
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'retries 5XX errors' do
|
80
|
+
stub = stub_request(:post, %r{.*api.gocardless.com/refunds})
|
81
|
+
.to_return(status: 502,
|
82
|
+
headers: { 'Content-Type' => 'text/html' },
|
83
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
84
|
+
.then.to_return(status: 200, headers: response_headers)
|
85
|
+
|
86
|
+
post_create_response
|
87
|
+
expect(stub).to have_been_requested.twice
|
88
|
+
end
|
89
|
+
end
|
65
90
|
end
|
66
91
|
|
67
92
|
context 'with a request that returns a validation error' do
|
@@ -78,7 +103,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
78
103
|
]
|
79
104
|
}
|
80
105
|
}.to_json,
|
81
|
-
headers:
|
106
|
+
headers: response_headers,
|
82
107
|
status: 422
|
83
108
|
)
|
84
109
|
end
|
@@ -87,33 +112,102 @@ describe GoCardlessPro::Services::RefundsService do
|
|
87
112
|
expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
|
88
113
|
end
|
89
114
|
end
|
115
|
+
|
116
|
+
context 'with a request that returns an idempotent creation conflict error' do
|
117
|
+
let(:id) { 'ID123' }
|
118
|
+
|
119
|
+
let(:new_resource) do
|
120
|
+
{
|
121
|
+
|
122
|
+
'amount' => 'amount-input',
|
123
|
+
'created_at' => 'created_at-input',
|
124
|
+
'currency' => 'currency-input',
|
125
|
+
'id' => 'id-input',
|
126
|
+
'links' => 'links-input',
|
127
|
+
'metadata' => 'metadata-input',
|
128
|
+
'reference' => 'reference-input'
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
let!(:post_stub) do
|
133
|
+
stub_request(:post, %r{.*api.gocardless.com/refunds}).to_return(
|
134
|
+
body: {
|
135
|
+
error: {
|
136
|
+
type: 'invalid_state',
|
137
|
+
code: 409,
|
138
|
+
errors: [
|
139
|
+
{
|
140
|
+
message: 'A resource has already been created with this idempotency key',
|
141
|
+
reason: 'idempotent_creation_conflict',
|
142
|
+
links: {
|
143
|
+
conflicting_resource_id: id
|
144
|
+
}
|
145
|
+
}
|
146
|
+
]
|
147
|
+
}
|
148
|
+
}.to_json,
|
149
|
+
headers: response_headers,
|
150
|
+
status: 409
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
let!(:get_stub) do
|
155
|
+
stub_url = "/refunds/#{id}"
|
156
|
+
stub_request(:get, /.*api.gocardless.com#{stub_url}/)
|
157
|
+
.to_return(
|
158
|
+
body: {
|
159
|
+
'refunds' => {
|
160
|
+
|
161
|
+
'amount' => 'amount-input',
|
162
|
+
'created_at' => 'created_at-input',
|
163
|
+
'currency' => 'currency-input',
|
164
|
+
'id' => 'id-input',
|
165
|
+
'links' => 'links-input',
|
166
|
+
'metadata' => 'metadata-input',
|
167
|
+
'reference' => 'reference-input'
|
168
|
+
}
|
169
|
+
}.to_json,
|
170
|
+
headers: response_headers
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'fetches the already-created resource' do
|
175
|
+
post_create_response
|
176
|
+
expect(post_stub).to have_been_requested
|
177
|
+
expect(get_stub).to have_been_requested
|
178
|
+
end
|
179
|
+
end
|
90
180
|
end
|
91
181
|
|
92
182
|
describe '#list' do
|
93
183
|
describe 'with no filters' do
|
94
184
|
subject(:get_list_response) { client.refunds.list }
|
95
185
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
'refunds' => [{
|
186
|
+
let(:body) do
|
187
|
+
{
|
188
|
+
'refunds' => [{
|
100
189
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
}
|
190
|
+
'amount' => 'amount-input',
|
191
|
+
'created_at' => 'created_at-input',
|
192
|
+
'currency' => 'currency-input',
|
193
|
+
'id' => 'id-input',
|
194
|
+
'links' => 'links-input',
|
195
|
+
'metadata' => 'metadata-input',
|
196
|
+
'reference' => 'reference-input'
|
197
|
+
}],
|
198
|
+
meta: {
|
199
|
+
cursors: {
|
200
|
+
before: nil,
|
201
|
+
after: 'ABC123'
|
114
202
|
}
|
115
|
-
}
|
116
|
-
|
203
|
+
}
|
204
|
+
}.to_json
|
205
|
+
end
|
206
|
+
|
207
|
+
before do
|
208
|
+
stub_request(:get, %r{.*api.gocardless.com/refunds}).to_return(
|
209
|
+
body: body,
|
210
|
+
headers: response_headers
|
117
211
|
)
|
118
212
|
end
|
119
213
|
|
@@ -139,6 +233,29 @@ describe GoCardlessPro::Services::RefundsService do
|
|
139
233
|
end
|
140
234
|
|
141
235
|
specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
|
236
|
+
|
237
|
+
describe 'retry behaviour' do
|
238
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
239
|
+
|
240
|
+
it 'retries timeouts' do
|
241
|
+
stub = stub_request(:get, %r{.*api.gocardless.com/refunds})
|
242
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
|
243
|
+
|
244
|
+
get_list_response
|
245
|
+
expect(stub).to have_been_requested.twice
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'retries 5XX errors' do
|
249
|
+
stub = stub_request(:get, %r{.*api.gocardless.com/refunds})
|
250
|
+
.to_return(status: 502,
|
251
|
+
headers: { 'Content-Type' => 'text/html' },
|
252
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
253
|
+
.then.to_return(status: 200, headers: response_headers, body: body)
|
254
|
+
|
255
|
+
get_list_response
|
256
|
+
expect(stub).to have_been_requested.twice
|
257
|
+
end
|
258
|
+
end
|
142
259
|
end
|
143
260
|
end
|
144
261
|
|
@@ -161,7 +278,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
161
278
|
limit: 1
|
162
279
|
}
|
163
280
|
}.to_json,
|
164
|
-
headers:
|
281
|
+
headers: response_headers
|
165
282
|
)
|
166
283
|
end
|
167
284
|
|
@@ -183,7 +300,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
183
300
|
cursors: {}
|
184
301
|
}
|
185
302
|
}.to_json,
|
186
|
-
headers:
|
303
|
+
headers: response_headers
|
187
304
|
)
|
188
305
|
end
|
189
306
|
|
@@ -192,6 +309,111 @@ describe GoCardlessPro::Services::RefundsService do
|
|
192
309
|
expect(first_response_stub).to have_been_requested
|
193
310
|
expect(second_response_stub).to have_been_requested
|
194
311
|
end
|
312
|
+
|
313
|
+
describe 'retry behaviour' do
|
314
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
315
|
+
|
316
|
+
it 'retries timeouts' do
|
317
|
+
first_response_stub = stub_request(:get, %r{.*api.gocardless.com/refunds$}).to_return(
|
318
|
+
body: {
|
319
|
+
'refunds' => [{
|
320
|
+
|
321
|
+
'amount' => 'amount-input',
|
322
|
+
'created_at' => 'created_at-input',
|
323
|
+
'currency' => 'currency-input',
|
324
|
+
'id' => 'id-input',
|
325
|
+
'links' => 'links-input',
|
326
|
+
'metadata' => 'metadata-input',
|
327
|
+
'reference' => 'reference-input'
|
328
|
+
}],
|
329
|
+
meta: {
|
330
|
+
cursors: { after: 'AB345' },
|
331
|
+
limit: 1
|
332
|
+
}
|
333
|
+
}.to_json,
|
334
|
+
headers: response_headers
|
335
|
+
)
|
336
|
+
|
337
|
+
second_response_stub = stub_request(:get, %r{.*api.gocardless.com/refunds\?after=AB345})
|
338
|
+
.to_timeout.then
|
339
|
+
.to_return(
|
340
|
+
body: {
|
341
|
+
'refunds' => [{
|
342
|
+
|
343
|
+
'amount' => 'amount-input',
|
344
|
+
'created_at' => 'created_at-input',
|
345
|
+
'currency' => 'currency-input',
|
346
|
+
'id' => 'id-input',
|
347
|
+
'links' => 'links-input',
|
348
|
+
'metadata' => 'metadata-input',
|
349
|
+
'reference' => 'reference-input'
|
350
|
+
}],
|
351
|
+
meta: {
|
352
|
+
limit: 2,
|
353
|
+
cursors: {}
|
354
|
+
}
|
355
|
+
}.to_json,
|
356
|
+
headers: response_headers
|
357
|
+
)
|
358
|
+
|
359
|
+
client.refunds.all.to_a
|
360
|
+
|
361
|
+
expect(first_response_stub).to have_been_requested
|
362
|
+
expect(second_response_stub).to have_been_requested.twice
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'retries 5XX errors' do
|
366
|
+
first_response_stub = stub_request(:get, %r{.*api.gocardless.com/refunds$}).to_return(
|
367
|
+
body: {
|
368
|
+
'refunds' => [{
|
369
|
+
|
370
|
+
'amount' => 'amount-input',
|
371
|
+
'created_at' => 'created_at-input',
|
372
|
+
'currency' => 'currency-input',
|
373
|
+
'id' => 'id-input',
|
374
|
+
'links' => 'links-input',
|
375
|
+
'metadata' => 'metadata-input',
|
376
|
+
'reference' => 'reference-input'
|
377
|
+
}],
|
378
|
+
meta: {
|
379
|
+
cursors: { after: 'AB345' },
|
380
|
+
limit: 1
|
381
|
+
}
|
382
|
+
}.to_json,
|
383
|
+
headers: response_headers
|
384
|
+
)
|
385
|
+
|
386
|
+
second_response_stub = stub_request(:get, %r{.*api.gocardless.com/refunds\?after=AB345})
|
387
|
+
.to_return(
|
388
|
+
status: 502,
|
389
|
+
body: '<html><body>Response from Cloudflare</body></html>',
|
390
|
+
headers: { 'Content-Type' => 'text/html' }
|
391
|
+
).then.to_return(
|
392
|
+
body: {
|
393
|
+
'refunds' => [{
|
394
|
+
|
395
|
+
'amount' => 'amount-input',
|
396
|
+
'created_at' => 'created_at-input',
|
397
|
+
'currency' => 'currency-input',
|
398
|
+
'id' => 'id-input',
|
399
|
+
'links' => 'links-input',
|
400
|
+
'metadata' => 'metadata-input',
|
401
|
+
'reference' => 'reference-input'
|
402
|
+
}],
|
403
|
+
meta: {
|
404
|
+
limit: 2,
|
405
|
+
cursors: {}
|
406
|
+
}
|
407
|
+
}.to_json,
|
408
|
+
headers: response_headers
|
409
|
+
)
|
410
|
+
|
411
|
+
client.refunds.all.to_a
|
412
|
+
|
413
|
+
expect(first_response_stub).to have_been_requested
|
414
|
+
expect(second_response_stub).to have_been_requested.twice
|
415
|
+
end
|
416
|
+
end
|
195
417
|
end
|
196
418
|
|
197
419
|
describe '#get' do
|
@@ -217,7 +439,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
217
439
|
'reference' => 'reference-input'
|
218
440
|
}
|
219
441
|
}.to_json,
|
220
|
-
headers:
|
442
|
+
headers: response_headers
|
221
443
|
)
|
222
444
|
end
|
223
445
|
|
@@ -249,7 +471,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
249
471
|
'reference' => 'reference-input'
|
250
472
|
}
|
251
473
|
}.to_json,
|
252
|
-
headers:
|
474
|
+
headers: response_headers
|
253
475
|
)
|
254
476
|
end
|
255
477
|
|
@@ -263,7 +485,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
263
485
|
stub_url = '/refunds/:identity'.gsub(':identity', id)
|
264
486
|
stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
|
265
487
|
body: '',
|
266
|
-
headers:
|
488
|
+
headers: response_headers
|
267
489
|
)
|
268
490
|
end
|
269
491
|
|
@@ -279,6 +501,33 @@ describe GoCardlessPro::Services::RefundsService do
|
|
279
501
|
expect { get_response }.to_not raise_error(/bad URI/)
|
280
502
|
end
|
281
503
|
end
|
504
|
+
|
505
|
+
describe 'retry behaviour' do
|
506
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
507
|
+
|
508
|
+
it 'retries timeouts' do
|
509
|
+
stub_url = '/refunds/:identity'.gsub(':identity', id)
|
510
|
+
|
511
|
+
stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
|
512
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers)
|
513
|
+
|
514
|
+
get_response
|
515
|
+
expect(stub).to have_been_requested.twice
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'retries 5XX errors' do
|
519
|
+
stub_url = '/refunds/:identity'.gsub(':identity', id)
|
520
|
+
|
521
|
+
stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
|
522
|
+
.to_return(status: 502,
|
523
|
+
headers: { 'Content-Type' => 'text/html' },
|
524
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
525
|
+
.then.to_return(status: 200, headers: response_headers)
|
526
|
+
|
527
|
+
get_response
|
528
|
+
expect(stub).to have_been_requested.twice
|
529
|
+
end
|
530
|
+
end
|
282
531
|
end
|
283
532
|
|
284
533
|
describe '#update' do
|
@@ -303,7 +552,7 @@ describe GoCardlessPro::Services::RefundsService do
|
|
303
552
|
'reference' => 'reference-input'
|
304
553
|
}
|
305
554
|
}.to_json,
|
306
|
-
headers:
|
555
|
+
headers: response_headers
|
307
556
|
)
|
308
557
|
end
|
309
558
|
|
@@ -311,6 +560,31 @@ describe GoCardlessPro::Services::RefundsService do
|
|
311
560
|
expect(put_update_response).to be_a(GoCardlessPro::Resources::Refund)
|
312
561
|
expect(stub).to have_been_requested
|
313
562
|
end
|
563
|
+
|
564
|
+
describe 'retry behaviour' do
|
565
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
566
|
+
|
567
|
+
it 'retries timeouts' do
|
568
|
+
stub_url = '/refunds/:identity'.gsub(':identity', id)
|
569
|
+
stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
|
570
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers)
|
571
|
+
|
572
|
+
put_update_response
|
573
|
+
expect(stub).to have_been_requested.twice
|
574
|
+
end
|
575
|
+
|
576
|
+
it 'retries 5XX errors' do
|
577
|
+
stub_url = '/refunds/:identity'.gsub(':identity', id)
|
578
|
+
stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
|
579
|
+
.to_return(status: 502,
|
580
|
+
headers: { 'Content-Type' => 'text/html' },
|
581
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
582
|
+
.then.to_return(status: 200, headers: response_headers)
|
583
|
+
|
584
|
+
put_update_response
|
585
|
+
expect(stub).to have_been_requested.twice
|
586
|
+
end
|
587
|
+
end
|
314
588
|
end
|
315
589
|
end
|
316
590
|
end
|
@@ -7,6 +7,8 @@ describe GoCardlessPro::Services::SubscriptionsService 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.subscriptions.create(params: new_resource) }
|
12
14
|
context 'with a valid request' do
|
@@ -82,13 +84,36 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
82
84
|
}
|
83
85
|
|
84
86
|
}.to_json,
|
85
|
-
headers:
|
87
|
+
headers: response_headers
|
86
88
|
)
|
87
89
|
end
|
88
90
|
|
89
91
|
it 'creates and returns the resource' do
|
90
92
|
expect(post_create_response).to be_a(GoCardlessPro::Resources::Subscription)
|
91
93
|
end
|
94
|
+
|
95
|
+
describe 'retry behaviour' do
|
96
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
97
|
+
|
98
|
+
it 'retries timeouts' do
|
99
|
+
stub = stub_request(:post, %r{.*api.gocardless.com/subscriptions})
|
100
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers)
|
101
|
+
|
102
|
+
post_create_response
|
103
|
+
expect(stub).to have_been_requested.twice
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'retries 5XX errors' do
|
107
|
+
stub = stub_request(:post, %r{.*api.gocardless.com/subscriptions})
|
108
|
+
.to_return(status: 502,
|
109
|
+
headers: { 'Content-Type' => 'text/html' },
|
110
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
111
|
+
.then.to_return(status: 200, headers: response_headers)
|
112
|
+
|
113
|
+
post_create_response
|
114
|
+
expect(stub).to have_been_requested.twice
|
115
|
+
end
|
116
|
+
end
|
92
117
|
end
|
93
118
|
|
94
119
|
context 'with a request that returns a validation error' do
|
@@ -105,7 +130,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
105
130
|
]
|
106
131
|
}
|
107
132
|
}.to_json,
|
108
|
-
headers:
|
133
|
+
headers: response_headers,
|
109
134
|
status: 422
|
110
135
|
)
|
111
136
|
end
|
@@ -114,42 +139,129 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
114
139
|
expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
|
115
140
|
end
|
116
141
|
end
|
142
|
+
|
143
|
+
context 'with a request that returns an idempotent creation conflict error' do
|
144
|
+
let(:id) { 'ID123' }
|
145
|
+
|
146
|
+
let(:new_resource) do
|
147
|
+
{
|
148
|
+
|
149
|
+
'amount' => 'amount-input',
|
150
|
+
'created_at' => 'created_at-input',
|
151
|
+
'currency' => 'currency-input',
|
152
|
+
'day_of_month' => 'day_of_month-input',
|
153
|
+
'end_date' => 'end_date-input',
|
154
|
+
'id' => 'id-input',
|
155
|
+
'interval' => 'interval-input',
|
156
|
+
'interval_unit' => 'interval_unit-input',
|
157
|
+
'links' => 'links-input',
|
158
|
+
'metadata' => 'metadata-input',
|
159
|
+
'month' => 'month-input',
|
160
|
+
'name' => 'name-input',
|
161
|
+
'payment_reference' => 'payment_reference-input',
|
162
|
+
'start_date' => 'start_date-input',
|
163
|
+
'status' => 'status-input',
|
164
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
let!(:post_stub) do
|
169
|
+
stub_request(:post, %r{.*api.gocardless.com/subscriptions}).to_return(
|
170
|
+
body: {
|
171
|
+
error: {
|
172
|
+
type: 'invalid_state',
|
173
|
+
code: 409,
|
174
|
+
errors: [
|
175
|
+
{
|
176
|
+
message: 'A resource has already been created with this idempotency key',
|
177
|
+
reason: 'idempotent_creation_conflict',
|
178
|
+
links: {
|
179
|
+
conflicting_resource_id: id
|
180
|
+
}
|
181
|
+
}
|
182
|
+
]
|
183
|
+
}
|
184
|
+
}.to_json,
|
185
|
+
headers: response_headers,
|
186
|
+
status: 409
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
let!(:get_stub) do
|
191
|
+
stub_url = "/subscriptions/#{id}"
|
192
|
+
stub_request(:get, /.*api.gocardless.com#{stub_url}/)
|
193
|
+
.to_return(
|
194
|
+
body: {
|
195
|
+
'subscriptions' => {
|
196
|
+
|
197
|
+
'amount' => 'amount-input',
|
198
|
+
'created_at' => 'created_at-input',
|
199
|
+
'currency' => 'currency-input',
|
200
|
+
'day_of_month' => 'day_of_month-input',
|
201
|
+
'end_date' => 'end_date-input',
|
202
|
+
'id' => 'id-input',
|
203
|
+
'interval' => 'interval-input',
|
204
|
+
'interval_unit' => 'interval_unit-input',
|
205
|
+
'links' => 'links-input',
|
206
|
+
'metadata' => 'metadata-input',
|
207
|
+
'month' => 'month-input',
|
208
|
+
'name' => 'name-input',
|
209
|
+
'payment_reference' => 'payment_reference-input',
|
210
|
+
'start_date' => 'start_date-input',
|
211
|
+
'status' => 'status-input',
|
212
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
213
|
+
}
|
214
|
+
}.to_json,
|
215
|
+
headers: response_headers
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'fetches the already-created resource' do
|
220
|
+
post_create_response
|
221
|
+
expect(post_stub).to have_been_requested
|
222
|
+
expect(get_stub).to have_been_requested
|
223
|
+
end
|
224
|
+
end
|
117
225
|
end
|
118
226
|
|
119
227
|
describe '#list' do
|
120
228
|
describe 'with no filters' do
|
121
229
|
subject(:get_list_response) { client.subscriptions.list }
|
122
230
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
'subscriptions' => [{
|
231
|
+
let(:body) do
|
232
|
+
{
|
233
|
+
'subscriptions' => [{
|
127
234
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
}
|
235
|
+
'amount' => 'amount-input',
|
236
|
+
'created_at' => 'created_at-input',
|
237
|
+
'currency' => 'currency-input',
|
238
|
+
'day_of_month' => 'day_of_month-input',
|
239
|
+
'end_date' => 'end_date-input',
|
240
|
+
'id' => 'id-input',
|
241
|
+
'interval' => 'interval-input',
|
242
|
+
'interval_unit' => 'interval_unit-input',
|
243
|
+
'links' => 'links-input',
|
244
|
+
'metadata' => 'metadata-input',
|
245
|
+
'month' => 'month-input',
|
246
|
+
'name' => 'name-input',
|
247
|
+
'payment_reference' => 'payment_reference-input',
|
248
|
+
'start_date' => 'start_date-input',
|
249
|
+
'status' => 'status-input',
|
250
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
251
|
+
}],
|
252
|
+
meta: {
|
253
|
+
cursors: {
|
254
|
+
before: nil,
|
255
|
+
after: 'ABC123'
|
150
256
|
}
|
151
|
-
}
|
152
|
-
|
257
|
+
}
|
258
|
+
}.to_json
|
259
|
+
end
|
260
|
+
|
261
|
+
before do
|
262
|
+
stub_request(:get, %r{.*api.gocardless.com/subscriptions}).to_return(
|
263
|
+
body: body,
|
264
|
+
headers: response_headers
|
153
265
|
)
|
154
266
|
end
|
155
267
|
|
@@ -193,6 +305,29 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
193
305
|
end
|
194
306
|
|
195
307
|
specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
|
308
|
+
|
309
|
+
describe 'retry behaviour' do
|
310
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
311
|
+
|
312
|
+
it 'retries timeouts' do
|
313
|
+
stub = stub_request(:get, %r{.*api.gocardless.com/subscriptions})
|
314
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
|
315
|
+
|
316
|
+
get_list_response
|
317
|
+
expect(stub).to have_been_requested.twice
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'retries 5XX errors' do
|
321
|
+
stub = stub_request(:get, %r{.*api.gocardless.com/subscriptions})
|
322
|
+
.to_return(status: 502,
|
323
|
+
headers: { 'Content-Type' => 'text/html' },
|
324
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
325
|
+
.then.to_return(status: 200, headers: response_headers, body: body)
|
326
|
+
|
327
|
+
get_list_response
|
328
|
+
expect(stub).to have_been_requested.twice
|
329
|
+
end
|
330
|
+
end
|
196
331
|
end
|
197
332
|
end
|
198
333
|
|
@@ -224,7 +359,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
224
359
|
limit: 1
|
225
360
|
}
|
226
361
|
}.to_json,
|
227
|
-
headers:
|
362
|
+
headers: response_headers
|
228
363
|
)
|
229
364
|
end
|
230
365
|
|
@@ -255,7 +390,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
255
390
|
cursors: {}
|
256
391
|
}
|
257
392
|
}.to_json,
|
258
|
-
headers:
|
393
|
+
headers: response_headers
|
259
394
|
)
|
260
395
|
end
|
261
396
|
|
@@ -264,6 +399,147 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
264
399
|
expect(first_response_stub).to have_been_requested
|
265
400
|
expect(second_response_stub).to have_been_requested
|
266
401
|
end
|
402
|
+
|
403
|
+
describe 'retry behaviour' do
|
404
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
405
|
+
|
406
|
+
it 'retries timeouts' do
|
407
|
+
first_response_stub = stub_request(:get, %r{.*api.gocardless.com/subscriptions$}).to_return(
|
408
|
+
body: {
|
409
|
+
'subscriptions' => [{
|
410
|
+
|
411
|
+
'amount' => 'amount-input',
|
412
|
+
'created_at' => 'created_at-input',
|
413
|
+
'currency' => 'currency-input',
|
414
|
+
'day_of_month' => 'day_of_month-input',
|
415
|
+
'end_date' => 'end_date-input',
|
416
|
+
'id' => 'id-input',
|
417
|
+
'interval' => 'interval-input',
|
418
|
+
'interval_unit' => 'interval_unit-input',
|
419
|
+
'links' => 'links-input',
|
420
|
+
'metadata' => 'metadata-input',
|
421
|
+
'month' => 'month-input',
|
422
|
+
'name' => 'name-input',
|
423
|
+
'payment_reference' => 'payment_reference-input',
|
424
|
+
'start_date' => 'start_date-input',
|
425
|
+
'status' => 'status-input',
|
426
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
427
|
+
}],
|
428
|
+
meta: {
|
429
|
+
cursors: { after: 'AB345' },
|
430
|
+
limit: 1
|
431
|
+
}
|
432
|
+
}.to_json,
|
433
|
+
headers: response_headers
|
434
|
+
)
|
435
|
+
|
436
|
+
second_response_stub = stub_request(:get, %r{.*api.gocardless.com/subscriptions\?after=AB345})
|
437
|
+
.to_timeout.then
|
438
|
+
.to_return(
|
439
|
+
body: {
|
440
|
+
'subscriptions' => [{
|
441
|
+
|
442
|
+
'amount' => 'amount-input',
|
443
|
+
'created_at' => 'created_at-input',
|
444
|
+
'currency' => 'currency-input',
|
445
|
+
'day_of_month' => 'day_of_month-input',
|
446
|
+
'end_date' => 'end_date-input',
|
447
|
+
'id' => 'id-input',
|
448
|
+
'interval' => 'interval-input',
|
449
|
+
'interval_unit' => 'interval_unit-input',
|
450
|
+
'links' => 'links-input',
|
451
|
+
'metadata' => 'metadata-input',
|
452
|
+
'month' => 'month-input',
|
453
|
+
'name' => 'name-input',
|
454
|
+
'payment_reference' => 'payment_reference-input',
|
455
|
+
'start_date' => 'start_date-input',
|
456
|
+
'status' => 'status-input',
|
457
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
458
|
+
}],
|
459
|
+
meta: {
|
460
|
+
limit: 2,
|
461
|
+
cursors: {}
|
462
|
+
}
|
463
|
+
}.to_json,
|
464
|
+
headers: response_headers
|
465
|
+
)
|
466
|
+
|
467
|
+
client.subscriptions.all.to_a
|
468
|
+
|
469
|
+
expect(first_response_stub).to have_been_requested
|
470
|
+
expect(second_response_stub).to have_been_requested.twice
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'retries 5XX errors' do
|
474
|
+
first_response_stub = stub_request(:get, %r{.*api.gocardless.com/subscriptions$}).to_return(
|
475
|
+
body: {
|
476
|
+
'subscriptions' => [{
|
477
|
+
|
478
|
+
'amount' => 'amount-input',
|
479
|
+
'created_at' => 'created_at-input',
|
480
|
+
'currency' => 'currency-input',
|
481
|
+
'day_of_month' => 'day_of_month-input',
|
482
|
+
'end_date' => 'end_date-input',
|
483
|
+
'id' => 'id-input',
|
484
|
+
'interval' => 'interval-input',
|
485
|
+
'interval_unit' => 'interval_unit-input',
|
486
|
+
'links' => 'links-input',
|
487
|
+
'metadata' => 'metadata-input',
|
488
|
+
'month' => 'month-input',
|
489
|
+
'name' => 'name-input',
|
490
|
+
'payment_reference' => 'payment_reference-input',
|
491
|
+
'start_date' => 'start_date-input',
|
492
|
+
'status' => 'status-input',
|
493
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
494
|
+
}],
|
495
|
+
meta: {
|
496
|
+
cursors: { after: 'AB345' },
|
497
|
+
limit: 1
|
498
|
+
}
|
499
|
+
}.to_json,
|
500
|
+
headers: response_headers
|
501
|
+
)
|
502
|
+
|
503
|
+
second_response_stub = stub_request(:get, %r{.*api.gocardless.com/subscriptions\?after=AB345})
|
504
|
+
.to_return(
|
505
|
+
status: 502,
|
506
|
+
body: '<html><body>Response from Cloudflare</body></html>',
|
507
|
+
headers: { 'Content-Type' => 'text/html' }
|
508
|
+
).then.to_return(
|
509
|
+
body: {
|
510
|
+
'subscriptions' => [{
|
511
|
+
|
512
|
+
'amount' => 'amount-input',
|
513
|
+
'created_at' => 'created_at-input',
|
514
|
+
'currency' => 'currency-input',
|
515
|
+
'day_of_month' => 'day_of_month-input',
|
516
|
+
'end_date' => 'end_date-input',
|
517
|
+
'id' => 'id-input',
|
518
|
+
'interval' => 'interval-input',
|
519
|
+
'interval_unit' => 'interval_unit-input',
|
520
|
+
'links' => 'links-input',
|
521
|
+
'metadata' => 'metadata-input',
|
522
|
+
'month' => 'month-input',
|
523
|
+
'name' => 'name-input',
|
524
|
+
'payment_reference' => 'payment_reference-input',
|
525
|
+
'start_date' => 'start_date-input',
|
526
|
+
'status' => 'status-input',
|
527
|
+
'upcoming_payments' => 'upcoming_payments-input'
|
528
|
+
}],
|
529
|
+
meta: {
|
530
|
+
limit: 2,
|
531
|
+
cursors: {}
|
532
|
+
}
|
533
|
+
}.to_json,
|
534
|
+
headers: response_headers
|
535
|
+
)
|
536
|
+
|
537
|
+
client.subscriptions.all.to_a
|
538
|
+
|
539
|
+
expect(first_response_stub).to have_been_requested
|
540
|
+
expect(second_response_stub).to have_been_requested.twice
|
541
|
+
end
|
542
|
+
end
|
267
543
|
end
|
268
544
|
|
269
545
|
describe '#get' do
|
@@ -298,7 +574,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
298
574
|
'upcoming_payments' => 'upcoming_payments-input'
|
299
575
|
}
|
300
576
|
}.to_json,
|
301
|
-
headers:
|
577
|
+
headers: response_headers
|
302
578
|
)
|
303
579
|
end
|
304
580
|
|
@@ -339,7 +615,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
339
615
|
'upcoming_payments' => 'upcoming_payments-input'
|
340
616
|
}
|
341
617
|
}.to_json,
|
342
|
-
headers:
|
618
|
+
headers: response_headers
|
343
619
|
)
|
344
620
|
end
|
345
621
|
|
@@ -353,7 +629,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
353
629
|
stub_url = '/subscriptions/:identity'.gsub(':identity', id)
|
354
630
|
stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
|
355
631
|
body: '',
|
356
|
-
headers:
|
632
|
+
headers: response_headers
|
357
633
|
)
|
358
634
|
end
|
359
635
|
|
@@ -369,6 +645,33 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
369
645
|
expect { get_response }.to_not raise_error(/bad URI/)
|
370
646
|
end
|
371
647
|
end
|
648
|
+
|
649
|
+
describe 'retry behaviour' do
|
650
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
651
|
+
|
652
|
+
it 'retries timeouts' do
|
653
|
+
stub_url = '/subscriptions/:identity'.gsub(':identity', id)
|
654
|
+
|
655
|
+
stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
|
656
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers)
|
657
|
+
|
658
|
+
get_response
|
659
|
+
expect(stub).to have_been_requested.twice
|
660
|
+
end
|
661
|
+
|
662
|
+
it 'retries 5XX errors' do
|
663
|
+
stub_url = '/subscriptions/:identity'.gsub(':identity', id)
|
664
|
+
|
665
|
+
stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
|
666
|
+
.to_return(status: 502,
|
667
|
+
headers: { 'Content-Type' => 'text/html' },
|
668
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
669
|
+
.then.to_return(status: 200, headers: response_headers)
|
670
|
+
|
671
|
+
get_response
|
672
|
+
expect(stub).to have_been_requested.twice
|
673
|
+
end
|
674
|
+
end
|
372
675
|
end
|
373
676
|
|
374
677
|
describe '#update' do
|
@@ -402,7 +705,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
402
705
|
'upcoming_payments' => 'upcoming_payments-input'
|
403
706
|
}
|
404
707
|
}.to_json,
|
405
|
-
headers:
|
708
|
+
headers: response_headers
|
406
709
|
)
|
407
710
|
end
|
408
711
|
|
@@ -410,6 +713,31 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
410
713
|
expect(put_update_response).to be_a(GoCardlessPro::Resources::Subscription)
|
411
714
|
expect(stub).to have_been_requested
|
412
715
|
end
|
716
|
+
|
717
|
+
describe 'retry behaviour' do
|
718
|
+
before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
|
719
|
+
|
720
|
+
it 'retries timeouts' do
|
721
|
+
stub_url = '/subscriptions/:identity'.gsub(':identity', id)
|
722
|
+
stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
|
723
|
+
.to_timeout.then.to_return(status: 200, headers: response_headers)
|
724
|
+
|
725
|
+
put_update_response
|
726
|
+
expect(stub).to have_been_requested.twice
|
727
|
+
end
|
728
|
+
|
729
|
+
it 'retries 5XX errors' do
|
730
|
+
stub_url = '/subscriptions/:identity'.gsub(':identity', id)
|
731
|
+
stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
|
732
|
+
.to_return(status: 502,
|
733
|
+
headers: { 'Content-Type' => 'text/html' },
|
734
|
+
body: '<html><body>Response from Cloudflare</body></html>')
|
735
|
+
.then.to_return(status: 200, headers: response_headers)
|
736
|
+
|
737
|
+
put_update_response
|
738
|
+
expect(stub).to have_been_requested.twice
|
739
|
+
end
|
740
|
+
end
|
413
741
|
end
|
414
742
|
end
|
415
743
|
|
@@ -443,7 +771,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
443
771
|
'upcoming_payments' => 'upcoming_payments-input'
|
444
772
|
}
|
445
773
|
}.to_json,
|
446
|
-
headers:
|
774
|
+
headers: response_headers
|
447
775
|
)
|
448
776
|
end
|
449
777
|
|
@@ -453,6 +781,17 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
453
781
|
expect(stub).to have_been_requested
|
454
782
|
end
|
455
783
|
|
784
|
+
describe 'retry behaviour' do
|
785
|
+
it "doesn't retry errors" do
|
786
|
+
stub_url = '/subscriptions/:identity/actions/cancel'.gsub(':identity', resource_id)
|
787
|
+
stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/)
|
788
|
+
.to_timeout
|
789
|
+
|
790
|
+
expect { post_response }.to raise_error(Faraday::TimeoutError)
|
791
|
+
expect(stub).to have_been_requested
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
456
795
|
context 'when the request needs a body and custom header' do
|
457
796
|
let(:body) { { foo: 'bar' } }
|
458
797
|
let(:headers) { { 'Foo' => 'Bar' } }
|
@@ -489,7 +828,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
|
|
489
828
|
'upcoming_payments' => 'upcoming_payments-input'
|
490
829
|
}
|
491
830
|
}.to_json,
|
492
|
-
headers:
|
831
|
+
headers: response_headers
|
493
832
|
)
|
494
833
|
end
|
495
834
|
end
|