rdstation-ruby-client 2.1.0 → 2.5.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 (40) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +121 -1
  3. data/README.md +106 -22
  4. data/Rakefile +4 -0
  5. data/lib/rdstation-ruby-client.rb +6 -1
  6. data/lib/rdstation.rb +19 -0
  7. data/lib/rdstation/api_response.rb +1 -2
  8. data/lib/rdstation/authentication.rb +8 -3
  9. data/lib/rdstation/{authorization_header.rb → authorization.rb} +11 -8
  10. data/lib/rdstation/builder/field.rb +70 -0
  11. data/lib/rdstation/client.rb +17 -7
  12. data/lib/rdstation/contacts.rb +22 -13
  13. data/lib/rdstation/error.rb +3 -0
  14. data/lib/rdstation/error/format.rb +29 -3
  15. data/lib/rdstation/error/formatter.rb +69 -8
  16. data/lib/rdstation/error_handler.rb +6 -1
  17. data/lib/rdstation/error_handler/invalid_refresh_token.rb +24 -0
  18. data/lib/rdstation/error_handler/unauthorized.rb +2 -0
  19. data/lib/rdstation/events.rb +7 -12
  20. data/lib/rdstation/fields.rb +35 -6
  21. data/lib/rdstation/retryable_request.rb +35 -0
  22. data/lib/rdstation/version.rb +1 -1
  23. data/lib/rdstation/webhooks.rb +25 -13
  24. data/rdstation-ruby-client.gemspec +2 -1
  25. data/spec/lib/rdstation/api_response_spec.rb +34 -0
  26. data/spec/lib/rdstation/authentication_spec.rb +105 -2
  27. data/spec/lib/rdstation/{authorization_header_spec.rb → authorization_spec.rb} +3 -3
  28. data/spec/lib/rdstation/builder/field_spec.rb +69 -0
  29. data/spec/lib/rdstation/client_spec.rb +6 -6
  30. data/spec/lib/rdstation/contacts_spec.rb +23 -3
  31. data/spec/lib/rdstation/error/format_spec.rb +63 -0
  32. data/spec/lib/rdstation/error/formatter_spec.rb +113 -0
  33. data/spec/lib/rdstation/error_handler/invalid_refresh_token_spec.rb +53 -0
  34. data/spec/lib/rdstation/error_handler_spec.rb +23 -0
  35. data/spec/lib/rdstation/events_spec.rb +8 -3
  36. data/spec/lib/rdstation/fields_spec.rb +6 -1
  37. data/spec/lib/rdstation/retryable_request_spec.rb +142 -0
  38. data/spec/lib/rdstation/webhooks_spec.rb +26 -1
  39. data/spec/lib/rdstation_spec.rb +18 -0
  40. metadata +36 -8
@@ -4,27 +4,27 @@ RSpec.describe RDStation::Client do
4
4
  context "when access_token is given" do
5
5
  let(:access_token) { 'access_token' }
6
6
  let(:client) { described_class.new(access_token: access_token) }
7
- let(:mock_authorization_header) { double(RDStation::AuthorizationHeader) }
7
+ let(:mock_authorization) { double(RDStation::Authorization) }
8
8
 
9
- before { allow(RDStation::AuthorizationHeader).to receive(:new).and_return mock_authorization_header }
9
+ before { allow(RDStation::Authorization).to receive(:new).and_return mock_authorization }
10
10
 
11
11
  it 'returns Contacts endpoint' do
12
- expect(RDStation::Contacts).to receive(:new).with({ authorization_header: mock_authorization_header }).and_call_original
12
+ expect(RDStation::Contacts).to receive(:new).with({ authorization: mock_authorization }).and_call_original
13
13
  expect(client.contacts).to be_instance_of RDStation::Contacts
14
14
  end
15
15
 
16
16
  it 'returns Events endpoint' do
17
- expect(RDStation::Events).to receive(:new).with({ authorization_header: mock_authorization_header }).and_call_original
17
+ expect(RDStation::Events).to receive(:new).with({ authorization: mock_authorization }).and_call_original
18
18
  expect(client.events).to be_instance_of RDStation::Events
