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,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::ScenarioSimulatorsService 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 '#run' do
13
+ subject(:post_response) { client.scenario_simulators.run(resource_id) }
14
+
15
+ let(:resource_id) { 'ABC123' }
16
+
17
+ let!(:stub) do
18
+ # /scenario_simulators/%v/actions/run
19
+ stub_url = '/scenario_simulators/:identity/actions/run'.gsub(':identity', resource_id)
20
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
21
+ body: {
22
+ 'scenario_simulators' => {
23
+
24
+ 'id' => 'id-input',
25
+ },
26
+ }.to_json,
27
+ headers: response_headers
28
+ )
29
+ end
30
+
31
+ it 'wraps the response and calls the right endpoint' do
32
+ expect(post_response).to be_a(GoCardlessPro::Resources::ScenarioSimulator)
33
+
34
+ expect(stub).to have_been_requested
35
+ end
36
+
37
+ describe 'retry behaviour' do
38
+ it "doesn't retry errors" do
39
+ stub_url = '/scenario_simulators/:identity/actions/run'.gsub(':identity', resource_id)
40
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
41
+ to_timeout
42
+
43
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
44
+ expect(stub).to have_been_requested
45
+ end
46
+ end
47
+
48
+ context 'when the request needs a body and custom header' do
49
+ let(:body) { { foo: 'bar' } }
50
+ let(:headers) { { 'Foo' => 'Bar' } }
51
+ subject(:post_response) { client.scenario_simulators.run(resource_id, body, headers) }
52
+
53
+ let(:resource_id) { 'ABC123' }
54
+
55
+ let!(:stub) do
56
+ # /scenario_simulators/%v/actions/run
57
+ stub_url = '/scenario_simulators/:identity/actions/run'.gsub(':identity', resource_id)
58
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
59
+ with(
60
+ body: { foo: 'bar' },
61
+ headers: { 'Foo' => 'Bar' }
62
+ ).to_return(
63
+ body: {
64
+ 'scenario_simulators' => {
65
+
66
+ 'id' => 'id-input',
67
+ },
68
+ }.to_json,
69
+ headers: response_headers
70
+ )
71
+ end
72
+ end
73
+ end
74
+ end
@@ -257,19 +257,6 @@ describe GoCardlessPro::Services::SubscriptionsService do
257
257
  to raise_error(GoCardlessPro::IdempotencyConflict)
258
258
  end
259
259
  end
260
-
261
- context 'with on_idempotency_conflict: :unknown' do
262
- let(:client) do
263
- GoCardlessPro::Client.new(
264
- access_token: 'SECRET_TOKEN',
265
- on_idempotency_conflict: :unknown
266
- )
267
- end
268
-
269
- it 'raises an ArgumentError' do
270
- expect { post_create_response }.to raise_error(ArgumentError)
271
- end
272
- end
273
260
  end
274
261
  end
275
262
 
