leanplum_api 1.3.1 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eaef8b007ad46754ae7107b22f86db959f8805c9
4
- data.tar.gz: 503030e7e4f4a85640e42aa2e2d60da7911bad5d
3
+ metadata.gz: e3ada1da3173ffd60da9b2abdddbf4901d20d8cd
4
+ data.tar.gz: 56ca6681108d38d0d91aed19701624db0faae812
5
5
  SHA512:
6
- metadata.gz: 3d9b7d5ad103922bf4888953aaad2e5130b98c2136a8b18a0b02ba30e9d55d6d2d041403eddad4799457c51290b42491570a42a9a68bb63315b3843130cf0814
7
- data.tar.gz: dc14c91eb847b399af97a187bed901f948f88a34462539a2489d72fd587c07a885537e3b3b2f34dac4e8bad3dd4795f0a918ccbd0395e3d99bd64046f876efa7
6
+ metadata.gz: f7f0436608323f894b38932da9dd1cd2ebab1aa5f992267fc0c01f871d48e6bdfed8800317dd255907ec6858a18711118e19de9820165d8cc133ff2663030651
7
+ data.tar.gz: f35e6b7a620fb5f4136f3914381f46abcff6931ebda1a5dbeb5efd2a9fcd072c80bde63b2c7a00135413b803af5fc472b006faa20259d8baab7b7f5b29bc9929
data/README.md CHANGED
@@ -27,10 +27,10 @@ LeanplumApi.configure do |config|
27
27
  config.development_key = 'MY_CONTENT_KEY' # Optional; needed for resetting anomalous events
28
28
 
29
29
  # Optional configuration variables
30
- config.log_path = '/log/path' # Defaults to 'log/'
31
- attr_accessor :timeout_seconds # Defaults to 600
32
- config.api_version # Defaults to 1.0.6
33
- attr_accessor :developer_mode # Defaults to false
30
+ config.logger = LeanplumApi::Logger.new('file.log') # Defaults to STDOUT. The gem logger class hides passwords.
31
+ config.timeout_seconds # Defaults to 600
32
+ config.api_version # Defaults to 1.0.6
33
+ config.developer_mode # Defaults to false
34
34
 
35
35
  # S3 export required options
36
36
  config.s3_bucket_name = 'my_bucket'
@@ -75,6 +75,12 @@ api.track_events(event)
75
75
 
76
76
  # You can also track events and user attributes at the same time
77
77
  api.track_multi(event, attribute_hash)