19
19
  end
20
20
 
21
21
  it 'returns Fields endpoint' do
22
- expect(RDStation::Fields).to receive(:new).with({ authorization_header: mock_authorization_header }).and_call_original
22
+ expect(RDStation::Fields).to receive(:new).with({ authorization: mock_authorization }).and_call_original
23
23
  expect(client.fields).to be_instance_of RDStation::Fields
24
24
  end
25
25
 
26
26
  it 'returns Webhooks endpoint' do
27
- expect(RDStation::Webhooks).to receive(:new).with({ authorization_header: mock_authorization_header }).and_call_original
27
+ expect(RDStation::Webhooks).to receive(:new).with({ authorization: mock_authorization }).and_call_original
28
28
  expect(client.webhooks).to be_instance_of RDStation::Webhooks
29
29
  end
30
30
  end
@@ -16,13 +16,13 @@ RSpec.describe RDStation::Contacts do
16
16
  let(:expired_access_token) { 'expired_access_token' }
17
17
 
18
18
  let(:contact_with_valid_token) do
19
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: valid_access_token))
19
+ described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
20
20
  end
21
21
  let(:contact_with_expired_token) do
22
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: expired_access_token))
22
+ described_class.new(authorization: RDStation::Authorization.new(access_token: expired_access_token))
23
23
  end
24
24
  let(:contact_with_invalid_token) do
25
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: invalid_access_token))
25
+ described_class.new(authorization: RDStation::Authorization.new(access_token: invalid_access_token))
26
26
  end
27
27
 
28
28
 
@@ -109,6 +109,11 @@ RSpec.describe RDStation::Contacts do
109
109
  end
110
110
 
111
111
  describe '#by_uuid' do
112
+ it 'calls retryable_request' do
113
+ expect(contact_with_valid_token).to receive(:retryable_request)
114
+ contact_with_valid_token.by_uuid('valid_uuid')
115
+ end
116
+
112
117
  context 'with a valid auth token' do
113
118
  context 'when the contact exists' do
114
119
  let(:contact) do
@@ -172,6 +177,11 @@ RSpec.describe RDStation::Contacts do
172
177
  end
173
178
 
174
179
  describe '#by_email' do
180
+ it 'calls retryable_request' do
181
+ expect(contact_with_valid_token).to receive(:retryable_request)
182
+ contact_with_valid_token.by_email('x@xpto.com')
183
+ end
184
+
175
185
  context 'with a valid auth token' do
176
186
  context 'when the contact exists' do
177
187
  let(:contact) do
@@ -235,6 +245,11 @@ RSpec.describe RDStation::Contacts do
235
245
  end
236
246
 
237
247
  describe '#update' do
248
+ it 'calls retryable_request' do
249
+ expect(contact_with_valid_token).to receive(:retryable_request)
250
+ contact_with_valid_token.update('valid_uuid', {})
251
+ end
252
+
238
253
  context 'with a valid access_token' do
239
254
  let(:valid_access_token) { 'valid_access_token' }
240
255
  let(:headers) do
@@ -322,6 +337,11 @@ RSpec.describe RDStation::Contacts do
322
337
  end
323
338
 
324
339
  describe '#upsert' do
340
+ it 'calls retryable_request' do
341
+ expect(contact_with_valid_token).to receive(:retryable_request)
342
+ contact_with_valid_token.upsert('email', 'valid@email.com', {})
343
+ end
344
+
325
345
  context 'with a valid access_token' do
326
346
  let(:valid_access_token) { 'valid_access_token' }
327
347
 
@@ -52,5 +52,68 @@ RSpec.describe RDStation::Error::Format do
52
52
  expect(result).to eq(RDStation::Error::Format::ARRAY_OF_HASHES)
53
53
  end
54
54
  end
