leanplum_api 3.1.0 → 4.0.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/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
|