78
+
79
+ # If your event is sufficiently far in the past, leanplum will mark your user as "Anomalous"
80
+ # To force a reset of this flag, either call the method directly
81
+ api.reset_anomalous_users([12345, 23456])
82
+ # Or use the :force_anomalous_override option when calling track_events or track_multi
83
+ api.track_events(event, force_anomalous_override: true)
78
84
  ```
79
85
 
80
86
  Data export:
@@ -4,11 +4,11 @@ module LeanplumApi
4
4
  EXPORT_RUNNING = 'RUNNING'
5
5
  EXPORT_FINISHED = 'FINISHED'
6
6
 
7
+ class LeanplumValidationException < RuntimeError; end
8
+
7
9
  def initialize(options = {})
8
10
  fail 'LeanplumApi not configured yet!' unless LeanplumApi.configuration
9
-
10
- @logger = options[:logger] || LeanplumApiLogger.new(File.join(LeanplumApi.configuration.log_path, "#{$$}_leanplum_#{Time.now.utc.strftime('%Y-%m-%d_%H:%M:%S')}.log"))
11
- @http = LeanplumApi::HTTP.new(logger: @logger)
11
+ @http = LeanplumApi::HTTP.new
12
12
  end
13
13
 
14
14
  def set_user_attributes(user_attributes, options = {})
@@ -24,12 +24,11 @@ module LeanplumApi
24
24
  # Set the :force_anomalous_override to catch warnings from leanplum about anomalous events and force them to not
25
25
  # be considered anomalous
26
26
  def track_multi(events = nil, user_attributes = nil, options = {})
27
- events = arrayify(events)
28
- user_attributes = arrayify(user_attributes)
27
+ events = Array.wrap(events)
28
+ user_attributes = Array.wrap(user_attributes)
29
29
 
30
30
  request_data = user_attributes.map { |h| build_user_attributes_hash(h) } + events.map { |h| build_event_attributes_hash(h) }
31
31
  response = @http.post(request_data)
32
- validate_response(events + user_attributes, response)
33
32
 
34
33
  if options[:force_anomalous_override]
35
34
  user_ids_to_reset = []
@@ -48,7 +47,7 @@ module LeanplumApi
48
47
  # They recommend using the automatic export to S3 if possible.
49
48
  def export_data(start_time, end_time = nil)
50
49
  fail "Start time #{start_time} after end time #{end_time}" if end_time && start_time > end_time
51
- @logger.info("Requesting data export from #{start_time} to #{end_time}...")
50
+ LeanplumApi.configuration.logger.info("Requesting data export from #{start_time} to #{end_time}...")
52
51
 
53
52
  # Because of open questions about how startTime and endTime work (or don't work, as the case may be), we
54
53
  # only want to pass the dates unless start and end times are specifically requested.
@@ -72,17 +71,12 @@ module LeanplumApi
72
71
  params.merge!(s3ObjectPrefix: LeanplumApi.configuration.s3_object_prefix) if LeanplumApi.configuration.s3_object_prefix
73
72
  end
74
73
 
75
- response = data_export_connection.get(params).body['response'].first
76
- if response['success'] == true
77
- response['jobId']
78
- else
79
- fail "No success message! Response: #{response}"
80
- end
74
+ data_export_connection.get(params).body['response'].first['jobId']
81
75
  end
82
76
 
83
77
  # See leanplum docs.
84
78
  # The segment syntax is identical to that produced by the "Insert Value" feature on the dashboard.
85
- # Examples: 'Country = "US"', '{Country = US} and {App version = 1}'.
79
+ # Examples: 'Country = "US"', '{Country = "US"} and {App version = 1}'.
86
80
  def export_users(segment, ab_test_id)
87
81
  data_export_connection.get(action: 'exportUsers', segment: segment, ab_test_id: ab_test_id)
88
82
  end
@@ -90,8 +84,8 @@ module LeanplumApi
90
84
  def get_export_results(job_id)
91
85
  response = data_export_connection.get(action: 'getExportResults', jobId: job_id).body['response'].first
92
86
  if response['state'] == EXPORT_FINISHED
93
- @logger.info("Export finished.")
94
- @logger.debug(" Response: #{response}")
87
+ LeanplumApi.configuration.logger.info("Export finished.")
88
+ LeanplumApi.configuration.logger.debug(" Response: #{response}")
95
89
  {
96
90
  files: response['files'],
97
91
  number_of_sessions: response['numSessions'],
@@ -106,7 +100,7 @@ module LeanplumApi
106
100
 
107
101
  def wait_for_job(job_id, polling_interval = 60)
108
102
  while get_export_results(job_id)[:state] != EXPORT_FINISHED
109
- @logger.debug("Polling job #{job_id}: #{get_export_results(job_id)}")
103
+ LeanplumApi.configuration.logger.debug("Polling job #{job_id}: #{get_export_results(job_id)}")
110
104
  sleep(polling_interval)
111
105
  end
112
106
  get_export_results(job_id)
@@ -145,26 +139,25 @@ module LeanplumApi
145
139
  # Calling this method after you pass old events will fix that for all events for the specified user_id
146
140
  # For some reason this API feature requires the developer key
147
141
  def reset_anomalous_users(user_ids)
148
- user_ids = arrayify(user_ids)
142
+ user_ids = Array.wrap(user_ids)
149
143
  request_data = user_ids.map { |user_id| { 'action' => 'setUserAttributes', 'resetAnomalies' => true, 'userId' => user_id } }
150
- response = development_connection.post(request_data)
151
- validate_response(request_data, response)
144
+ development_connection.post(request_data)
152
145
  end
153
146
 
154
147
  private
155
148
 
156
149
  # Only instantiated for data export endpoint calls
157
150
  def data_export_connection
158
- @data_export ||= LeanplumApi::DataExport.new(logger: @logger)
151
+ @data_export ||= LeanplumApi::DataExport.new
159
152
  end
160
153
 
161
154
  # Only instantiated for ContentReadOnly calls (AB tests)
162
155
  def content_read_only_connection
163
- @content_read_only ||= LeanplumApi::ContentReadOnly.new(logger: @logger)
156
+ @content_read_only ||= LeanplumApi::ContentReadOnly.new
164
157
  end
165
158
 
166
159
  def development_connection
167
- @development ||= LeanplumApi::Development.new(logger: @logger)
160
+ @development ||= LeanplumApi::Development.new
168
161
  end
169
162
 
170
163
  def extract_user_id_or_device_id_hash(hash)
@@ -217,35 +210,5 @@ module LeanplumApi
217
210
  end
218
211
  new_hash
219
212
  end
220
-
221
- # In case leanplum decides your events are too old, they will send a warning.
222
- # Right now we aren't responding to this directly.
223
- # '{"response":[{"success":true,"warning":{"message":"Anomaly detected: time skew. User will be excluded from analytics."}}]}'
224
- def validate_response(input, response)
225
- success_indicators = response.body['response']
226
- if success_indicators.size != input.size
227
- fail "Attempted to update #{input.size} records but only received confirmation for #{success_indicators.size}!"
228
- end
229
-
230
- failure_indices = []
231
- success_indicators.each_with_index do |s,i|
232
- if s['success'].to_s != 'true'
233
- @logger.error("Unsuccessful attempt to update at position #{i}: #{input[i]}")
234
- failure_indices << i
235
- else
236
- @logger.debug("Successfully updated position #{i}: #{input[i]}")
237
- end
238
- end
239
-
240
- fail LeanplumValidationException.new('Failed to update') if failure_indices.size > 0
241
- end
242
-
243
- def arrayify(x)
244
- if x && !x.is_a?(Array)
245
- [x]
246
- else
247
- x || []
248
- end
249
- end
250
213
  end
251
214
  end
@@ -26,6 +26,7 @@ module LeanplumApi
26
26
  attr_accessor :api_version
27
27
  attr_accessor :developer_mode
28
28
  attr_accessor :log_path
29
+ attr_accessor :logger
29
30
  attr_accessor :timeout_seconds
30
31
 
31
32
  # Optional configuration for exporting raw data to S3.
@@ -36,10 +37,13 @@ module LeanplumApi
36
37
  attr_accessor :s3_object_prefix
37
38
 
38
39
  def initialize
39
- @log_path = 'log'
40
40
  @api_version = DEFAULT_LEANPLUM_API_VERSION
41
41
  @developer_mode = false
42
42
  @timeout_seconds = 600
43
+ @logger = LeanplumApi::Logger.new(STDOUT)
44
+
45
+ # Deprecated
46
+ @log_path = 'log'
43
47
  end
44
48
  end
45
49
  end
@@ -0,0 +1,45 @@
1
+ module LeanplumApi
2
+ class BadResponseError < RuntimeError; end
3
+ class ResourceNotFoundError < RuntimeError; end
4
+
5
+ class ResponseValidation < Faraday::Middleware
6
+ Faraday::Request.register_middleware(leanplum_response_validation: self)
7
+
8
+ def call(environment)
9
+ operations = nil
10
+
11
+ if environment.body
12
+ operations = environment.body[:data] if environment.body[:data] && environment.body[:data].is_a?(Array)
13
+ environment.body = environment.body.to_json
14
+ end
15
+
16
+ @app.call(environment).on_complete do |response|
17
+ 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 #{response.inspect}!" unless response.body['response'].is_a?(Array) && response.body['response'].first.has_key?('success')
20
+ fail BadResponseError, "Not a success! Response: #{response.inspect}" unless response.body['response'].first['success'] == true
21
+ validate_operation_success(operations, response) if operations
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def validate_operation_success(operations, response)
28
+ success_indicators = response.body['response']
29
+ if success_indicators.size != operations.size
30
+ fail "Attempted to update #{operations.size} records but only received confirmation for #{success_indicators.size}!"
31
+ end
32
+
33
+ failures = []
34
+ success_indicators.each_with_index do |s, i|
35
+ if s['success'].to_s != 'true'
36
+ LeanplumApi.configuration.logger.error("Unsuccessful attempt to update at position #{i}: #{operations[i]}")
37
+ failures << { operation: operations[i], error: s }
38
+ end
39
+ LeanplumApi.configuration.logger.warn("Warning for operation #{operations[i]}: #{s['warning']}") if s['warning']
40
+ end
41
+
42
+ fail LeanplumValidationException.new("Operation failures: #{failures}") if failures.size > 0
43
+ end
44
+ end
45
+ end
@@ -12,7 +12,7 @@ module LeanplumApi
12
12
 
13
13
  def post(payload)
14
14
  connection.post("#{LEANPLUM_API_PATH}?#{authed_multi_param_string}") do |request|
15
- request.body = { data: payload }.to_json
15
+ request.body = { data: payload }
16
16
  end
17
17
  end
18
18
 
@@ -44,7 +44,7 @@ module LeanplumApi
44
44
  }
45
45
 
46
46
  @connection ||= Faraday.new(options) do |connection|
47
- connection.request :json
47
+ connection.request :leanplum_response_validation
48
48
 
49
49
  connection.response :logger, @logger, bodies: true if api_debug?
50
50
  connection.response :json, :content_type => /\bjson$/
@@ -1,7 +1,7 @@
1
1
  require 'logger'
2
2
 
3
3
  module LeanplumApi
4
- class LeanplumApiLogger < Logger
4
+ class Logger < ::Logger
5
5
  def format_message(severity, timestamp, progname, msg)
6
6
  @keys ||= [
7
7
  LeanplumApi.configuration.production_key,
@@ -1,3 +1,3 @@
1
1
  module LeanplumApi
2
- VERSION = '1.3.1'
2
+ VERSION = '1.3.5'
3
3
  end
data/lib/leanplum_api.rb CHANGED
@@ -1,15 +1,9 @@
1
1
  require 'faraday'
2
2
  require 'active_support/all'
3
3
 
4
- require 'leanplum_api/api'
5
- require 'leanplum_api/configuration'
6
- require 'leanplum_api/content_read_only'
7
- require 'leanplum_api/data_export'
8
- require 'leanplum_api/development'
9
- require 'leanplum_api/exception'
10
- require 'leanplum_api/http'
11
- require 'leanplum_api/logger'
12
- require 'leanplum_api/version'
4
+ path = File.join(File.expand_path(File.dirname(__FILE__)), 'leanplum_api')
5
+ Dir["#{path}/*.rb"].each { |f| require f }
6
+ Dir["#{path}/**/*.rb"].each { |f| require f }
13
7
 
14
8
  module LeanplumApi
15
9
  end
data/spec/api_spec.rb CHANGED
@@ -152,10 +152,6 @@ describe LeanplumApi::API do
152
152
  end
153
153
 
154
154
  context 'data export methods' do
155
- let(:s3_bucket_name) { 'bucket' }
156
- let(:s3_access_key) { 's3_access_key' }
157
- let(:s3_access_id) { 's3_access_id' }
158
-
159
155
  around(:all) do |example|
160
156
  LeanplumApi.configure do |c|
161
157
  c.developer_mode = false
@@ -165,17 +161,27 @@ describe LeanplumApi::API do
165
161
  end
166
162
 
167
163
  context 'export_data' do
168
- it 'should request a data export job with a starttime' do
169
- VCR.use_cassette('export_data') do
170
- expect { api.export_data(Time.at(1438660800).utc) }.to raise_error(/No matching data found/)
164
+ context 'regular export' do
165
+ it 'should request a data export job with a starttime' do
166
+ VCR.use_cassette('export_data') do
167
+ expect { api.export_data(Time.at(1438660800).utc) }.to raise_error LeanplumApi::ResourceNotFoundError
168
+ end
171
169
  end
172
- end
173
170
 
174
- it 'should request a data export job with start and end dates' do
175
- VCR.use_cassette('export_data_dates') do
176
- expect { api.export_data(Date.new(2015, 9, 5), Date.new(2015, 9, 6)) }.to raise_error(/No matching data found/)
171
+ it 'should request a data export job with start and end dates' do
172
+ VCR.use_cassette('export_data_dates') do
173
+ expect { api.export_data(Date.new(2015, 9, 5), Date.new(2015, 9, 6)) }.to raise_error LeanplumApi::ResourceNotFoundError
174
+ end
177
175
  end
178
176
  end
177
+
178
+ context 's3 export' do
179
+ let(:s3_bucket_name) { 'bucket' }
180
+ let(:s3_access_key) { 's3_access_key' }
181
+ let(:s3_access_id) { 's3_access_id' }
182
+
183
+ it 'should request an S3 export'
184
+ end
179
185
  end
180
186
 
181
187
  context 'get_export_results' do
@@ -195,34 +201,44 @@ describe LeanplumApi::API do
195
201
  end
196
202
 
197
203
  context 'content read only methods' do
198
- it 'gets ab tests' do
199
- VCR.use_cassette('get_ab_tests') do
200
- expect(api.get_ab_tests).to eq([])
204
+ context 'ab tests' do
205
+ it 'gets ab tests' do
206
+ VCR.use_cassette('get_ab_tests') do
207
+ expect(api.get_ab_tests).to eq([])
208
+ end
201
209
  end
202
- end
203
210
 
204
- it 'gets an ab test' do
205
- VCR.use_cassette('get_ab_test') do
206
- expect(api.get_ab_tests(1)).to eq([])
211
+ it 'gets an ab test' do
212
+ VCR.use_cassette('get_ab_test') do
213
+ expect(api.get_ab_tests(1)).to eq([])
214
+ end
207
215
  end
208
216
  end
209
217
 
210
- it 'gets messages' do
211
- VCR.use_cassette('get_messages') do
212
- expect(api.get_messages).to eq([{
213
- "id" => 5670583287676928,
214
- "created" => 1440091595.799,
215
- "name" => "New Message",
216
- "active" => false,
217
- "messageType" => "Push Notification"
218
- }])
218
+ context 'messages' do
219
+ it 'gets messages' do
220
+ VCR.use_cassette('get_messages') do
221
+ expect(api.get_messages).to eq([{
222
+ "id" => 5670583287676928,
223
+ "created" => 1440091595.799,
224
+ "name" => "New Message",
225
+ "active" => false,
226
+ "messageType" => "Push Notification"
227
+ }])
228
+ end
229
+ end
230
+
231
+ it 'throws exception on missing message' do
232
+ VCR.use_cassette('missing_message') do
233
+ expect { api.get_message(1234) }.to raise_error LeanplumApi::ResourceNotFoundError
234
+ end
219
235
  end
220
236
  end
221
237
 
222
238
  it 'gets vars' do
223
239
  VCR.use_cassette('get_vars') do
224
240
  vars = api.get_vars(first_user_id)
225
- expect(vars).to eq({'test_var' => 1})
241
+ expect(vars).to eq({ 'test_var' => 1 })
226
242
  end
227
243
  end
228
244
  end
@@ -0,0 +1,40 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://www.leanplum.com/api?action=getMessage&apiVersion=1.0.6&appId=<LEANPLUM_APP_ID>&clientKey=<LEANPLUM_CONTENT_READ_ONLY_KEY>&devMode=false&id=1234
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.2
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - "*/*"
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Access-Control-Allow-Origin:
22
+ - "*"
23
+ Content-Type:
24
+ - application/json
25
+ Date:
26
+ - Mon, 04 Jan 2016 18:15:51 GMT
27
+ Server:
28
+ - Google Frontend
29
+ Cache-Control:
30
+ - private
31
+ Alt-Svc:
32
+ - quic=":443"; ma=604800; v="30,29,28,27,26,25"
33
+ Transfer-Encoding:
34
+ - chunked
35
+ body:
36
+ encoding: UTF-8
37
+ string: '{"response":[{"error":{"message":"Message not found."},"success":false}]}'
38
+ http_version:
39
+ recorded_at: Wed, 12 Aug 2015 00:00:00 GMT
40
+ recorded_with: VCR 2.9.3
data/spec/spec_helper.rb CHANGED
@@ -19,6 +19,7 @@ RSpec.configure do |config|
19
19
  configuration.data_export_key = ENV.fetch('LEANPLUM_DATA_EXPORT_KEY')
20
20
  configuration.content_read_only_key = ENV.fetch('LEANPLUM_CONTENT_READ_ONLY_KEY')
21
21
  configuration.development_key = ENV.fetch('LEANPLUM_DEVELOPMENT_KEY')
22
+ configuration.logger.level = Logger::FATAL
22
23
  end
23
24
 
24
25
  Timecop.freeze('2015-08-12'.to_time.utc)
@@ -37,7 +38,7 @@ VCR.configure do |c|
37
38
  c.filter_sensitive_data('<LEANPLUM_APP_ID>') { ENV.fetch('LEANPLUM_APP_ID') }
38
39
  c.filter_sensitive_data('<LEANPLUM_CONTENT_READ_ONLY_KEY>') { ENV.fetch('LEANPLUM_CONTENT_READ_ONLY_KEY') }
39
40
  c.filter_sensitive_data('<LEANPLUM_DATA_EXPORT_KEY>') { ENV.fetch('LEANPLUM_DATA_EXPORT_KEY') }
40
- c.filter_sensitive_data('<LEANPLUM_DEVELOPMENT_KEY>') { ENV.fetch('LEANPLUM_DEVELOPMENT_KEY') }
41
+ c.filter_sensitive_data('<LEANPLUM_DEVELOPMENT_KEY>') { ENV.fetch('LEANPLUM_DEVELOPMENT_KEY') }
41
42
 
42
43
  c.default_cassette_options = {
43
44
  match_requests_on: [:method, :uri, :body]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leanplum_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lumos Labs, Inc.
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: awesome_print
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: faraday
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -145,7 +159,7 @@ files:
145
159
  - lib/leanplum_api/content_read_only.rb
146
160
  - lib/leanplum_api/data_export.rb
147
161
  - lib/leanplum_api/development.rb
148
- - lib/leanplum_api/exception.rb
162
+ - lib/leanplum_api/faraday_middleware/response_validation.rb
149
163
  - lib/leanplum_api/http.rb
150
164
  - lib/leanplum_api/logger.rb
151
165
  - lib/leanplum_api/version.rb
@@ -159,6 +173,7 @@ files:
159
173
  - spec/fixtures/vcr/get_export_results.yml
160
174
  - spec/fixtures/vcr/get_messages.yml
161
175
  - spec/fixtures/vcr/get_vars.yml
176
+ - spec/fixtures/vcr/missing_message.yml
162
177
  - spec/fixtures/vcr/reset_anomalous_user.yml
163
178
  - spec/fixtures/vcr/set_user_attributes.yml
164
179
  - spec/fixtures/vcr/track_events.yml
@@ -201,6 +216,7 @@ test_files:
201
216
  - spec/fixtures/vcr/get_export_results.yml
202
217
  - spec/fixtures/vcr/get_messages.yml
203
218
  - spec/fixtures/vcr/get_vars.yml
219
+ - spec/fixtures/vcr/missing_message.yml
204
220
  - spec/fixtures/vcr/reset_anomalous_user.yml
205
221
  - spec/fixtures/vcr/set_user_attributes.yml
206
222
  - spec/fixtures/vcr/track_events.yml
@@ -1,4 +0,0 @@
1
- module LeanplumApi
2
- class LeanplumValidationException < Exception
3
- end
4
- end