55
+
56
+ context 'when receives a mixed type of errors' do
57
+ let(:errors) do
58
+ {
59
+ 'label': {
60
+ 'pt-BR': [
61
+ {
62
+ 'error_type': 'CANNOT_BE_BLANK',
63
+ 'error_message': 'cannot be blank'
64
+ }
65
+ ]
66
+ },
67
+ 'api_identifier': [
68
+ {
69
+ 'error_type': 'CANNOT_BE_BLANK',
70
+ 'error_message': 'cannot be blank'
71
+ }
72
+ ]
73
+ }
74
+ end
75
+
76
+ it 'returns the HASH_OF_MULTIPLE_TYPES format' do
77
+ result = error_format.format
78
+ expect(result).to eq(RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES)
79
+ end
80
+ end
81
+
82
+ context 'when receives a hash of hashes errors' do
83
+ let(:errors) do
84
+ {
85
+ label: {
86
+ 'pt-BR': [
87
+ {
88
+ 'error_type': 'CANNOT_BE_BLANK',
89
+ 'error_message': 'cannot be blank'
90
+ }
91
+ ]
92
+ }
93
+ }
94
+ end
95
+
96
+ it 'returns the HASH_OF_MULTILINGUAL format' do
97
+ result = error_format.format
98
+ expect(result).to eq(RDStation::Error::Format::HASH_OF_HASHES)
99
+ end
100
+ end
101
+
102
+ context 'when receives a single hash with error' do
103
+ let(:errors) do
104
+ {
105
+ 'error' => "'lead_limiter' rate limit exceeded for 86400 second(s) period for key ...",
106
+ 'max' => 24,
107
+ 'usage' => 55,
108
+ 'remaining_time' => 20745,
109
+ }
110
+ end
111
+
112
+ it 'returns the SINGLE_HASH format' do
113
+ result = error_format.format
114
+ expect(result).to eq(RDStation::Error::Format::SINGLE_HASH)
115
+ end
116
+
117
+ end
55
118
  end
56
119
  end
@@ -132,5 +132,118 @@ RSpec.describe RDStation::Error::Formatter do
132
132
  expect(result).to eq(expected_result)
133
133
  end
134
134
  end
135
+
136
+ context 'when receives a hash of multiple type errors' do
137
+ let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES) }
138
+
139
+ let(:error_response) do
140
+ {
141
+ 'errors' => {
142
+ 'label' => {
143
+ 'pt-BR' => [
144
+ {
145
+ 'error_type' => 'CANNOT_BE_BLANK',
146
+ 'error_message' => 'cannot be blank'
147
+ }
148
+ ]
149
+ },
150
+ 'api_identifier' => [
151
+ {
152
+ 'error_type' => 'CANNOT_BE_BLANK',
153
+ 'error_message' => 'cannot be blank'
154
+ }
155
+ ]
156
+ }
157
+ }
158
+ end
159
+
160
+ let(:error_formatter) { described_class.new(error_response) }
161
+
162
+ let(:expected_result) do
163
+ [
164
+ {
165
+ 'error_type' => 'CANNOT_BE_BLANK',
166
+ 'error_message' => 'cannot be blank',
167
+ 'path' => 'body.label.pt-BR'
168
+ },
169
+ {
170
+ 'error_type' => 'CANNOT_BE_BLANK',
171
+ 'error_message' => 'cannot be blank',
172
+ 'path' => 'body.api_identifier'
173
+ }
174
+ ]
175
+ end
176
+
177
+ it 'returns an array of errors' do
178
+ result = error_formatter.to_array
179
+ expect(result).to eq(expected_result)
180
+ end
181
+ end
182
+
183
+ context 'when receives a hash of hashes type errors' do
184
+ let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::HASH_OF_HASHES) }
185
+
186
+ let(:error_response) do
187
+ {
188
+ 'errors' => {
189
+ 'label' => {
190
+ 'pt-BR' => [
191
+ {
192
+ 'error_type' => 'CANNOT_BE_BLANK',
193
+ 'error_message' => 'cannot be blank'
194
+ }
195
+ ]
196
+ }
197
+ }
198
+ }
199
+ end
200
+
201
+ let(:error_formatter) { described_class.new(error_response) }
202
+
203
+ let(:expected_result) do
204
+ [
205
+ {
206
+ 'error_type' => 'CANNOT_BE_BLANK',
207
+ 'error_message' => 'cannot be blank',
208
+ 'path' => 'body.label.pt-BR'
209
+ }
210
+ ]
211
+ end
212
+
213
+ it 'returns an array of errors' do
214
+ result = error_formatter.to_array
215
+ expect(result).to eq(expected_result)
216
+ end
217
+ end
218
+
219
+ context 'when receives a single hash of errors' do
220
+ let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::SINGLE_HASH) }
221
+
222
+ let(:error_response) do
223
+ {
224
+ 'error' => "'lead_limiter' rate limit exceeded for 86400 second(s) period for key",
225
+ 'max' => 24,
226
+ 'usage' => 55,
227
+ 'remaining_time' => 20745
228
+ }
229
+ end
230
+
231
+ let(:error_formatter) { described_class.new(error_response) }
232
+
233
+ let(:expected_result) do
234
+ [
235
+ {
236
+ 'error_type' => 'TOO_MANY_REQUESTS',
237
+ 'error_message' => "'lead_limiter' rate limit exceeded for 86400 second(s) period for key",
238
+ 'details' => { 'max' => 24, 'usage' => 55, 'remaining_time' => 20745 }
239
+ }
240
+ ]
241
+ end
242
+
243
+ it 'returns an array of errors' do
244
+ result = error_formatter.to_array
245
+ expect(result).to eq(expected_result)
246
+ end
247
+ end
135
248
  end
