gocardless_pro 2.25.0 → 2.27.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 (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