rdstation-ruby-client 2.0.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +116 -4
- data/README.md +114 -22
- data/lib/rdstation-ruby-client.rb +6 -1
- data/lib/rdstation.rb +19 -0
- data/lib/rdstation/api_response.rb +1 -2
- data/lib/rdstation/authentication.rb +32 -3
- data/lib/rdstation/{authorization_header.rb → authorization.rb} +11 -8
- data/lib/rdstation/builder/field.rb +70 -0
- data/lib/rdstation/client.rb +17 -7
- data/lib/rdstation/contacts.rb +22 -13
- data/lib/rdstation/error.rb +2 -0
- data/lib/rdstation/error/format.rb +29 -3
- data/lib/rdstation/error/formatter.rb +69 -8
- data/lib/rdstation/error_handler.rb +6 -1
- data/lib/rdstation/events.rb +7 -12
- data/lib/rdstation/fields.rb +35 -6
- data/lib/rdstation/retryable_request.rb +35 -0
- data/lib/rdstation/version.rb +1 -1
- data/lib/rdstation/webhooks.rb +25 -13
- data/rdstation-ruby-client.gemspec +2 -1
- data/spec/lib/rdstation/api_response_spec.rb +34 -0
- data/spec/lib/rdstation/authentication_spec.rb +164 -0
- data/spec/lib/rdstation/{authorization_header_spec.rb → authorization_spec.rb} +3 -3
- data/spec/lib/rdstation/builder/field_spec.rb +69 -0
- data/spec/lib/rdstation/client_spec.rb +6 -6
- data/spec/lib/rdstation/contacts_spec.rb +23 -3
- data/spec/lib/rdstation/error/format_spec.rb +63 -0
- data/spec/lib/rdstation/error/formatter_spec.rb +113 -0
- data/spec/lib/rdstation/error_handler_spec.rb +23 -0
- data/spec/lib/rdstation/events_spec.rb +8 -3
- data/spec/lib/rdstation/fields_spec.rb +6 -1
- data/spec/lib/rdstation/retryable_request_spec.rb +142 -0
- data/spec/lib/rdstation/webhooks_spec.rb +26 -1
- data/spec/lib/rdstation_spec.rb +18 -0
- metadata +36 -11
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
RSpec.describe RDStation::
|
3
|
+
RSpec.describe RDStation::Authorization do
|
4
4
|
|
5
5
|
describe ".initialize" do
|
6
6
|
context "when access_token is nil" do
|
@@ -12,11 +12,11 @@ RSpec.describe RDStation::AuthorizationHeader do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
describe "#
|
15
|
+
describe "#headers" do
|
16
16
|
let(:access_token) { 'access_token' }
|
17
17
|
|
18
18
|
it "generates the correct header" do
|
19
|
-
header = described_class.new(access_token: access_token).
|
19
|
+
header = described_class.new(access_token: access_token).headers
|
20
20
|
expect(header['Authorization']).to eq "Bearer #{access_token}"
|
21
21
|
expect(header['Content-Type']).to eq "application/json"
|
22
22
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe RDStation::Builder::Field do
|
6
|
+
def valid_builder
|
7
|
+
described_class.new('cf_identifier')
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'when create a builder' do
|
11
|
+
context 'valid' do
|
12
|
+
let(:initial_parameters) do
|
13
|
+
'cf_api_identifier'
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:builder) { described_class.new(initial_parameters) }
|
17
|
+
|
18
|
+
let(:expected_result) do
|
19
|
+
{
|
20
|
+
'api_identifier' => 'cf_api_identifier',
|
21
|
+
'data_type' => 'STRING',
|
22
|
+
'presentation_type' => 'TEXT_INPUT',
|
23
|
+
'label' => { 'pt-BR' => 'My label' },
|
24
|
+
'name' => { 'pt-BR' => 'My name' }
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns an hash of required values' do
|
29
|
+
builder.label 'pt-BR', 'My label'
|
30
|
+
builder.name 'pt-BR', 'My name'
|
31
|
+
builder.data_type 'STRING'
|
32
|
+
builder.presentation_type 'TEXT_INPUT'
|
33
|
+
|
34
|
+
result = builder.build
|
35
|
+
expect(result).to eq(expected_result)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'invalid' do
|
40
|
+
it 'using invalid api_identifier ' do
|
41
|
+
expect { described_class.new('invald_identifier') }.to raise_error(
|
42
|
+
'api_identifier is not in a valid format, need start with "cf_"'
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'using invalid data_type ' do
|
47
|
+
expect { valid_builder.data_type('invalid_data_type') }.to raise_error(
|
48
|
+
'Not valid data_type - ["STRING", "INTEGER", "BOOLEAN", "STRING[]"]'
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'using invalid presentation_type ' do
|
53
|
+
expect { valid_builder.presentation_type('invalid presentation_type') }.to raise_error(
|
54
|
+
'Not valid presentation_type - ["TEXT_INPUT", "TEXT_AREA", "URL_INPUT", "PHONE_INPUT", "EMAIL_INPUT", "CHECK_BOX", "NUMBER_INPUT", "COMBO_BOX", "RADIO_BUTTON", "MULTIPLE_CHOICE"]'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'without api_identifier' do
|
59
|
+
expect { described_class.new(nil) }.to raise_error('api_identifier required')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'without required fields' do
|
63
|
+
expect { valid_builder.build }.to raise_error(
|
64
|
+
'Required fields are missing - ["data_type", "presentation_type", "label", "name"]'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -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(:
|
7
|
+
let(:mock_authorization) { double(RDStation::Authorization) }
|
8
8
|
|
9
|
-
before { allow(RDStation::
|
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({
|
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({
|
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({
|
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({
|
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(
|
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(
|
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(
|
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
|
@@ -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(
|
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(
|
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(
|
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(
|
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)
|