rdstation-ruby-client 1.2.1 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/rdsm-ruby-client-issue-template.md +49 -0
  3. data/.rspec +2 -0
  4. data/CHANGELOG.md +167 -0
  5. data/README.md +243 -43
  6. data/lib/rdstation-ruby-client.rb +6 -0
  7. data/lib/rdstation.rb +19 -0
  8. data/lib/rdstation/api_response.rb +3 -3
  9. data/lib/rdstation/authentication.rb +32 -3
  10. data/lib/rdstation/authorization.rb +24 -0
  11. data/lib/rdstation/builder/field.rb +70 -0
  12. data/lib/rdstation/client.rb +17 -74
  13. data/lib/rdstation/contacts.rb +21 -16
  14. data/lib/rdstation/error.rb +23 -15
  15. data/lib/rdstation/error/format.rb +21 -3
  16. data/lib/rdstation/error/formatter.rb +53 -7
  17. data/lib/rdstation/error_handler.rb +31 -26
  18. data/lib/rdstation/error_handler/bad_request.rb +30 -0
  19. data/lib/rdstation/error_handler/unauthorized.rb +17 -9
  20. data/lib/rdstation/events.rb +7 -19
  21. data/lib/rdstation/fields.rb +31 -7
  22. data/lib/rdstation/retryable_request.rb +35 -0
  23. data/lib/rdstation/version.rb +1 -1
  24. data/lib/rdstation/webhooks.rb +25 -17
  25. data/rdstation-ruby-client.gemspec +4 -1
  26. data/spec/lib/rdstation-ruby-client_spec.rb +1 -1
  27. data/spec/lib/rdstation/api_response_spec.rb +34 -0
  28. data/spec/lib/rdstation/authentication_spec.rb +164 -0
  29. data/spec/lib/rdstation/authorization_spec.rb +24 -0
  30. data/spec/lib/rdstation/builder/field_spec.rb +69 -0
  31. data/spec/lib/rdstation/client_spec.rb +37 -0
  32. data/spec/lib/rdstation/contacts_spec.rb +54 -41
  33. data/spec/lib/rdstation/error/format_spec.rb +46 -0
  34. data/spec/lib/rdstation/error/formatter_spec.rb +83 -0
  35. data/spec/lib/rdstation/error_handler/unauthorized_spec.rb +0 -29
  36. data/spec/lib/rdstation/error_handler_spec.rb +162 -26
  37. data/spec/lib/rdstation/events_spec.rb +20 -9
  38. data/spec/lib/rdstation/fields_spec.rb +10 -3
  39. data/spec/lib/rdstation/retryable_request_spec.rb +142 -0
  40. data/spec/lib/rdstation/webhooks_spec.rb +41 -13
  41. data/spec/lib/rdstation_spec.rb +18 -0
  42. metadata +41 -12
  43. data/lib/rdstation/error_handler/default.rb +0 -15
  44. data/lib/rdstation/error_handler/resource_not_found.rb +0 -24
  45. data/spec/lib/rdstation/error_handler/default_spec.rb +0 -14
  46. data/spec/lib/rdstation/error_handler/resource_not_found_spec.rb +0 -54
@@ -52,5 +52,51 @@ 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
55
101
  end
56
102
  end
@@ -132,5 +132,88 @@ 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
135
218
  end
136
219
  end
@@ -21,34 +21,5 @@ RSpec.describe RDStation::ErrorHandler::Unauthorized do
21
21
  end.to raise_error(RDStation::Error::Unauthorized, 'Error Message')
22
22
  end
23
23
  end
24
-
25
- context 'when none of the errors are unauthorized errors' do
26
- let(:errors) do
27
- [
28
- {
29
- 'error_message' => 'Error Message',
30
- 'error_type' => 'RANDOM_ERROR_TYPE'
31
- },
32
- {
33
- 'error_message' => 'Another Error Message',
34
- 'error_type' => 'ANOTHER_RANDOM_ERROR_TYPE'
35
- }
36
- ]
37
- end
38
-
39
- it 'does not raise an Unauthorized error' do
40
- result = unauthorized_error.raise_error
41
- expect(result).to be_nil
42
- end
43
- end
44
-
45
- context 'when there are no errors' do
46
- let(:errors) { [] }
47
-
48
- it 'does not raise an Unauthorized error' do
49
- result = unauthorized_error.raise_error
50
- expect(result).to be_nil
51
- end
52
- end
53
24
  end
54
25
  end
@@ -4,45 +4,181 @@ RSpec.describe RDStation::ErrorHandler do
4
4
  describe '#raise_errors' do
5
5
  subject(:error_handler) { described_class.new(error_response) }
6
6
 