@@ -0,0 +1,545 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::WebhooksService 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 '#list' do
13
+ describe 'with no filters' do
14
+ subject(:get_list_response) { client.webhooks.list }
15
+
16
+ let(:body) do
17
+ {
18
+ 'webhooks' => [{
19
+
20
+ 'created_at' => 'created_at-input',
21
+ 'id' => 'id-input',
22
+ 'is_test' => 'is_test-input',
23
+ 'request_body' => 'request_body-input',
24
+ 'request_headers' => 'request_headers-input',
25
+ 'response_body' => 'response_body-input',
26
+ 'response_body_truncated' => 'response_body_truncated-input',
27
+ 'response_code' => 'response_code-input',
28
+ 'response_headers' => 'response_headers-input',
29
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
30
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
31
+ 'successful' => 'successful-input',
32
+ 'url' => 'url-input',
33
+ }],
34
+ meta: {
35
+ cursors: {
36
+ before: nil,
37
+ after: 'ABC123',
38
+ },
39
+ },
40
+ }.to_json
41
+ end
42
+
43
+ before do
44
+ stub_request(:get, %r{.*api.gocardless.com/webhooks}).to_return(
45
+ body: body,
46
+ headers: response_headers
47
+ )
48
+ end
49
+
50
+ it 'wraps each item in the resource class' do
51
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Webhook)
52
+
53
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
54
+
55
+ expect(get_list_response.records.first.id).to eq('id-input')
56
+
57
+ expect(get_list_response.records.first.is_test).to eq('is_test-input')
58
+
59
+ expect(get_list_response.records.first.request_body).to eq('request_body-input')
60
+
61
+ expect(get_list_response.records.first.request_headers).to eq('request_headers-input')
62
+
63
+ expect(get_list_response.records.first.response_body).to eq('response_body-input')
64
+
65
+ expect(get_list_response.records.first.response_body_truncated).to eq('response_body_truncated-input')
66
+
67
+ expect(get_list_response.records.first.response_code).to eq('response_code-input')
68
+
69
+ expect(get_list_response.records.first.response_headers).to eq('response_headers-input')
70
+
71
+ expect(get_list_response.records.first.response_headers_content_truncated).to eq('response_headers_content_truncated-input')
72
+
73
+ expect(get_list_response.records.first.response_headers_count_truncated).to eq('response_headers_count_truncated-input')
74
+
75
+ expect(get_list_response.records.first.successful).to eq('successful-input')
76
+
77
+ expect(get_list_response.records.first.url).to eq('url-input')
78
+ end
79
+
80
+ it 'exposes the cursors for before and after' do
81
+ expect(get_list_response.before).to eq(nil)
82
+ expect(get_list_response.after).to eq('ABC123')
83
+ end
84
+
85
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
86
+
87
+ describe 'retry behaviour' do
88
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
89
+
90
+ it 'retries timeouts' do
91
+ stub = stub_request(:get, %r{.*api.gocardless.com/webhooks}).
92
+ to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
93
+
94
+ get_list_response
95
+ expect(stub).to have_been_requested.twice
96
+ end
97
+
98
+ it 'retries 5XX errors' do
99
+ stub = stub_request(:get, %r{.*api.gocardless.com/webhooks}).
100
+ to_return(status: 502,
101
+ headers: { 'Content-Type' => 'text/html' },
102
+ body: '<html><body>Response from Cloudflare</body></html>').
103
+ then.to_return(status: 200, headers: response_headers, body: body)
104
+
105
+ get_list_response
106
+ expect(stub).to have_been_requested.twice
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe '#all' do
113
+ let!(:first_response_stub) do
114
+ stub_request(:get, %r{.*api.gocardless.com/webhooks$}).to_return(
115
+ body: {
116
+ 'webhooks' => [{
117
+
118
+ 'created_at' => 'created_at-input',
119
+ 'id' => 'id-input',
120
+ 'is_test' => 'is_test-input',
121
+ 'request_body' => 'request_body-input',
122
+ 'request_headers' => 'request_headers-input',
123
+ 'response_body' => 'response_body-input',
124
+ 'response_body_truncated' => 'response_body_truncated-input',
125
+ 'response_code' => 'response_code-input',
126
+ 'response_headers' => 'response_headers-input',
127
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
128
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
129
+ 'successful' => 'successful-input',
130
+ 'url' => 'url-input',
131
+ }],
132
+ meta: {
133
+ cursors: { after: 'AB345' },
134
+ limit: 1,
135
+ },
136
+ }.to_json,
137
+ headers: response_headers
138
+ )
139
+ end
140
+
141
+ let!(:second_response_stub) do
142
+ stub_request(:get, %r{.*api.gocardless.com/webhooks\?after=AB345}).to_return(
143
+ body: {
144
+ 'webhooks' => [{
145
+
146
+ 'created_at' => 'created_at-input',
147
+ 'id' => 'id-input',
148
+ 'is_test' => 'is_test-input',
149
+ 'request_body' => 'request_body-input',
150
+ 'request_headers' => 'request_headers-input',
151
+ 'response_body' => 'response_body-input',
152
+ 'response_body_truncated' => 'response_body_truncated-input',
153
+ 'response_code' => 'response_code-input',
154
+ 'response_headers' => 'response_headers-input',
155
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
156
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
157
+ 'successful' => 'successful-input',
158
+ 'url' => 'url-input',
159
+ }],
160
+ meta: {
161
+ limit: 2,
162
+ cursors: {},
163
+ },
164
+ }.to_json,
165
+ headers: response_headers
166
+ )
167
+ end
168
+
169
+ it 'automatically makes the extra requests' do
170
+ expect(client.webhooks.all.to_a.length).to eq(2)
171
+ expect(first_response_stub).to have_been_requested
172
+ expect(second_response_stub).to have_been_requested
173
+ end
174
+
175
+ describe 'retry behaviour' do
176
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
177
+
178
+ it 'retries timeouts' do
179
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/webhooks$}).to_return(
180
+ body: {
181
+ 'webhooks' => [{
182
+
183
+ 'created_at' => 'created_at-input',
184
+ 'id' => 'id-input',
185
+ 'is_test' => 'is_test-input',
186
+ 'request_body' => 'request_body-input',
187
+ 'request_headers' => 'request_headers-input',
188
+ 'response_body' => 'response_body-input',
189
+ 'response_body_truncated' => 'response_body_truncated-input',
190
+ 'response_code' => 'response_code-input',
191
+ 'response_headers' => 'response_headers-input',
192
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
193
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
194
+ 'successful' => 'successful-input',
195
+ 'url' => 'url-input',
196
+ }],
197
+ meta: {
198
+ cursors: { after: 'AB345' },
199
+ limit: 1,
200
+ },
201
+ }.to_json,
202
+ headers: response_headers
203
+ )
204
+
205
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/webhooks\?after=AB345}).
206
+ to_timeout.then.
207
+ to_return(
208
+ body: {
209
+ 'webhooks' => [{
210
+
211
+ 'created_at' => 'created_at-input',
212
+ 'id' => 'id-input',
213
+ 'is_test' => 'is_test-input',
214
+ 'request_body' => 'request_body-input',
215
+ 'request_headers' => 'request_headers-input',
216
+ 'response_body' => 'response_body-input',
217
+ 'response_body_truncated' => 'response_body_truncated-input',
218
+ 'response_code' => 'response_code-input',
219
+ 'response_headers' => 'response_headers-input',
220
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
221
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
222
+ 'successful' => 'successful-input',
223
+ 'url' => 'url-input',
224
+ }],
225
+ meta: {
226
+ limit: 2,
227
+ cursors: {},
228
+ },
229
+ }.to_json,
230
+ headers: response_headers
231
+ )
232
+
233
+ client.webhooks.all.to_a
234
+
235
+ expect(first_response_stub).to have_been_requested
236
+ expect(second_response_stub).to have_been_requested.twice
237
+ end
238
+
239
+ it 'retries 5XX errors' do
240
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/webhooks$}).to_return(
241
+ body: {
242
+ 'webhooks' => [{
243
+
244
+ 'created_at' => 'created_at-input',
245
+ 'id' => 'id-input',
246
+ 'is_test' => 'is_test-input',
247
+ 'request_body' => 'request_body-input',
248
+ 'request_headers' => 'request_headers-input',
249
+ 'response_body' => 'response_body-input',
250
+ 'response_body_truncated' => 'response_body_truncated-input',
251
+ 'response_code' => 'response_code-input',
252
+ 'response_headers' => 'response_headers-input',
253
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
254
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
255
+ 'successful' => 'successful-input',
256
+ 'url' => 'url-input',
257
+ }],
258
+ meta: {
259
+ cursors: { after: 'AB345' },
260
+ limit: 1,
261
+ },
262
+ }.to_json,
263
+ headers: response_headers
264
+ )
265
+
266
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/webhooks\?after=AB345}).
267
+ to_return(
268
+ status: 502,
269
+ body: '<html><body>Response from Cloudflare</body></html>',
270
+ headers: { 'Content-Type' => 'text/html' }
271
+ ).then.to_return(
272
+ body: {
273
+ 'webhooks' => [{
274
+
275
+ 'created_at' => 'created_at-input',
276
+ 'id' => 'id-input',
277
+ 'is_test' => 'is_test-input',
278
+ 'request_body' => 'request_body-input',
279
+ 'request_headers' => 'request_headers-input',
280
+ 'response_body' => 'response_body-input',
281
+ 'response_body_truncated' => 'response_body_truncated-input',
282
+ 'response_code' => 'response_code-input',
283
+ 'response_headers' => 'response_headers-input',
284
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
285
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
286
+ 'successful' => 'successful-input',
287
+ 'url' => 'url-input',
288
+ }],
289
+ meta: {
290
+ limit: 2,
291
+ cursors: {},
292
+ },
293
+ }.to_json,
294
+ headers: response_headers
295
+ )
296
+
297
+ client.webhooks.all.to_a
298
+
299
+ expect(first_response_stub).to have_been_requested
300
+ expect(second_response_stub).to have_been_requested.twice
301
+ end
302
+ end
303
+ end
304
+
305
+ describe '#get' do
306
+ let(:id) { 'ID123' }
307
+
308
+ subject(:get_response) { client.webhooks.get(id) }
309
+
310
+ context 'passing in a custom header' do
311
+ let!(:stub) do
312
+ stub_url = '/webhooks/:identity'.gsub(':identity', id)
313
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
314
+ with(headers: { 'Foo' => 'Bar' }).
315
+ to_return(
316
+ body: {
317
+ 'webhooks' => {
318
+
319
+ 'created_at' => 'created_at-input',
320
+ 'id' => 'id-input',
321
+ 'is_test' => 'is_test-input',
322
+ 'request_body' => 'request_body-input',
323
+ 'request_headers' => 'request_headers-input',
324
+ 'response_body' => 'response_body-input',
325
+ 'response_body_truncated' => 'response_body_truncated-input',
326
+ 'response_code' => 'response_code-input',
327
+ 'response_headers' => 'response_headers-input',
328
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
329
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
330
+ 'successful' => 'successful-input',
331
+ 'url' => 'url-input',
332
+ },
333
+ }.to_json,
334
+ headers: response_headers
335
+ )
336
+ end
337
+
338
+ subject(:get_response) do
339
+ client.webhooks.get(id, headers: {
340
+ 'Foo' => 'Bar',
341
+ })
342
+ end
343
+
344
+ it 'includes the header' do
345
+ get_response
346
+ expect(stub).to have_been_requested
347
+ end
348
+ end
349
+
350
+ context 'when there is a webhook to return' do
351
+ before do
352
+ stub_url = '/webhooks/:identity'.gsub(':identity', id)
353
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
354
+ body: {
355
+ 'webhooks' => {
356
+
357
+ 'created_at' => 'created_at-input',
358
+ 'id' => 'id-input',
359
+ 'is_test' => 'is_test-input',
360
+ 'request_body' => 'request_body-input',
361
+ 'request_headers' => 'request_headers-input',
362
+ 'response_body' => 'response_body-input',
363
+ 'response_body_truncated' => 'response_body_truncated-input',
364
+ 'response_code' => 'response_code-input',
365
+ 'response_headers' => 'response_headers-input',
366
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
367
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
368
+ 'successful' => 'successful-input',
369
+ 'url' => 'url-input',
370
+ },
371
+ }.to_json,
372
+ headers: response_headers
373
+ )
374
+ end
375
+
376
+ it 'wraps the response in a resource' do
377
+ expect(get_response).to be_a(GoCardlessPro::Resources::Webhook)
378
+ end
379
+ end
380
+
381
+ context 'when nothing is returned' do
382
+ before do
383
+ stub_url = '/webhooks/:identity'.gsub(':identity', id)
384
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
385
+ body: '',
386
+ headers: response_headers
387
+ )
388
+ end
389
+
390
+ it 'returns nil' do
391
+ expect(get_response).to be_nil
392
+ end
393
+ end
394
+
395
+ context "when an ID is specified which can't be included in a valid URI" do
396
+ let(:id) { '`' }
397
+
398
+ it "doesn't raise an error" do
399
+ expect { get_response }.to_not raise_error(/bad URI/)
400
+ end
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
+ stub_url = '/webhooks/:identity'.gsub(':identity', id)
408
+
409
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
410
+ to_timeout.then.to_return(status: 200, headers: response_headers)
411
+
412
+ get_response
413
+ expect(stub).to have_been_requested.twice
414
+ end
415
+
416
+ it 'retries 5XX errors, other than 500s' do
417
+ stub_url = '/webhooks/:identity'.gsub(':identity', id)
418
+
419
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
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)
424
+
425
+ get_response
426
+ expect(stub).to have_been_requested.twice
427
+ end
428
+
429
+ it 'retries 500 errors returned by the API' do
430
+ stub_url = '/webhooks/:identity'.gsub(':identity', id)
431
+
432
+ gocardless_error = {
433
+ 'error' => {
434
+ 'message' => 'Internal server error',
435
+ 'documentation_url' => 'https://developer.gocardless.com/#gocardless',
436
+ 'errors' => [{
437
+ 'message' => 'Internal server error',
438
+ 'reason' => 'internal_server_error',
439
+ }],
440
+ 'type' => 'gocardless',
441
+ 'code' => 500,
442
+ 'request_id' => 'dummy_request_id',
443
+ 'id' => 'dummy_exception_id',
444
+ },
445
+ }
446
+
447
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
448
+ to_return(status: 500,
449
+ headers: response_headers,
450
+ body: gocardless_error.to_json).
451
+ then.to_return(status: 200, headers: response_headers)
452
+
453
+ get_response
454
+ expect(stub).to have_been_requested.twice
455
+ end
456
+ end
457
+ end
458
+
459
+ describe '#retry' do
460
+ subject(:post_response) { client.webhooks.retry(resource_id) }
461
+
462
+ let(:resource_id) { 'ABC123' }
463
+
464
+ let!(:stub) do
465
+ # /webhooks/%v/actions/retry
466
+ stub_url = '/webhooks/:identity/actions/retry'.gsub(':identity', resource_id)
467
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
468
+ body: {
469
+ 'webhooks' => {
470
+
471
+ 'created_at' => 'created_at-input',
472
+ 'id' => 'id-input',
473
+ 'is_test' => 'is_test-input',
474
+ 'request_body' => 'request_body-input',
475
+ 'request_headers' => 'request_headers-input',
476
+ 'response_body' => 'response_body-input',
477
+ 'response_body_truncated' => 'response_body_truncated-input',
478
+ 'response_code' => 'response_code-input',
479
+ 'response_headers' => 'response_headers-input',
480
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
481
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
482
+ 'successful' => 'successful-input',
483
+ 'url' => 'url-input',
484
+ },
485
+ }.to_json,
486
+ headers: response_headers
487
+ )
488
+ end
489
+
490
+ it 'wraps the response and calls the right endpoint' do
491
+ expect(post_response).to be_a(GoCardlessPro::Resources::Webhook)
492
+
493
+ expect(stub).to have_been_requested
494
+ end
495
+
496
+ describe 'retry behaviour' do
497
+ it "doesn't retry errors" do
498
+ stub_url = '/webhooks/:identity/actions/retry'.gsub(':identity', resource_id)
499
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
500
+ to_timeout
501
+
502
+ expect { post_response }.to raise_error(Faraday::ConnectionFailed)
503
+ expect(stub).to have_been_requested
504
+ end
505
+ end
506
+
507
+ context 'when the request needs a body and custom header' do
508
+ let(:body) { { foo: 'bar' } }
509
+ let(:headers) { { 'Foo' => 'Bar' } }
510
+ subject(:post_response) { client.webhooks.retry(resource_id, body, headers) }
511
+
512
+ let(:resource_id) { 'ABC123' }
513
+
514
+ let!(:stub) do
515
+ # /webhooks/%v/actions/retry
516
+ stub_url = '/webhooks/:identity/actions/retry'.gsub(':identity', resource_id)
517
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).
518
+ with(
519
+ body: { foo: 'bar' },
520
+ headers: { 'Foo' => 'Bar' }
521
+ ).to_return(
522
+ body: {
523
+ 'webhooks' => {
524
+
525
+ 'created_at' => 'created_at-input',
526
+ 'id' => 'id-input',
527
+ 'is_test' => 'is_test-input',
528
+ 'request_body' => 'request_body-input',
529
+ 'request_headers' => 'request_headers-input',
530
+ 'response_body' => 'response_body-input',
531
+ 'response_body_truncated' => 'response_body_truncated-input',
532
+ 'response_code' => 'response_code-input',
533
+ 'response_headers' => 'response_headers-input',
534
+ 'response_headers_content_truncated' => 'response_headers_content_truncated-input',
535
+ 'response_headers_count_truncated' => 'response_headers_count_truncated-input',
536
+ 'successful' => 'successful-input',
537
+ 'url' => 'url-input',
538
+ },
539
+ }.to_json,
540
+ headers: response_headers
541
+ )
542
+ end
543
+ end
544
+ end
545
+ end