leanplum_api 3.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +63 -32
- data/lib/leanplum_api/api.rb +107 -156
- data/lib/leanplum_api/configuration.rb +9 -1
- data/lib/leanplum_api/connection.rb +2 -2
- data/lib/leanplum_api/data_export_api.rb +78 -0
- data/lib/leanplum_api/faraday_middleware/response_validation.rb +23 -19
- data/lib/leanplum_api/version.rb +1 -1
- data/spec/api_spec.rb +142 -98
- data/spec/configuration_spec.rb +2 -2
- data/spec/data_export_api_spec.rb +57 -0
- data/spec/fixtures/vcr/delete_user.yml +129 -0
- data/spec/fixtures/vcr/export_data.yml +5 -5
- data/spec/fixtures/vcr/export_data_dates.yml +6 -6
- data/spec/fixtures/vcr/export_user.yml +7 -7
- data/spec/fixtures/vcr/export_users.yml +44 -0
- data/spec/fixtures/vcr/get_ab_test.yml +5 -5
- data/spec/fixtures/vcr/get_ab_tests.yml +5 -5
- data/spec/fixtures/vcr/get_export_results.yml +5 -5
- data/spec/fixtures/vcr/get_messages.yml +5 -5
- data/spec/fixtures/vcr/get_vars.yml +5 -5
- data/spec/fixtures/vcr/missing_message.yml +4 -4
- data/spec/fixtures/vcr/reset_anomalous_user.yml +6 -6
- data/spec/fixtures/vcr/set_device_attributes.yml +46 -0
- data/spec/fixtures/vcr/set_user_attributes.yml +7 -7
- data/spec/fixtures/vcr/set_user_attributes_with_devices.yml +46 -0
- data/spec/fixtures/vcr/set_user_attributes_with_devices_and_events.yml +46 -0
- data/spec/fixtures/vcr/set_user_attributes_with_events.yml +46 -0
- data/spec/fixtures/vcr/track_events.yml +8 -8
- data/spec/fixtures/vcr/track_events_and_attributes.yml +9 -9
- data/spec/fixtures/vcr/track_events_anomaly_overrider.yml +20 -19
- data/spec/fixtures/vcr/track_offline_events.yml +8 -8
- data/spec/http_spec.rb +6 -5
- data/spec/spec_helper.rb +11 -8
- metadata +40 -3
@@ -29,6 +29,9 @@ module LeanplumApi
|
|
29
29
|
attr_accessor :logger
|
30
30
|
attr_accessor :timeout_seconds
|
31
31
|
|
32
|
+
# Override validations for leanplum response. On by default.
|
33
|
+
attr_accessor :validate_response
|
34
|
+
|
32
35
|
# Optional configuration for exporting raw data to S3.
|
33
36
|
# If s3_bucket_name is provided, s3_access_id and s3_access_key must also be provided.
|
34
37
|
attr_accessor :s3_bucket_name
|
@@ -39,9 +42,14 @@ module LeanplumApi
|
|
39
42
|
def initialize
|
40
43
|
@api_version = DEFAULT_LEANPLUM_API_VERSION
|
41
44
|
@developer_mode = false
|
45
|
+
@validate_response = true
|
42
46
|
@timeout_seconds = 600
|
43
47
|
@logger = LeanplumApi::Logger.new(STDOUT)
|
44
|
-
@api_debug =
|
48
|
+
@api_debug = debug_mode?
|
49
|
+
end
|
50
|
+
|
51
|
+
def debug_mode?
|
52
|
+
ENV['LEANPLUM_API_DEBUG'].to_s =~ /^(true|t|yes|y|1)$/i
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
@@ -7,13 +7,13 @@ module LeanplumApi
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def get(query)
|
10
|
-
connection.get(LEANPLUM_API_PATH, query.merge(authentication_params))
|
10
|
+
connection.get(LEANPLUM_API_PATH, query.merge(authentication_params)).body['response']
|
11
11
|
end
|
12
12
|
|
13
13
|
def multi(payload)
|
14
14
|
connection.post("#{LEANPLUM_API_PATH}?#{authed_multi_param_string}") do |request|
|
15
15
|
request.body = { data: payload }
|
16
|
-
end
|
16
|
+
end.body['response']
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'leanplum_api/api'
|
2
|
+
|
3
|
+
# Support for data export features are semi-deprecated in the gem, because the data they give has historically
|
4
|
+
# been inaccurate. The automated S3 export has better accuracy with a fraction of the headaches.
|
5
|
+
# Use these methods at your own risk.
|
6
|
+
|
7
|
+
module LeanplumApi
|
8
|
+
class DataExportAPI < API
|
9
|
+
# Returns the jobId
|
10
|
+
# Leanplum has confirmed that using startTime and endTime, especially trying to be relatively up to the minute,
|
11
|
+
# leads to sort of unprocessed information that can be incomplete.
|
12
|
+
# They recommend using the automatic export to S3 if possible.
|
13
|
+
def export_data(start_time, end_time = nil)
|
14
|
+
LeanplumApi.configuration.logger.warn("You should probably use the direct S3 export instead of exportData")
|
15
|
+
fail "Start time #{start_time} after end time #{end_time}" if end_time && start_time > end_time
|
16
|
+
LeanplumApi.configuration.logger.info("Requesting data export from #{start_time} to #{end_time}...")
|
17
|
+
|
18
|
+
# Because of open questions about how startTime and endTime work (or don't work, as the case may be), we
|
19
|
+
# only want to pass the dates unless start and end times are specifically requested.
|
20
|
+
params = { action: 'exportData', startDate: start_time.strftime('%Y%m%d') }
|
21
|
+
params[:startTime] = start_time.strftime('%s') if start_time.is_a?(DateTime) || start_time.is_a?(Time)
|
22
|
+
|
23
|
+
if end_time
|
24
|
+
params[:endDate] = end_time.strftime('%Y%m%d')
|
25
|
+
params[:endTime] = end_time.strftime('%s') if end_time.is_a?(DateTime) || end_time.is_a?(Time)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Handle optional S3 export params
|
29
|
+
if LeanplumApi.configuration.s3_bucket_name
|
30
|
+
fail 's3_bucket_name set but s3_access_id not configured!' unless LeanplumApi.configuration.s3_access_id
|
31
|
+
fail 's3_bucket_name set but s3_access_key not configured!' unless LeanplumApi.configuration.s3_access_key
|
32
|
+
|
33
|
+
params.merge!(
|
34
|
+
s3BucketName: LeanplumApi.configuration.s3_bucket_name,
|
35
|
+
s3AccessId: LeanplumApi.configuration.s3_access_id,
|
36
|
+
s3AccessKey: LeanplumApi.configuration.s3_access_key
|
37
|
+
)
|
38
|
+
params.merge!(s3ObjectPrefix: LeanplumApi.configuration.s3_object_prefix) if LeanplumApi.configuration.s3_object_prefix
|
39
|
+
end
|
40
|
+
|
41
|
+
data_export_connection.get(params).first['jobId']
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_export_results(job_id)
|
45
|
+
response = data_export_connection.get(action: 'getExportResults', jobId: job_id).first
|
46
|
+
|
47
|
+
if response['state'] == EXPORT_FINISHED
|
48
|
+
LeanplumApi.configuration.logger.info("Export finished.")
|
49
|
+
LeanplumApi.configuration.logger.debug(" Response: #{response}")
|
50
|
+
{
|
51
|
+
files: response['files'],
|
52
|
+
number_of_sessions: response['numSessions'],
|
53
|
+
number_of_bytes: response['numBytes'],
|
54
|
+
state: response['state'],
|
55
|
+
s3_copy_status: response['s3CopyStatus']
|
56
|
+
}
|
57
|
+
else
|
58
|
+
{ state: response['state'] }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# See leanplum docs.
|
63
|
+
# The segment syntax is identical to that produced by the "Insert Value" feature on the dashboard.
|
64
|
+
# Examples: 'Country = "US"', '{Country = "US"} and {App version = 1}'.
|
65
|
+
def export_users(ab_test_id = nil, segment = nil)
|
66
|
+
data_export_connection.get(action: 'exportUsers', segment: segment, ab_test_id: ab_test_id).first['jobId']
|
67
|
+
end
|
68
|
+
|
69
|
+
def wait_for_export_job(job_id, polling_interval = 60)
|
70
|
+
while get_export_results(job_id)[:state] != EXPORT_FINISHED
|
71
|
+
LeanplumApi.configuration.logger.debug("Polling job #{job_id}: #{get_export_results(job_id)}")
|
72
|
+
sleep(polling_interval)
|
73
|
+
end
|
74
|
+
|
75
|
+
get_export_results(job_id)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -5,42 +5,46 @@ module LeanplumApi
|
|
5
5
|
class ResponseValidation < Faraday::Middleware
|
6
6
|
Faraday::Request.register_middleware(leanplum_response_validation: self)
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
SUCCESS = 'success'.freeze
|
9
|
+
WARN = 'warning'.freeze
|
10
10
|
|
11
|
+
def call(environment)
|
11
12
|
if environment.body
|
12
|
-
|
13
|
+
requests = environment.body[:data] if environment.body[:data] && environment.body[:data].is_a?(Array)
|
13
14
|
environment.body = environment.body.to_json
|
14
15
|
end
|
15
16
|
|
16
17
|
@app.call(environment).on_complete do |response|
|
17
18
|
fail ResourceNotFoundError, response.inspect if response.status == 404
|
18
|
-
fail BadResponseError, response.inspect unless response.status == 200 && response.body['response']
|
19
|
-
fail BadResponseError, "No :success key in #{
|
20
|
-
fail BadResponseError, "Not a success! Response: #{response.inspect}" unless response.body['response'].first['success'] == true
|
19
|
+
fail BadResponseError, response.inspect unless response.status == 200 && (responses = response.body['response']).is_a?(Array)
|
20
|
+
fail BadResponseError, "No :success key in #{responses.inspect}!" unless responses.all? { |r| r.key?(SUCCESS) }
|
21
21
|
|
22
|
-
|
22
|
+
validate_request_success(responses, requests) if LeanplumApi.configuration.validate_response
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
def
|
29
|
-
success_indicators
|
30
|
-
|
31
|
-
fail "Attempted to do #{operations.size} operations but only received confirmation for #{success_indicators.size}!"
|
28
|
+
def validate_request_success(success_indicators, requests)
|
29
|
+
if requests && success_indicators.size != requests.size
|
30
|
+
fail BadResponseError, "Attempted #{requests.size} operations but received confirmation for #{success_indicators.size}!"
|
32
31
|
end
|
33
32
|
|
34
|
-
failures =
|
35
|
-
|
36
|
-
|
37
|
-
LeanplumApi.configuration.logger.error("Unsuccessful request at position #{i}: #{operations[i]}")
|
38
|
-
failures << { operation: operations[i], error: s }
|
33
|
+
failures = success_indicators.map.with_index do |indicator, i|
|
34
|
+
if indicator[WARN]
|
35
|
+
LeanplumApi.configuration.logger.warn((requests ? "Warning for #{requests[i]}: " : '') + indicator[WARN].to_s)
|
39
36
|
end
|
40
|
-
LeanplumApi.configuration.logger.warn("Warning for operation #{operations[i]}: #{s['warning']}") if s['warning']
|
41
|
-
end
|
42
37
|
|
43
|
-
|
38
|
+
next nil if indicator[SUCCESS].to_s == 'true'
|
39
|
+
|
40
|
+
requests ? { operation: requests[i], error: indicator } : { error: indicator }
|
41
|
+
end.compact
|
42
|
+
|
43
|
+
unless failures.empty?
|
44
|
+
error_message = "Operation failures: #{failures}"
|
45
|
+
LeanplumApi.configuration.logger.error(error_message)
|
46
|
+
fail BadResponseError, error_message
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
data/lib/leanplum_api/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -1,59 +1,109 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe LeanplumApi::API do
|
4
2
|
let(:api) { described_class.new }
|
5
3
|
let(:first_user_id) { 123456 }
|
6
4
|
let(:first_event_time) { Time.now.utc - 1.day }
|
7
5
|
let(:last_event_time) { Time.now.utc }
|
8
|
-
let(:users)
|
9
|
-
|
6
|
+
let(:users) { [user] }
|
7
|
+
let(:devices) { [device] }
|
8
|
+
let(:user) do
|
9
|
+
{
|
10
10
|
user_id: first_user_id,
|
11
11
|
first_name: 'Mike',
|
12
12
|
last_name: 'Jones',
|
13
13
|
gender: 'm',
|
14
14
|
email: 'still_tippin@test.com',
|
15
15
|
create_date: '2010-01-01'.to_date,
|
16
|
-
is_tipping: true
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
is_tipping: true
|
17
|
+
}
|
18
|
+
end
|
19
|
+
let(:device) do
|
20
|
+
{
|
21
|
+
device_id: 'fu123',
|
22
|
+
appVersion: 'x42x',
|
23
|
+
deviceModel: 'p0d',
|
24
|
+
create_date: '2018-01-01'.to_date
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'devices' do
|
29
|
+
it 'build_device_attributes_hash' do
|
30
|
+
expect(api.send(:build_device_attributes_hash, device)).to eq(
|
31
|
+
deviceId: device[:device_id],
|
32
|
+
action: described_class::SET_DEVICE_ATTRIBUTES,
|
33
|
+
deviceAttributes: api.send(:fix_iso8601, device.except(:device_id))
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'set_device_attributes' do
|
38
|
+
it 'sets device attributes without error' do
|
39
|
+
VCR.use_cassette('set_device_attributes') do
|
40
|
+
expect { api.set_device_attributes(devices) }.to_not raise_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
25
44
|
end
|
26
45
|
|
27
46
|
context 'users' do
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
47
|
+
let(:events) { { eventName1: { count: 1, firstTime: first_event_time, lastTime: last_event_time } } }
|
48
|
+
let(:events_with_timestamps) { Hash[events.map { |k, v| [k, api.send(:fix_seconds_since_epoch, v)] }] }
|
49
|
+
let(:user_with_devices) { user.merge(devices: devices) }
|
50
|
+
let(:user_with_events) { user.merge(events: events) }
|
51
|
+
|
52
|
+
context '#build_user_attributes_hash' do
|
53
|
+
let(:built_attributes) do
|
54
|
+
{
|
55
|
+
userId: first_user_id,
|
56
|
+
action: described_class::SET_USER_ATTRIBUTES,
|
57
|
+
userAttributes: api.send(:fix_iso8601, user.except(:user_id))
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'builds the right hash' do
|
62
|
+
expect(api.send(:build_user_attributes_hash, user)).to eq(built_attributes)
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with events' do
|
66
|
+
it 'builds the right hash' do
|
67
|
+
expect(api.send(:build_user_attributes_hash, user_with_events)).to eq(
|
68
|
+
built_attributes.merge(events: events_with_timestamps)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with devices' do
|
74
|
+
it 'builds the right hash' do
|
75
|
+
expect(api.send(:build_user_attributes_hash, user_with_devices)).to eq(
|
76
|
+
built_attributes.merge(devices: devices)
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
48
80
|
end
|
49
81
|
|
50
|
-
context 'set_user_attributes' do
|
82
|
+
context '#set_user_attributes' do
|
51
83
|
context 'valid request' do
|
52
84
|
it 'should successfully set user attributes' do
|
53
85
|
VCR.use_cassette('set_user_attributes') do
|
54
86
|
expect { api.set_user_attributes(users) }.to_not raise_error
|
55
87
|
end
|
56
88
|
end
|
89
|
+
|
90
|
+
it 'should successfully set user attributes and events' do
|
91
|
+
VCR.use_cassette('set_user_attributes_with_events') do
|
92
|
+
expect { api.set_user_attributes([user_with_events]) }.to_not raise_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should successfully set user attributes and devices' do
|
97
|
+
VCR.use_cassette('set_user_attributes_with_devices') do
|
98
|
+
expect { api.set_user_attributes([user_with_devices]) }.to_not raise_error
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should successfully set user attributes and devices and events' do
|
103
|
+
VCR.use_cassette('set_user_attributes_with_devices_and_events') do
|
104
|
+
expect { api.set_user_attributes([user_with_devices.merge(events: events)]) }.to_not raise_error
|
105
|
+
end
|
106
|
+
end
|
57
107
|
end
|
58
108
|
|
59
109
|
context 'invalid request' do
|
@@ -65,34 +115,43 @@ describe LeanplumApi::API do
|
|
65
115
|
end
|
66
116
|
end
|
67
117
|
|
68
|
-
context 'user_attributes' do
|
118
|
+
context '#user_attributes' do
|
69
119
|
it 'should get user attributes for this user' do
|
70
120
|
VCR.use_cassette('export_user') do
|
71
121
|
api.user_attributes(first_user_id).each do |k, v|
|
72
|
-
if
|
73
|
-
expect(v).to eq(
|
122
|
+
if user[k.to_sym].is_a?(Date) || user[k.to_sym].is_a?(DateTime)
|
123
|
+
expect(v).to eq(user[k.to_sym].strftime('%Y-%m-%d'))
|
74
124
|
else
|
75
|
-
expect(v).to eq(
|
125
|
+
expect(v).to eq(user[k.to_sym])
|
76
126
|
end
|
77
127
|
end
|
78
128
|
end
|
79
129
|
end
|
80
130
|
end
|
81
131
|
|
82
|
-
context '
|
83
|
-
it 'should export users'
|
84
|
-
end
|
85
|
-
|
86
|
-
context 'reset_anomalous_users' do
|
132
|
+
context '#reset_anomalous_users' do
|
87
133
|
it 'should successfully call setUserAttributes with resetAnomalies' do
|
88
134
|
VCR.use_cassette('reset_anomalous_user') do
|
89
135
|
expect { api.reset_anomalous_users(first_user_id) }.to_not raise_error
|
90
136
|
end
|
91
137
|
end
|
92
138
|
end
|
139
|
+
|
140
|
+
context '#delete_user' do
|
141
|
+
let(:user_id) { 'delete_yourself_123' }
|
142
|
+
let(:deletable_user) { user.merge(user_id: user_id) }
|
143
|
+
|
144
|
+
it 'should delete a user' do
|
145
|
+
VCR.use_cassette('delete_user') do
|
146
|
+
expect { api.set_user_attributes(deletable_user) }.to_not raise_error
|
147
|
+
expect { api.delete_user(user_id) }.to_not raise_error
|
148
|
+
expect { api.user_attributes(user_id) }.to raise_error(LeanplumApi::ResourceNotFoundError)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
93
152
|
end
|
94
153
|
|
95
|
-
context '
|
154
|
+
context 'event tracking' do
|
96
155
|
let(:timestamp) { '2015-05-01 01:02:03' }
|
97
156
|
let(:purchase) { 'purchase' }
|
98
157
|
let(:events) do
|
@@ -100,13 +159,13 @@ describe LeanplumApi::API do
|
|
100
159
|
{
|
101
160
|
user_id: first_user_id,
|
102
161
|
event: purchase,
|
103
|
-
time:
|
162
|
+
time: last_event_time,
|
104
163
|
some_timestamp: timestamp
|
105
164
|
},
|
106
165
|
{
|
107
166
|
user_id: 54321,
|
108
167
|
event: 'purchase_page_view',
|
109
|
-
time:
|
168
|
+
time: last_event_time - 10.minutes
|
110
169
|
}
|
111
170
|
]
|
112
171
|
end
|
@@ -115,9 +174,9 @@ describe LeanplumApi::API do
|
|
115
174
|
let(:event_hash) do
|
116
175
|
{
|
117
176
|
userId: first_user_id,
|
118
|
-
time: Time.now.utc.strftime('%s').to_i,
|
119
|
-
action: 'track',
|
120
177
|
event: purchase,
|
178
|
+
time: last_event_time.strftime('%s').to_i,
|
179
|
+
action: described_class::TRACK,
|
121
180
|
params: { some_timestamp: timestamp }
|
122
181
|
}
|
123
182
|
end
|
@@ -127,7 +186,7 @@ describe LeanplumApi::API do
|
|
127
186
|
end
|
128
187
|
end
|
129
188
|
|
130
|
-
context '
|
189
|
+
context '#track_events' do
|
131
190
|
context 'valid request' do
|
132
191
|
it 'should successfully track session events' do
|
133
192
|
VCR.use_cassette('track_events') do
|
@@ -137,7 +196,10 @@ describe LeanplumApi::API do
|
|
137
196
|
|
138
197
|
it 'should successfully track non session events' do
|
139
198
|
VCR.use_cassette('track_offline_events') do
|
140
|
-
expect
|
199
|
+
expect do
|
200
|
+
response = api.track_events(events, allow_offline: true)
|
201
|
+
expect(response.map { |r| r['success'] && r['isOffline'] }.all?).to be_truthy
|
202
|
+
end.to_not raise_error
|
141
203
|
end
|
142
204
|
end
|
143
205
|
end
|
@@ -153,28 +215,34 @@ describe LeanplumApi::API do
|
|
153
215
|
end
|
154
216
|
|
155
217
|
context 'anomalous data force_anomalous_override' do
|
156
|
-
let(:old_events) { events.map { |e| e[:time] -=
|
218
|
+
let(:old_events) { events.map { |e| e[:time] -= 2.years; e } }
|
157
219
|
|
158
220
|
it 'should successfully force the anomalous data override events' do
|
159
221
|
VCR.use_cassette('track_events_anomaly_overrider') do
|
160
|
-
expect
|
222
|
+
expect do
|
223
|
+
response = api.track_events(old_events, force_anomalous_override: true)
|
224
|
+
expect(response.map { |r| r['warning']['message'] }.all? { |w| w =~ /Past event detected/ }).to be true
|
225
|
+
end.to_not raise_error
|
161
226
|
end
|
162
227
|
end
|
163
228
|
end
|
164
229
|
end
|
165
230
|
|
166
|
-
context '
|
167
|
-
it '
|
231
|
+
context '#track_multi' do
|
232
|
+
it 'tracks users and events at the same time' do
|
168
233
|
VCR.use_cassette('track_events_and_attributes') do
|
169
|
-
expect
|
234
|
+
expect do
|
235
|
+
response = api.track_multi(events: events, user_attributes: users)
|
236
|
+
expect(response.first['success']).to be true
|
237
|
+
end.to_not raise_error
|
170
238
|
end
|
171
239
|
end
|
172
240
|
end
|
173
241
|
|
174
|
-
context 'user_events' do
|
242
|
+
context '#user_events' do
|
175
243
|
it 'should get user events for this user' do
|
176
244
|
VCR.use_cassette('export_user') do
|
177
|
-
expect(api.user_events(first_user_id)[purchase].keys).to eq(%w(firstTime lastTime count))
|
245
|
+
expect(api.user_events(first_user_id)[purchase].keys.sort).to eq(%w(firstTime lastTime count).sort)
|
178
246
|
end
|
179
247
|
end
|
180
248
|
end
|
@@ -188,46 +256,6 @@ describe LeanplumApi::API do
|
|
188
256
|
LeanplumApi.configure { |c| c.developer_mode = true }
|
189
257
|
end
|
190
258
|
|
191
|
-
context 'data export methods' do
|
192
|
-
context 'export_data' do
|
193
|
-
context 'regular export' do
|
194
|
-
it 'should request a data export job with a starttime' do
|
195
|
-
VCR.use_cassette('export_data') do
|
196
|
-
expect { api.export_data(Time.at(1438660800).utc) }.to raise_error LeanplumApi::BadResponseError
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'should request a data export job with start and end dates' do
|
201
|
-
VCR.use_cassette('export_data_dates') do
|
202
|
-
expect { api.export_data(Date.new(2017, 8, 5), Date.new(2017, 8, 6)) }.to_not raise_error
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
context 's3 export' do
|
208
|
-
let(:s3_bucket_name) { 'bucket' }
|
209
|
-
let(:s3_access_key) { 's3_access_key' }
|
210
|
-
let(:s3_access_id) { 's3_access_id' }
|
211
|
-
|
212
|
-
it 'should request an S3 export'
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
context 'get_export_results' do
|
217
|
-
it 'should get a status for a data export job' do
|
218
|
-
VCR.use_cassette('get_export_results') do
|
219
|
-
expect(api.get_export_results('export_4727756026281984_2904941266315269120')).to eq({
|
220
|
-
files: ['https://leanplum_export.storage.googleapis.com/export-4727756026281984-d5969d55-f242-48a6-85a3-165af08e2306-output-0'],
|
221
|
-
number_of_bytes: 36590,
|
222
|
-
number_of_sessions: 101,
|
223
|
-
state: LeanplumApi::API::EXPORT_FINISHED,
|
224
|
-
s3_copy_status: nil
|
225
|
-
})
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
259
|
context 'content read only methods' do
|
232
260
|
context 'ab tests' do
|
233
261
|
it 'gets ab tests' do
|
@@ -267,9 +295,25 @@ describe LeanplumApi::API do
|
|
267
295
|
pending 'Docs are extremely unclear about what getVars and setVars even do'
|
268
296
|
|
269
297
|
VCR.use_cassette('get_vars') do
|
270
|
-
expect(api.get_vars(
|
298
|
+
expect(api.get_vars(user[:user_id])).to eq({ 'test_var' => 1 })
|
271
299
|
end
|
272
300
|
end
|
273
301
|
end
|
274
302
|
end
|
303
|
+
|
304
|
+
context 'hash utility methods' do
|
305
|
+
let(:hash_with_times) { { not_time: 'grippin', time: Time.now.utc, date: Time.now.utc.to_date } }
|
306
|
+
|
307
|
+
it 'turns datetimes into seconds from the epoch' do
|
308
|
+
expect(api.send(:fix_seconds_since_epoch, hash_with_times)).to eq(
|
309
|
+
hash_with_times.merge(time: Time.now.utc.strftime('%s').to_i, date: Time.now.utc.to_date.strftime('%s').to_i)
|
310
|
+
)
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'turns datetimes into iso8601 format' do
|
314
|
+
expect(api.send(:fix_iso8601, hash_with_times)).to eq(
|
315
|
+
hash_with_times.merge(time: Time.now.utc.iso8601, date: Time.now.utc.to_date.iso8601)
|
316
|
+
)
|
317
|
+
end
|
318
|
+
end
|
275
319
|
end
|