136
249
  end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RDStation::ErrorHandler::InvalidRefreshToken do
4
+ describe '#raise_error' do
5
+ subject(:invalid_refresh_token) { described_class.new(errors) }
6
+
7
+ context 'when the refresh token is invalid or was revoked' do
8
+ let(:errors) do
9
+ [
10
+ {
11
+ 'error_type' => 'INVALID_REFRESH_TOKEN',
12
+ 'error_message' => 'Error Message',
13
+ }
14
+ ]
15
+ end
16
+
17
+ it 'raises an InvalidRefreshToken error' do
18
+ expect do
19
+ invalid_refresh_token.raise_error
20
+ end.to raise_error(RDStation::Error::InvalidRefreshToken, 'Error Message')
21
+ end
22
+ end
23
+
24
+ context 'when none of the errors are invalid refresh token errors' do
25
+ let(:errors) do
26
+ [
27
+ {
28
+ 'error_message' => 'Error Message',
29
+ 'error_type' => 'RANDOM_ERROR_TYPE'
30
+ },
31
+ {
32
+ 'error_message' => 'Another Error Message',
33
+ 'error_type' => 'ANOTHER_RANDOM_ERROR_TYPE'
34
+ }
35
+ ]
36
+ end
37
+
38
+ it 'does not raise an InvalidRefreshToken error' do
39
+ result = invalid_refresh_token.raise_error
40
+ expect(result).to be_nil
41
+ end
42
+ end
43
+
44
+ context 'when there are no errors' do
45
+ let(:errors) { [] }
46
+
47
+ it 'does not raise an InvalidRefreshToken error' do
48
+ result = invalid_refresh_token.raise_error
49
+ expect(result).to be_nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -151,6 +151,7 @@ RSpec.describe RDStation::ErrorHandler do
151
151
  expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServiceUnavailable, 'Error Message')
152
152
  end
153
153
  end
154
+
154
155
  context 'with 5xx error' do
155
156
  let(:http_status) { 505 }
156
157
 
@@ -158,5 +159,27 @@ RSpec.describe RDStation::ErrorHandler do
158
159
  expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServerError, 'Error Message')
159
160
  end
160
161
  end
