gocardless_pro 2.25.0 → 2.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/lib/gocardless_pro.rb +18 -0
  4. data/lib/gocardless_pro/client.rb +31 -1
  5. data/lib/gocardless_pro/resources/bank_authorisation.rb +87 -0
  6. data/lib/gocardless_pro/resources/billing_request.rb +86 -0
  7. data/lib/gocardless_pro/resources/billing_request_flow.rb +62 -0
  8. data/lib/gocardless_pro/resources/creditor.rb +2 -3
  9. data/lib/gocardless_pro/resources/institution.rb +45 -0
  10. data/lib/gocardless_pro/resources/payer_authorisation.rb +3 -0
  11. data/lib/gocardless_pro/resources/scenario_simulator.rb +42 -0
  12. data/lib/gocardless_pro/resources/webhook.rb +62 -0
  13. data/lib/gocardless_pro/services/bank_authorisations_service.rb +82 -0
  14. data/lib/gocardless_pro/services/billing_request_flows_service.rb +47 -0
  15. data/lib/gocardless_pro/services/billing_requests_service.rb +325 -0
  16. data/lib/gocardless_pro/services/institutions_service.rb +56 -0
  17. data/lib/gocardless_pro/services/payer_authorisations_service.rb +5 -5
  18. data/lib/gocardless_pro/services/scenario_simulators_service.rb +148 -0
  19. data/lib/gocardless_pro/services/subscriptions_service.rb +8 -3
  20. data/lib/gocardless_pro/services/webhooks_service.rb +113 -0
  21. data/lib/gocardless_pro/version.rb +1 -1
  22. data/spec/resources/bank_authorisation_spec.rb +259 -0
  23. data/spec/resources/billing_request_flow_spec.rb +129 -0
  24. data/spec/resources/billing_request_spec.rb +736 -0
  25. data/spec/resources/institution_spec.rb +103 -0
  26. data/spec/resources/scenario_simulator_spec.rb +63 -0
  27. data/spec/resources/webhook_spec.rb +323 -0
  28. data/spec/services/bank_authorisations_service_spec.rb +366 -0
  29. data/spec/services/billing_request_flows_service_spec.rb +152 -0
  30. data/spec/services/billing_requests_service_spec.rb +1042 -0
  31. data/spec/services/institutions_service_spec.rb +223 -0
  32. data/spec/services/scenario_simulators_service_spec.rb +74 -0
  33. data/spec/services/webhooks_service_spec.rb +545 -0
  34. metadata +39 -3