7
- context 'when the error type is recognized' do
8
- let(:error_response) do
9
- OpenStruct.new(
10
- code: 400,
11
- body: {
7
+ let(:array_of_errors) do
8
+ [
9
+ {
10
+ 'error_type' => 'ERROR_TYPE',
11
+ 'error_message' => 'Error Message',
12
+ 'headers' => { 'error' => 'header' },
13
+ 'http_status' => http_status,
14
+ 'body' => {
12
15
  'errors' => {
13
- 'error_type' => 'CONFLICTING_FIELD',
16
+ 'error_type' => 'ERROR_TYPE',
14
17
  'error_message' => 'Error Message'
15
18
  }
16
- }.to_json
17
- )
19
+ }
20
+ }
21
+ ]
22
+ end
23
+
24
+ let(:error_response) do
25
+ OpenStruct.new(
26
+ code: http_status,
27
+ headers: { 'error' => 'header' },
28
+ body: {
29
+ 'errors' => {
30
+ 'error_type' => 'ERROR_TYPE',
31
+ 'error_message' => 'Error Message'
32
+ }
33
+ }.to_json
34
+ )
35
+ end
36
+
37
+ context 'with an error 400' do
38
+ let(:http_status) { 400 }
39
+
40
+ let(:bad_request_handler) { instance_double(RDStation::ErrorHandler::BadRequest, raise_error: 'raised error') }
41
+
42
+ before do
43
+ allow(RDStation::ErrorHandler::BadRequest).to receive(:new).with(array_of_errors).and_return(bad_request_handler)
44
+ end
45
+
46
+ it 'calls the bad request error handler' do
47
+ error_handler.raise_error
48
+ expect(bad_request_handler).to have_received(:raise_error)
49
+ end
50
+ end
51
+
52
+ context 'with an error 401' do
53
+ let(:http_status) { 401 }
54
+
55
+ let(:unauthorized_handler) { instance_double(RDStation::ErrorHandler::Unauthorized, raise_error: 'raised error') }
56
+
57
+ before do
58
+ allow(RDStation::ErrorHandler::Unauthorized).to receive(:new).with(array_of_errors).and_return(unauthorized_handler)
59
+ end
60
+
61
+ it 'calls the unauthorized error handler' do
62
+ error_handler.raise_error
63
+ expect(unauthorized_handler).to have_received(:raise_error)
18
64
  end
65
+ end
66
+
67
+ context 'with an error 403' do
68
+ let(:http_status) { 403 }
69
+
70
+ it 'raises a forbidden error' do
71
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::Forbidden, 'Error Message')
72
+ end
73
+ end
74
+
75
+ context 'with an error 404' do
76
+ let(:http_status) { 404 }
77
+
78
+ it 'raises a not found error' do
79
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::NotFound, 'Error Message')
80
+ end
81
+ end
82
+
83
+ context 'with an error 405' do
84
+ let(:http_status) { 405 }
85
+
86
+ it 'raises a method not allowed error' do
87
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::MethodNotAllowed, 'Error Message')
88
+ end
89
+ end
90
+
91
+ context 'with an error 406' do
92
+ let(:http_status) { 406 }
93
+
94
+ it 'raises a not acceptable error' do
95
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::NotAcceptable, 'Error Message')
96
+ end
97
+ end
98
+
99
+ context 'with an error 409' do
100
+ let(:http_status) { 409 }
19
101
 
20
- it 'raises the corresponding error class' do
21
- expect { error_handler.raise_errors }.to raise_error(RDStation::Error::ConflictingField, 'Error Message')
102
+ it 'raises a conflict error' do
103
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::Conflict, 'Error Message')
22
104
  end
23
105
  end
24
106
 
25
- context 'when the error type is not recognized' do
107
+ context 'with an error 415' do
108
+ let(:http_status) { 415 }
109
+
110
+ it 'raises an unsupported media type error' do
111
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::UnsupportedMediaType, 'Error Message')
112
+ end
113
+ end
114
+
115
+ context 'with an error 422' do
116
+ let(:http_status) { 422 }
117
+
118
+ it 'raises an unprocessable entity error' do
119
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::UnprocessableEntity, 'Error Message')
120
+ end
121
+ end
122
+
123
+ context 'with an error 500' do
124
+ let(:http_status) { 500 }
125
+
126
+ it 'raises an internal server error' do
127
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::InternalServerError, 'Error Message')
128
+ end
129
+ end
130
+
131
+ context 'with an error 501' do
132
+ let(:http_status) { 501 }
133
+
134
+ it 'raises a not implemented error' do
135
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::NotImplemented, 'Error Message')
136
+ end
137
+ end
138
+
139
+ context 'with an error 502' do
140
+ let(:http_status) { 502 }
141
+
142
+ it 'raises a bad gateway error' do
143
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::BadGateway, 'Error Message')
144
+ end
145
+ end
146
+
147
+ context 'with an error 503' do
148
+ let(:http_status) { 503 }
149
+
150
+ it 'raises a service unavailable error' do
151
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServiceUnavailable, 'Error Message')
152
+ end
153
+ end
154
+
155
+ context 'with 5xx error' do
156
+ let(:http_status) { 505 }
157
+
158
+ it 'raises a server error' do
159
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServerError, 'Error Message')
160
+ end
161
+ end
162
+
163
+ context "when response body is not JSON-parseable" do
26
164
  let(:error_response) do