162
+
163
+ context "when response body is not JSON-parseable" do
164
+ let(:error_response) do
165
+ OpenStruct.new(
166
+ code: 502,
167
+ headers: { 'error' => 'header' },
168
+ body: '<html><body>HTML error response</body></html>'
169
+ )
170
+ end
171
+
172
+ it 'raises the correct error' do
173
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::BadGateway, '<html><body>HTML error response</body></html>')
174
+ end
175
+ end
176
+
177
+ context 'with an unknown error' do
178
+ let(:http_status) { 123 }
179
+
180
+ it 'raises a unknown error' do
181
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::UnknownError, 'Error Message')
182
+ end
183
+ end
161
184
  end
162
185
  end
@@ -6,13 +6,13 @@ RSpec.describe RDStation::Events do
6
6
  let(:expired_access_token) { 'expired_access_token' }
7
7
 
8
8
  let(:event_with_valid_token) do
9
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: valid_access_token))
9
+ described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
10
10
  end
11
11
  let(:event_with_expired_token) do
12
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: expired_access_token))
12
+ described_class.new(authorization: RDStation::Authorization.new(access_token: expired_access_token))
13
13
  end
14
14
  let(:event_with_invalid_token) do
15
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: invalid_access_token))
15
+ described_class.new(authorization: RDStation::Authorization.new(access_token: invalid_access_token))
16
16
  end
17
17
 
18
18
  let(:events_endpoint) { 'https://api.rd.services/platform/events' }
@@ -108,6 +108,11 @@ RSpec.describe RDStation::Events do
108
108
  }
109
109
  end
110
110
 
111
+ it 'calls retryable_request' do
112
+ expect(event_with_valid_token).to receive(:retryable_request)
113
+ event_with_valid_token.create({})
114
+ end
115
+
111
116
  context 'with a valid auth token' do
112
117
  before do
113
118
  stub_request(:post, events_endpoint)
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  RSpec.describe RDStation::Fields do
4
4
  let(:valid_access_token) { 'valid_access_token' }
5
5
  let(:rdstation_fields_with_valid_token) do
6
- described_class.new(authorization_header: RDStation::AuthorizationHeader.new(access_token: valid_access_token))
6
+ described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
7
7
  end
8
8
 
9
9
  let(:valid_headers) do
@@ -38,6 +38,11 @@ RSpec.describe RDStation::Fields do
38
38
  }
39
39
  end
40
40
 
41
+ it 'calls retryable_request' do
42
+ expect(rdstation_fields_with_valid_token).to receive(:retryable_request)
43
+ rdstation_fields_with_valid_token.all
44
+ end
45
+
41
46
  context 'with a valid auth token' do
42
47
  before do
