clever_tap_dubit 0.3.2
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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +48 -0
- data/.travis.yml +6 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +164 -0
- data/Rakefile +6 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/clever_tap.gemspec +33 -0
- data/lib/clever_tap/client.rb +113 -0
- data/lib/clever_tap/config.rb +25 -0
- data/lib/clever_tap/entity.rb +87 -0
- data/lib/clever_tap/event.rb +30 -0
- data/lib/clever_tap/failed_response.rb +28 -0
- data/lib/clever_tap/profile.rb +7 -0
- data/lib/clever_tap/response.rb +34 -0
- data/lib/clever_tap/successful_response.rb +30 -0
- data/lib/clever_tap/uploader.rb +72 -0
- data/lib/clever_tap/version.rb +3 -0
- data/lib/clever_tap.rb +79 -0
- data/lib/clevertap-ruby.rb +1 -0
- data/spec/factories/profile.rb +36 -0
- data/spec/integrations/clever_tap_spec.rb +81 -0
- data/spec/rubocop_spec.rb +12 -0
- data/spec/shared/clever_tap_client.rb +13 -0
- data/spec/shared/entity.rb +105 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/units/clever_tap_client_spec.rb +277 -0
- data/spec/units/clever_tap_spec.rb +88 -0
- data/spec/units/event_spec.rb +43 -0
- data/spec/units/failed_response_spec.rb +31 -0
- data/spec/units/profile_spec.rb +29 -0
- data/spec/units/response_spec.rb +63 -0
- data/spec/units/successful_response_spec.rb +112 -0
- data/spec/units/uploader_spec.rb +129 -0
- data/spec/vcr_cassettes/CleverTap/uploading_a_many_profiles/when_only_some_are_valid/partially_succeds.yml +42 -0
- data/spec/vcr_cassettes/CleverTap/uploading_a_profile/when_is_invalid/fails.yml +41 -0
- data/spec/vcr_cassettes/CleverTap/uploading_a_profile/when_is_valid/succeed.yml +35 -0
- data/spec/vcr_cassettes/CleverTap/uploading_an_event/when_is_valid/succeed.yml +34 -0
- data/spec/vcr_cassettes/CleverTap_Client/_upload/when_upload_records_are_homogenous/and_invalid_records/calls_on_failed_upload_once.yml +38 -0
- data/spec/vcr_cassettes/CleverTap_Client/_upload/when_upload_records_are_homogenous/and_invalid_records/returns_an_array_with_one_failed_Response_object.yml +38 -0
- data/spec/vcr_cassettes/CleverTap_Client/_upload/when_upload_records_are_homogenous/and_valid_records/and_objects_do_not_fit_upload_limit_/calls_on_successful_upload_proc_twice.yml +67 -0
- data/spec/vcr_cassettes/CleverTap_Client/_upload/when_upload_records_are_homogenous/and_valid_records/and_objects_do_not_fit_upload_limit_/returns_an_array_with_two_successful_Response_objects.yml +67 -0
- data/spec/vcr_cassettes/CleverTap_Client/_upload/when_upload_records_are_homogenous/and_valid_records/and_objects_fit_upload_limit_/calls_on_successful_upload_proc_once.yml +36 -0
- data/spec/vcr_cassettes/CleverTap_Client/_upload/when_upload_records_are_homogenous/and_valid_records/and_objects_fit_upload_limit_/returns_an_array_with_one_successful_Response_object.yml +36 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_age_is_invalid/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +48 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_education_status_is_invalid/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +49 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_email_is_invalid/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +48 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_employment_status_is_invalid/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +48 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_marital_status_is_invalid/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +48 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_phone_is_invalid/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +48 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/when_the_creation_date_field_is_missing/behaves_like_validation_failure/failed_to_upload_the_profiles.yml +48 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/with_invalid_credentials/failed_to_upload_the_profiles.yml +36 -0
- data/spec/vcr_cassettes/CleverTap_Uploader/_call/with_valid_data/makes_successful_upload.yml +36 -0
- data/spec/vcr_config.rb +13 -0
- metadata +192 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/clever_tap_client'
|
3
|
+
|
4
|
+
describe CleverTap::Client, vcr: true do
|
5
|
+
subject { described_class.new('123456', 'passcode') }
|
6
|
+
|
7
|
+
describe 'authentication' do
|
8
|
+
it 'send right `account_id`' do
|
9
|
+
expect(subject.connection.headers['X-CleverTap-Account-Id']).to eq('123456')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'send right `passcode`' do
|
13
|
+
expect(subject.connection.headers['X-CleverTap-Passcode']).to eq('passcode')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'customisations' do
|
18
|
+
context 'with different adapter' do
|
19
|
+
subject do
|
20
|
+
described_class.new('123456', 'passcode') { |config| config.adapter(:test) }
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'override the default adapter' do
|
24
|
+
adapter = subject.connection.builder.adapter
|
25
|
+
|
26
|
+
expect(adapter).to eq(Faraday::Adapter::Test)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'without an adapter' do
|
31
|
+
subject { described_class.new('123456', 'passcode') }
|
32
|
+
|
33
|
+
it 'use Net::HTTP adapter' do
|
34
|
+
adapter = subject.connection.builder.adapter
|
35
|
+
|
36
|
+
expect(adapter).to eq(Faraday::Adapter::NetHttp)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#new' do
|
42
|
+
let(:identity_field) { 'ID' }
|
43
|
+
let(:account_id) { 'ABC1234' }
|
44
|
+
let(:account_passcode) { 'AcCPasScoDe123' }
|
45
|
+
|
46
|
+
context 'when credentials set in `CleverTap.setup`' do
|
47
|
+
subject { CleverTap::Client.new }
|
48
|
+
|
49
|
+
before do
|
50
|
+
CleverTap.setup do |config|
|
51
|
+
config.identity_field = identity_field
|
52
|
+
config.account_id = account_id
|
53
|
+
config.account_passcode = account_passcode
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it_behaves_like 'configured `Client`'
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when credentials set in `CleverTap::Client.new`' do
|
61
|
+
subject { CleverTap::Client.new(account_id, account_passcode) }
|
62
|
+
it_behaves_like 'configured `Client`'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def event_factory(id, name)
|
67
|
+
CleverTap::Event.new(
|
68
|
+
data: { 'FBID' => id.to_s, 'Name' => name.to_s },
|
69
|
+
name: 'Web Event',
|
70
|
+
identity: 'FBID'
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def profile_factory
|
75
|
+
CleverTap::Profile.new(
|
76
|
+
data: { 'ID' => '1414', 'Name' => 'John', 'Phone' => '+44+441234' }
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#upload' do
|
81
|
+
let(:success_proc) { proc { 'sample proc' } }
|
82
|
+
let(:response) { subject.upload([event1, event2]) }
|
83
|
+
|
84
|
+
subject do
|
85
|
+
client = described_class.new
|
86
|
+
client.on_successful_upload(&success_proc)
|
87
|
+
client
|
88
|
+
end
|
89
|
+
|
90
|
+
before do
|
91
|
+
CleverTap.setup do |c|
|
92
|
+
c.identity_field = 'ID'
|
93
|
+
c.account_id = AUTH_ACCOUNT_ID
|
94
|
+
c.account_passcode = AUTH_PASSCODE
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when upload records are homogenous' do
|
99
|
+
context 'and valid records' do
|
100
|
+
let(:event1) { event_factory('1414', 'John') }
|
101
|
+
let(:event2) { event_factory('1515', 'Jill') }
|
102
|
+
|
103
|
+
context 'and objects fit `upload_limit`' do
|
104
|
+
VCR.use_cassette('upload within Event limit') do
|
105
|
+
it 'returns an array with one successful `Response` object' do
|
106
|
+
expect(response.count).to eq 1
|
107
|
+
expect(response.first.success).to be true
|
108
|
+
expect(response.first).to be_a(CleverTap::Response)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'calls `on_successful_upload` proc once' do
|
112
|
+
expect(success_proc).to receive(:call).once
|
113
|
+
subject.upload([event1, event2])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'and objects do not fit `upload_limit`' do
|
119
|
+
before do
|
120
|
+
allow(CleverTap::Event)
|
121
|
+
.to receive(:upload_limit).and_return(1)
|
122
|
+
end
|
123
|
+
|
124
|
+
VCR.use_cassette('upload out of Event limit') do
|
125
|
+
it 'returns an array with two successful `Response` objects' do
|
126
|
+
expect(response.count).to eq 2
|
127
|
+
expect(response.all?(&:success)).to be true
|
128
|
+
expect(
|
129
|
+
response.all? { |r| r.class == CleverTap::Response }
|
130
|
+
).to be true
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'calls `on_successful_upload` proc twice' do
|
134
|
+
expect(success_proc).to receive(:call).twice
|
135
|
+
subject.upload([event1, event2])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'and invalid records' do
|
142
|
+
let(:failure_proc) { proc { 'sample proc' } }
|
143
|
+
let(:response) { subject.upload([profile]) }
|
144
|
+
|
145
|
+
subject do
|
146
|
+
client = described_class.new
|
147
|
+
client.on_failed_upload(&failure_proc)
|
148
|
+
client
|
149
|
+
end
|
150
|
+
|
151
|
+
let(:profile) { profile_factory }
|
152
|
+
|
153
|
+
it 'returns an array with one failed `Response` object' do
|
154
|
+
expect(response.count).to eq 1
|
155
|
+
expect(response.first.class).to eq CleverTap::Response
|
156
|
+
expect(response.first.success).to be false
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'calls `on_failed_upload` once' do
|
160
|
+
expect(failure_proc).to receive(:call).once
|
161
|
+
subject.upload([profile])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'when objects are not homogenous' do
|
167
|
+
let(:event1) { event_factory('1414', 'John') }
|
168
|
+
let(:event2) { {} }
|
169
|
+
|
170
|
+
it 'raises `NotConsistentArrayError`' do
|
171
|
+
expect { subject.upload([event1, event2]) }.to raise_error CleverTap::NotConsistentArrayError
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe '#request_body' do
|
177
|
+
subject { described_class.new('123456', 'passcode') }
|
178
|
+
let(:records) do
|
179
|
+
[
|
180
|
+
{ 'ID' => '123', 'Name' => 'John' },
|
181
|
+
{ 'ID' => '456', 'Name' => 'Jill' }
|
182
|
+
]
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'converts records hash to json' do
|
186
|
+
expect(subject.send(:request_body, records))
|
187
|
+
.to eq({ 'd' => records }.to_json)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe '#determine_type' do
|
192
|
+
subject { described_class.new('123456', 'passcode') }
|
193
|
+
|
194
|
+
context 'when records are of the same type' do
|
195
|
+
let(:records) { [{}, {}] }
|
196
|
+
|
197
|
+
it 'returns the class of the elements' do
|
198
|
+
expect(subject.send(:determine_type, records)).to eq Hash
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'when records are of different type' do
|
203
|
+
let(:records) { [{}, []] }
|
204
|
+
|
205
|
+
it 'raises `NotConsistentArrayError`' do
|
206
|
+
expect { subject.send(:determine_type, records) }.to raise_error CleverTap::NotConsistentArrayError
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#ensure_array' do
|
212
|
+
subject { described_class.new('123456', 'passcode') }
|
213
|
+
let(:records) { %w[sample sample2] }
|
214
|
+
let(:record) { 'sample' }
|
215
|
+
|
216
|
+
it 'returns an array when an array passed' do
|
217
|
+
expect(subject.send(:ensure_array, records)).to eq records
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'returns an array when a single element passed' do
|
221
|
+
expect(subject.send(:ensure_array, record)).to eq [record]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe 'setting `account_id` and `passcode`' do
|
226
|
+
subject { described_class.new(client_id, client_passcode) }
|
227
|
+
let(:client_id) { '123456' }
|
228
|
+
let(:client_passcode) { 'passcode' }
|
229
|
+
let(:config_id) { 'config_account_id' }
|
230
|
+
let(:config_passcode) { 'config_passcode' }
|
231
|
+
|
232
|
+
def config_client(account, pass)
|
233
|
+
CleverTap.setup do |c|
|
234
|
+
c.account_id = account
|
235
|
+
c.account_passcode = pass
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'when credentials provided in configuration' do
|
240
|
+
before { config_client(config_id, config_passcode) }
|
241
|
+
|
242
|
+
context 'and in initialization as well' do
|
243
|
+
it 'has initialization values' do
|
244
|
+
expect(subject.send(:assign_account_id, client_id)).to eq client_id
|
245
|
+
expect(subject.send(:assign_passcode, client_passcode)).to eq client_passcode
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'and not in initialization' do
|
250
|
+
it 'has initialization values' do
|
251
|
+
expect(subject.send(:assign_account_id, nil)).to eq config_id
|
252
|
+
expect(subject.send(:assign_passcode, nil)).to eq config_passcode
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'when credentials not provided in configuration' do
|
258
|
+
before { config_client(nil, nil) }
|
259
|
+
|
260
|
+
context 'but provided in initialization' do
|
261
|
+
it 'has initialization values' do
|
262
|
+
expect(subject.send(:assign_account_id, client_id)).to eq client_id
|
263
|
+
expect(subject.send(:assign_passcode, client_passcode)).to eq client_passcode
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'and not provided in initialization as well' do
|
268
|
+
before { config_client(nil, nil) }
|
269
|
+
subject { described_class.new }
|
270
|
+
|
271
|
+
it 'raises a `RuntimeError` error' do
|
272
|
+
expect { subject }.to raise_error RuntimeError
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CleverTap do
|
4
|
+
describe '#new' do
|
5
|
+
context 'with valid arguments' do
|
6
|
+
context 'with keyword arguments' do
|
7
|
+
subject(:clever_tap) do
|
8
|
+
CleverTap.new(account_id: 'foo',
|
9
|
+
passcode: 'passcode',
|
10
|
+
identity_field: 'ID',
|
11
|
+
configure_faraday: configure_faraday)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:configure_faraday) { proc {} }
|
15
|
+
|
16
|
+
it('persist the account_id') { expect(clever_tap.config.account_id).to eq('foo') }
|
17
|
+
it('persist the passcode') { expect(clever_tap.config.passcode).to eq('passcode') }
|
18
|
+
it('persist the identity field') { expect(clever_tap.config.identity_field).to eq('ID') }
|
19
|
+
it('persist the faraday config') { expect(clever_tap.config.configure_faraday).to eq(configure_faraday) }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with block' do
|
23
|
+
subject(:clever_tap) do
|
24
|
+
CleverTap.new do |config|
|
25
|
+
config.account_id = 'foo'
|
26
|
+
config.passcode = 'passcode'
|
27
|
+
config.identity_field = 'ID'
|
28
|
+
config.configure_faraday(&configure_faraday)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:configure_faraday) { proc {} }
|
33
|
+
|
34
|
+
it('persist the account_id') { expect(clever_tap.config.account_id).to eq('foo') }
|
35
|
+
it('persist the passcode') { expect(clever_tap.config.passcode).to eq('passcode') }
|
36
|
+
it('persist the identity field') { expect(clever_tap.config.identity_field).to eq('ID') }
|
37
|
+
it('persist the faraday config') { expect(clever_tap.config.configure_faraday).to eq(configure_faraday) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with invalid arguments' do
|
42
|
+
it 'require `account_id`' do
|
43
|
+
expect { CleverTap.new(passcode: 'foo') }
|
44
|
+
.to raise_error(RuntimeError, /account_id/)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'require `passcode`' do
|
48
|
+
expect { CleverTap.new(account_id: 'bar') }
|
49
|
+
.to raise_error(RuntimeError, /passcode/)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#client' do
|
55
|
+
subject(:clever_tap) { CleverTap.new(account_id: 'foo', passcode: 'passcode', &configure_faraday) }
|
56
|
+
let(:configure_faraday) { proc { |_faraday| } }
|
57
|
+
|
58
|
+
it 'initialize client with a right auth data' do
|
59
|
+
expect(CleverTap::Client).to receive(:new).with('foo', 'passcode', &configure_faraday)
|
60
|
+
|
61
|
+
clever_tap.client
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'cache the client between calls' do
|
65
|
+
id = clever_tap.client.object_id
|
66
|
+
expect(clever_tap.client.object_id).to eq(id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '.config' do
|
71
|
+
let(:identity_field) { 'ID' }
|
72
|
+
let(:account_id) { 'ABC1234' }
|
73
|
+
let(:account_passcode) { 'AcCPasScoDe123' }
|
74
|
+
let(:remove_identity) { true }
|
75
|
+
|
76
|
+
it 'sets config variables' do
|
77
|
+
described_class.setup do |config|
|
78
|
+
config.identity_field = identity_field
|
79
|
+
config.account_id = account_id
|
80
|
+
config.account_passcode = account_passcode
|
81
|
+
end
|
82
|
+
|
83
|
+
expect(described_class.identity_field).to eq identity_field
|
84
|
+
expect(described_class.account_id).to eq account_id
|
85
|
+
expect(described_class.account_passcode).to eq account_passcode
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/entity'
|
3
|
+
|
4
|
+
RSpec.describe CleverTap::Event do
|
5
|
+
describe '.upload_limit' do
|
6
|
+
subject { described_class.upload_limit }
|
7
|
+
it { is_expected.to eq 1000 }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#to_h' do
|
11
|
+
subject { described_class.new(**params).to_h }
|
12
|
+
|
13
|
+
describe 'choosing `identity`' do
|
14
|
+
it_behaves_like 'choosing identity for', 'event'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'choosing timestamp' do
|
18
|
+
it_behaves_like 'choosing timestamp'
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'event name' do
|
22
|
+
let(:data) { { 'FBID' => '1414', 'Name' => 'John' } }
|
23
|
+
let(:params) { { data: data, identity: 'FBID' } }
|
24
|
+
|
25
|
+
context 'when `name` is not provided' do
|
26
|
+
it { expect { subject }.to raise_error(CleverTap::MissingEventNameError) }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when `name` is provided' do
|
30
|
+
let!(:params_ext) { params.merge!(name: 'Web Event') }
|
31
|
+
it { is_expected.to include 'evtName' => 'Web Event' }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'type' do
|
36
|
+
it_behaves_like 'proper type'
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'data' do
|
40
|
+
it_behaves_like 'constructing data for', 'event'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CleverTap::FailedResponse do
|
4
|
+
let(:records) { [{ 'id' => 1 }, { 'id' => 2 }] }
|
5
|
+
let(:message) { 'LOL an error' }
|
6
|
+
let(:code) { 401 }
|
7
|
+
|
8
|
+
subject { described_class.new(records: records, message: message, code: code) }
|
9
|
+
|
10
|
+
describe '#status' do
|
11
|
+
it { expect(subject.status).to eq 'fail' }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#success' do
|
15
|
+
it { expect(subject.success).to be false }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#errors' do
|
19
|
+
it do
|
20
|
+
error = { 'status' => 'fail', 'code' => code, 'error' => message }
|
21
|
+
|
22
|
+
expect(subject.errors).to match_array(
|
23
|
+
records.map { |r| error.merge('record' => r) }
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#message' do
|
29
|
+
it { expect(subject.message).to eq message }
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/entity'
|
3
|
+
|
4
|
+
RSpec.describe CleverTap::Profile do
|
5
|
+
describe '.upload_limit' do
|
6
|
+
subject { described_class.upload_limit }
|
7
|
+
it { is_expected.to eq 100 }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#to_h' do
|
11
|
+
subject { described_class.new(**params).to_h }
|
12
|
+
|
13
|
+
describe 'choosing `identity`' do
|
14
|
+
it_behaves_like 'choosing identity for', 'profile'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'choosing timestamp' do
|
18
|
+
it_behaves_like 'choosing timestamp'
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'type' do
|
22
|
+
it_behaves_like 'proper type'
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'data' do
|
26
|
+
it_behaves_like 'constructing data for', 'profile'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CleverTap::Response do
|
4
|
+
let(:success) do
|
5
|
+
{ 'status' => 'success', 'processed' => 1, 'unprocessed' => [] }
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:partial) do
|
9
|
+
{
|
10
|
+
'status' => 'success',
|
11
|
+
'processed' => 1,
|
12
|
+
'unprocessed' => [{ '{ "ID" => "5", "Name": "John"}' => 'Some error' }]
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:failure) do
|
17
|
+
{
|
18
|
+
'status' => 'fail',
|
19
|
+
'error' => 'Account Id not valid',
|
20
|
+
'code' => 401
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:non_json) do
|
25
|
+
'<head><title>502 Bad Gateway</title></head>'\
|
26
|
+
'<body>' \
|
27
|
+
'<center><h1>502 Bad Gateway</h1></center>'\
|
28
|
+
'</body>'\
|
29
|
+
'</html>'
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#new' do
|
33
|
+
subject { described_class.new(response) }
|
34
|
+
|
35
|
+
context 'when successful request' do
|
36
|
+
let(:response) { OpenStruct.new(body: success.to_json, success?: true) }
|
37
|
+
|
38
|
+
it { expect(subject.success).to be true }
|
39
|
+
it { expect(subject.failures).to eq [] }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when partially successful request' do
|
43
|
+
let(:response) { OpenStruct.new(body: partial.to_json, success?: true) }
|
44
|
+
|
45
|
+
it { expect(subject.success).to be false }
|
46
|
+
it { expect(subject.failures).to eq partial['unprocessed'] }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when failed request' do
|
50
|
+
let(:response) { OpenStruct.new(body: failure.to_json, success?: false) }
|
51
|
+
|
52
|
+
it { expect(subject.success).to be false }
|
53
|
+
it { expect(subject.failures).to eq [failure] }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when non json response' do
|
57
|
+
let(:response) { OpenStruct.new(body: non_json, success?: false) }
|
58
|
+
|
59
|
+
it { expect(subject.success).to be false }
|
60
|
+
it { expect(subject.failures).to eq [{ resp_string: non_json.to_s }.to_json] }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CleverTap::SuccessfulResponse do
|
4
|
+
shared_context 'successful state' do
|
5
|
+
let(:raw_response) do
|
6
|
+
{ 'status' => 'success', 'processed' => 2, 'unprocessed' => [] }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
shared_context 'partial state' do
|
11
|
+
let(:records) { [{ 'id' => 1 }] }
|
12
|
+
let(:raw_response) do
|
13
|
+
{
|
14
|
+
'status' => 'fail',
|
15
|
+
'processed' => 1,
|
16
|
+
'unprocessed' => records.map { |r| { 'record' => r.to_json } }
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
shared_context 'fail state' do
|
22
|
+
let(:records) { [{ 'id' => 1 }, { 'id' => 2 }] }
|
23
|
+
let(:raw_response) do
|
24
|
+
{
|
25
|
+
'status' => 'fail',
|
26
|
+
'processed' => 0,
|
27
|
+
'unprocessed' => records.map { |r| { 'record' => r.to_json } }
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
subject { described_class.new(raw_response) }
|
33
|
+
|
34
|
+
describe '#status' do
|
35
|
+
context 'with successful status' do
|
36
|
+
include_context 'successful state'
|
37
|
+
|
38
|
+
it { expect(subject.status).to eq 'success' }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with partial status' do
|
42
|
+
include_context 'partial state'
|
43
|
+
|
44
|
+
it { expect(subject.status).to eq 'partial' }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with fail status' do
|
48
|
+
include_context 'fail state'
|
49
|
+
|
50
|
+
it { expect(subject.status).to eq 'fail' }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#success' do
|
55
|
+
context 'with successful status' do
|
56
|
+
include_context 'successful state'
|
57
|
+
|
58
|
+
it { expect(subject.success).to be true }
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with partial status' do
|
62
|
+
include_context 'partial state'
|
63
|
+
|
64
|
+
it { expect(subject.success).to be false }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with fail status' do
|
68
|
+
include_context 'fail state'
|
69
|
+
|
70
|
+
it { expect(subject.success).to be false }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#errors' do
|
75
|
+
context 'with successful status' do
|
76
|
+
include_context 'successful state'
|
77
|
+
|
78
|
+
it { expect(subject.errors).to be_empty }
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with partial status' do
|
82
|
+
include_context 'partial state'
|
83
|
+
it { expect(subject.errors).to all(include('record')) }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with fail status' do
|
87
|
+
include_context 'fail state'
|
88
|
+
|
89
|
+
it { expect(subject.errors).to all(include('record')) }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#message' do
|
94
|
+
context 'with successful status' do
|
95
|
+
include_context 'successful state'
|
96
|
+
|
97
|
+
it { expect(subject.message).to eq '' }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with partial status' do
|
101
|
+
include_context 'partial state'
|
102
|
+
|
103
|
+
it { expect(subject.message).to eq '' }
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with fail status' do
|
107
|
+
include_context 'fail state'
|
108
|
+
|
109
|
+
it { expect(subject.message).to eq '' }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|