27
165
  OpenStruct.new(
28
- code: 400,
29
- headers: { 'Content-Type' => 'application/json' },
30
- body: {
31
- 'errors' => {
32
- 'error_type' => 'UNRECOGNIZED_ERROR_TYPE',
33
- 'error_message' => 'Error Message'
34
- }
35
- }.to_json
166
+ code: 502,
167
+ headers: { 'error' => 'header' },
168
+ body: '<html><body>HTML error response</body></html>'
36
169
  )
37
170
  end
38
171
 
39
- it 'raises the Default error' do
40
- expect { error_handler.raise_errors }.to raise_error(RDStation::Error::Default, 'Error Message') do |error|
41
- expect(error.details).to be
42
- expect(error.headers).to be
43
- expect(error.body).to be
44
- expect(error.http_status).to be
45
- end
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')
46
182
  end
47
183
  end
48
184
  end
@@ -1,13 +1,19 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe RDStation::Events do
4
- let(:valid_auth_token) { 'valid_auth_token' }
5
- let(:invalid_auth_token) { 'invalid_auth_token' }
6
- let(:expired_auth_token) { 'expired_auth_token' }
4
+ let(:valid_access_token) { 'valid_access_token' }
5
+ let(:invalid_access_token) { 'invalid_access_token' }
6
+ let(:expired_access_token) { 'expired_access_token' }
7
7
 
8
- let(:event_with_valid_token) { described_class.new(valid_auth_token) }
9
- let(:event_with_expired_token) { described_class.new(expired_auth_token) }
10
- let(:event_with_invalid_token) { described_class.new(invalid_auth_token) }
8
+ let(:event_with_valid_token) do
9
+ described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
10
+ end
11
+ let(:event_with_expired_token) do
12
+ described_class.new(authorization: RDStation::Authorization.new(access_token: expired_access_token))
13
+ end
14
+ let(:event_with_invalid_token) do
15
+ described_class.new(authorization: RDStation::Authorization.new(access_token: invalid_access_token))
16
+ end
11
17
 
12
18
  let(:events_endpoint) { 'https://api.rd.services/platform/events' }
13
19
 
@@ -45,21 +51,21 @@ RSpec.describe RDStation::Events do
45
51
 
46
52
  let(:valid_headers) do
47
53
  {
48
- 'Authorization' => "Bearer #{valid_auth_token}",
54
+ 'Authorization' => "Bearer #{valid_access_token}",
49
55
  'Content-Type' => 'application/json'
50
56
  }
51
57
  end
52
58
 
53
59
  let(:invalid_token_headers) do
54
60
  {
55
- 'Authorization' => "Bearer #{invalid_auth_token}",
61
+ 'Authorization' => "Bearer #{invalid_access_token}",
56
62
  'Content-Type' => 'application/json'
57
63
  }
58
64
  end
59
65
 
60
66
  let(:expired_token_headers) do
61
67
  {
62
- 'Authorization' => "Bearer #{expired_auth_token}",
68
+ 'Authorization' => "Bearer #{expired_access_token}",
63
69
  'Content-Type' => 'application/json'
64
70
  }
65
71
  end
@@ -102,6 +108,11 @@ RSpec.describe RDStation::Events do
102
108
  }
103
109
  end
104
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
+
105
116
  context 'with a valid auth token' do
106
117
  before do
107
118
  stub_request(:post, events_endpoint)
@@ -1,12 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe RDStation::Fields do
4
- let(:valid_auth_token) { 'valid_auth_token' }
5
- let(:rdstation_fields_with_valid_token) { described_class.new(valid_auth_token) }
4
+ let(:valid_access_token) { 'valid_access_token' }
5
+ let(:rdstation_fields_with_valid_token) do
6
+ described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
7
+ end
6
8
 
7
9
  let(:valid_headers) do
8
10
  {
9
- 'Authorization' => "Bearer #{valid_auth_token}",
11
+ 'Authorization' => "Bearer #{valid_access_token}",
10
12
  'Content-Type' => 'application/json'
11
13
  }
12
14
  end
@@ -36,6 +38,11 @@ RSpec.describe RDStation::Fields do
36
38
  }
37
39
  end
38
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
+
39
46
  context 'with a valid auth token' do
40
47
  before do
41
48
  stub_request(:get, fields_endpoint)