43
48
  stub_request(:get, fields_endpoint)
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+
3
+ class DummyClass
4
+ include ::RDStation::RetryableRequest
5
+ end
6
+
7
+ RSpec.describe RDStation::RetryableRequest do
8
+ let(:subject) { DummyClass.new }
9
+ describe '.retryable_request' do
10
+ context 'when authorization has a valid refresh_token and config is provided' do
11
+ let (:access_token) { 'access_token' }
12
+ let (:new_access_token) { 'new_access_token' }
13
+ let (:refresh_token) { 'refresh_token' }
14
+ let (:auth) do
15
+ ::RDStation::Authorization.new(access_token: access_token,
16
+ refresh_token: refresh_token
17
+ )
18
+ end
19
+ context 'original request was successful' do
20
+ it 'yields control to the given block' do
21
+ expect do |block|
22
+ subject.retryable_request(auth, &block)
23
+ end.to yield_with_args(auth)
24
+ end
25
+ end
26
+
27
+ context 'original request raised a retryable exception' do
28
+ let (:auth_new_access_token) do
29
+ ::RDStation::Authorization.new(access_token: new_access_token,
30
+ refresh_token: refresh_token
31
+ )
32
+ end
33
+
34
+ let(:new_credentials) do
35
+ {
36
+ 'access_token' => new_access_token,
37
+ 'expires_in' => 86_400,
38
+ 'refresh_token' => refresh_token
39
+ }
40
+ end
41
+ let(:authentication_client) {instance_double(::RDStation::Authentication) }
42
+
43
+ before do
44
+ RDStation.configure do |config|
45
+ config.client_id = "123"
46
+ config.client_secret = "312"
47
+ config.on_access_token_refresh do
48
+ 'callback code'
49
+ end
50
+ end
51
+ allow(::RDStation::Authentication).to receive(:new)
52
+ .with(no_args)
53
+ .and_return(authentication_client)
54
+ allow(authentication_client).to receive(:update_access_token)
55
+ .with(auth.refresh_token).
56
+ and_return(new_credentials)
57
+ end
58
+
59
+ it 'refreshes the access_token and retries the request' do
60
+ dummy_request = double("dummy_request")
61
+ expect(dummy_request).to receive(:call).twice do |auth|
62
+ expired_token = ::RDStation::Error::ExpiredAccessToken.new({'error_message' => 'x'})
63
+ raise expired_token unless auth.access_token == new_access_token
64
+ end
65
+
66
+ expect(RDStation.configuration.access_token_refresh_callback)
67
+ .to receive(:call)
68
+ .once do |authorization|
69
+ expect(authorization.access_token).to eq new_access_token
70
+ end
71
+
72
+ expect do
73
+ subject.retryable_request(auth) { |yielded_auth| dummy_request.call(yielded_auth) }
74
+ end.not_to raise_error
75
+ end
76
+
77
+ context 'and keeps raising retryable exception event after token refreshed' do
78
+ it 'retries only once' do
79
+ dummy_request = double("dummy_request")
80
+ expect(dummy_request).to receive(:call).twice do |_|
81
+ raise ::RDStation::Error::ExpiredAccessToken.new({'error_message' => 'x'})
82
+ end
83
+
84
+ expect do
85
+ subject.retryable_request(auth) { |yielded_auth| dummy_request.call(yielded_auth) }
86
+ end.to raise_error ::RDStation::Error::ExpiredAccessToken
87
+ end
88
+ end
89
+
90
+ context 'and access token refresh callback is not set' do
91
+ before do
92
+ RDStation.configure do |config|
93
+ config.on_access_token_refresh(&nil)
94
+ end
95
+ end
96
+
97
+ it 'executes the refresh and retry without raising an error' do
98
+ dummy_request = double("dummy_request")
99
+ expect(dummy_request).to receive(:call).twice do |auth|
100
+ expired_token = ::RDStation::Error::ExpiredAccessToken.new({'error_message' => 'x'})
101
+ raise expired_token unless auth.access_token == new_access_token
102
+ end
103
+
104
+ expect do
105
+ subject.retryable_request(auth) { |yielded_auth| dummy_request.call(yielded_auth) }
106
+ end.not_to raise_error
107
+ end
108
+ end
109
+ end
110
+
111
+ context 'original request raised a non retryable exception' do
112
+ it 'raises error' do
113
+ dummy_request = double("dummy_request")
114
+ expect(dummy_request).to receive(:call).once do |_|
115
+ raise RuntimeError.new("a non retryable error")
116
+ end
117
+
118
+ expect do
119
+ subject.retryable_request(auth) { |yielded_auth| dummy_request.call(yielded_auth) }
120
+ end.to raise_error RuntimeError
121
+ end
122
+ end
123
+ end
124
+
125
+ context 'all legacy scenarios' do
126
+ let (:access_token) { 'access_token' }
127
+ let (:auth) { ::RDStation::Authorization.new(access_token: access_token) }
128
+
129
+ it 'implement me' do
130
+ dummy_request = double("dummy_request")
131
+ expect(dummy_request).to receive(:call).once do |_|
132
+ raise ::RDStation::Error::ExpiredAccessToken.new({'error_message' => 'x'})
133
+ end
134
+
135
+ expect do
136
+ subject.retryable_request(auth) { |yielded_auth| dummy_request.call(yielded_auth) }
137
+ end.to raise_error ::RDStation::Error::ExpiredAccessToken
138
+ end
139
+ end
140
+
141
+ end
142
+ end