@@ -0,0 +1,223 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::InstitutionsService 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.institutions.list }
15
+
16
+ let(:body) do
17
+ {
18
+ 'institutions' => [{
19
+
20
+ 'icon_url' => 'icon_url-input',
21
+ 'id' => 'id-input',
22
+ 'logo_url' => 'logo_url-input',
23
+ 'name' => 'name-input',
24
+ }],
25
+ meta: {
26
+ cursors: {
27
+ before: nil,
28
+ after: 'ABC123',
29
+ },
30
+ },
31
+ }.to_json
32
+ end
33
+
34
+ before do
35
+ stub_request(:get, %r{.*api.gocardless.com/institutions}).to_return(
36
+ body: body,
37
+ headers: response_headers
38
+ )
39
+ end
40
+
41
+ it 'wraps each item in the resource class' do
42
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Institution)
43
+
44
+ expect(get_list_response.records.first.icon_url).to eq('icon_url-input')
45
+
46
+ expect(get_list_response.records.first.id).to eq('id-input')
47
+
48
+ expect(get_list_response.records.first.logo_url).to eq('logo_url-input')
49
+
50
+ expect(get_list_response.records.first.name).to eq('name-input')
51
+ end
52
+
53
+ it 'exposes the cursors for before and after' do
54
+ expect(get_list_response.before).to eq(nil)
55
+ expect(get_list_response.after).to eq('ABC123')
56
+ end
57
+
58
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
59
+
60
+ describe 'retry behaviour' do
61
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
62
+
63
+ it 'retries timeouts' do
64
+ stub = stub_request(:get, %r{.*api.gocardless.com/institutions}).
65
+ to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
66
+
67
+ get_list_response
68
+ expect(stub).to have_been_requested.twice
69
+ end
70
+
71
+ it 'retries 5XX errors' do
72
+ stub = stub_request(:get, %r{.*api.gocardless.com/institutions}).
73
+ to_return(status: 502,
74
+ headers: { 'Content-Type' => 'text/html' },
75
+ body: '<html><body>Response from Cloudflare</body></html>').
76
+ then.to_return(status: 200, headers: response_headers, body: body)
77
+
78
+ get_list_response
79
+ expect(stub).to have_been_requested.twice
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#all' do
86
+ let!(:first_response_stub) do
87
+ stub_request(:get, %r{.*api.gocardless.com/institutions$}).to_return(
88
+ body: {
89
+ 'institutions' => [{
90
+
91
+ 'icon_url' => 'icon_url-input',
92
+ 'id' => 'id-input',
93
+ 'logo_url' => 'logo_url-input',
94
+ 'name' => 'name-input',
95
+ }],
96
+ meta: {
97
+ cursors: { after: 'AB345' },
98
+ limit: 1,
99
+ },
100
+ }.to_json,
101
+ headers: response_headers
102
+ )
103
+ end
104
+
105
+ let!(:second_response_stub) do
106
+ stub_request(:get, %r{.*api.gocardless.com/institutions\?after=AB345}).to_return(
107
+ body: {
108
+ 'institutions' => [{
109
+
110
+ 'icon_url' => 'icon_url-input',
111
+ 'id' => 'id-input',
112
+ 'logo_url' => 'logo_url-input',
113
+ 'name' => 'name-input',
114
+ }],
115
+ meta: {
116
+ limit: 2,
117
+ cursors: {},
118
+ },
119
+ }.to_json,
120
+ headers: response_headers
121
+ )
122
+ end
123
+
124
+ it 'automatically makes the extra requests' do
125
+ expect(client.institutions.all.to_a.length).to eq(2)
126
+ expect(first_response_stub).to have_been_requested
127
+ expect(second_response_stub).to have_been_requested
128
+ end
129
+
130
+ describe 'retry behaviour' do
131
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
132
+
133
+ it 'retries timeouts' do
134
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/institutions$}).to_return(
135
+ body: {
136
+ 'institutions' => [{
137
+
138
+ 'icon_url' => 'icon_url-input',
139
+ 'id' => 'id-input',
140
+ 'logo_url' => 'logo_url-input',
141
+ 'name' => 'name-input',
142
+ }],
143
+ meta: {
144
+ cursors: { after: 'AB345' },
145
+ limit: 1,
146
+ },
147
+ }.to_json,
148
+ headers: response_headers
149
+ )
150
+
151
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/institutions\?after=AB345}).
152
+ to_timeout.then.
153
+ to_return(
154
+ body: {
155
+ 'institutions' => [{
156
+
157
+ 'icon_url' => 'icon_url-input',
158
+ 'id' => 'id-input',
159
+ 'logo_url' => 'logo_url-input',
160
+ 'name' => 'name-input',
161
+ }],
162
+ meta: {
163
+ limit: 2,
164
+ cursors: {},
165
+ },
166
+ }.to_json,
167
+ headers: response_headers
168
+ )
169
+
170
+ client.institutions.all.to_a
171
+
172
+ expect(first_response_stub).to have_been_requested
173
+ expect(second_response_stub).to have_been_requested.twice
174
+ end
175
+
176
+ it 'retries 5XX errors' do
177
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/institutions$}).to_return(
178
+ body: {
179
+ 'institutions' => [{
180
+
181
+ 'icon_url' => 'icon_url-input',
182
+ 'id' => 'id-input',
183
+ 'logo_url' => 'logo_url-input',
184
+ 'name' => 'name-input',
185
+ }],
186
+ meta: {
187
+ cursors: { after: 'AB345' },
188
+ limit: 1,
189
+ },
190
+ }.to_json,
191
+ headers: response_headers
192
+ )
193
+
194
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/institutions\?after=AB345}).
195
+ to_return(
196
+ status: 502,
197
+ body: '<html><body>Response from Cloudflare</body></html>',
198
+ headers: { 'Content-Type' => 'text/html' }
199
+ ).then.to_return(
200
+ body: {
201
+ 'institutions' => [{
202
+
203
+ 'icon_url' => 'icon_url-input',
204
+ 'id' => 'id-input',
205
+ 'logo_url' => 'logo_url-input',
206
+ 'name' => 'name-input',
207
+ }],
208
+ meta: {
209
+ limit: 2,
210
+ cursors: {},
211
+ },
212
+ }.to_json,
213
+ headers: response_headers
214
+ )
215
+
216
+ client.institutions.all.to_a
217
+
218
+ expect(first_response_stub).to have_been_requested
219
+ expect(second_response_stub).to have_been_requested.twice
220
+ end
221
+ end
222
+ end
223
+ end
@@ -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
@@ -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