optimizely-sdk 4.0.1 → 5.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/lib/optimizely/audience.rb +7 -7
  4. data/lib/optimizely/bucketer.rb +2 -2
  5. data/lib/optimizely/config/datafile_project_config.rb +58 -39
  6. data/lib/optimizely/config_manager/http_project_config_manager.rb +20 -10
  7. data/lib/optimizely/config_manager/project_config_manager.rb +2 -1
  8. data/lib/optimizely/config_manager/static_project_config_manager.rb +5 -3
  9. data/lib/optimizely/event/event_factory.rb +2 -2
  10. data/lib/optimizely/event_builder.rb +13 -13
  11. data/lib/optimizely/event_dispatcher.rb +2 -4
  12. data/lib/optimizely/exceptions.rb +69 -11
  13. data/lib/optimizely/helpers/constants.rb +45 -1
  14. data/lib/optimizely/helpers/http_utils.rb +3 -0
  15. data/lib/optimizely/helpers/sdk_settings.rb +61 -0
  16. data/lib/optimizely/helpers/validator.rb +54 -1
  17. data/lib/optimizely/notification_center_registry.rb +71 -0
  18. data/lib/optimizely/odp/lru_cache.rb +114 -0
  19. data/lib/optimizely/odp/odp_config.rb +102 -0
  20. data/lib/optimizely/odp/odp_event.rb +75 -0
  21. data/lib/optimizely/odp/odp_event_api_manager.rb +70 -0
  22. data/lib/optimizely/odp/odp_event_manager.rb +286 -0
  23. data/lib/optimizely/odp/odp_manager.rb +159 -0
  24. data/lib/optimizely/odp/odp_segment_api_manager.rb +122 -0
  25. data/lib/optimizely/odp/odp_segment_manager.rb +97 -0
  26. data/lib/optimizely/optimizely_config.rb +4 -2
  27. data/lib/optimizely/optimizely_factory.rb +17 -14
  28. data/lib/optimizely/optimizely_user_context.rb +40 -6
  29. data/lib/optimizely/user_condition_evaluator.rb +1 -1
  30. data/lib/optimizely/version.rb +2 -2
  31. data/lib/optimizely.rb +155 -23
  32. metadata +15 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c6c3ed7012fac749fdca7c3c328eed7157fbc506f7d69ccebbae2d8064f23efd
4
- data.tar.gz: 0e3e8c5b066fed0afbb542a41441e84da94fa2c92aa323e995eb59a1323d0e45
3
+ metadata.gz: 7249ff9bec6f12c00a9a873df03e6f91c9692bcbe2388e87ea9a6a6f1472fbf5
4
+ data.tar.gz: 902fa025d32f1224833fa25f13158817ff3129244819a170ee3d907812290709
5
5
  SHA512:
6
- metadata.gz: d04f0b497e127336af09e8ddf071767614e2a8c8bb63ab5e6681e18faefcc105864633ca667d79706637b2c49d5e1324ef63d225fb7e4f7388fce785be443854
7
- data.tar.gz: 35d476afe2f1ff9a8d10367a59cd153485dd169324bd8f4f43faba56939bfbd85489160ca5453856bbaa16302357eebec603a9821e2551bb92df7290342d3deb
6
+ metadata.gz: b96a27927fd78a3d789b9edbb2c8488ba499c4f00220f08f9d9463691f38580db04f5dc6f7278873301a6c7217c54a9cf4f38d400b9feba196b7df70ec173e33
7
+ data.tar.gz: 368c9b5f096c8773c4bac487b8d6198ade424dde1ea6295449eaee3ecf5c0b4f7e2ab6b88a8bac4ab5ed2a2dce31f3ca24ef8c8596faae34cdae18aebfcdab79
data/LICENSE CHANGED
@@ -187,7 +187,7 @@
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright 2016, Optimizely and contributors
190
+ © Optimizely 2016
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2016-2017, 2019-2020, Optimizely and contributors
4
+ # Copyright 2016-2017, 2019-2020, 2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@ module Optimizely
59
59
  user_condition_evaluator = UserConditionEvaluator.new(user_context, logger)
60
60
 
61
61
  evaluate_user_conditions = lambda do |condition|
62
- return user_condition_evaluator.evaluate(condition)
62
+ user_condition_evaluator.evaluate(condition)
63
63
  end
64
64
 
65
65
  evaluate_audience = lambda do |audience_id|
@@ -112,12 +112,12 @@ module Optimizely
112
112
  # Returns array of segment names.
113
113
  segments = []
114
114
 
115
- conditions.each do |condition|
116
- case condition
117
- when Array
115
+ case conditions
116
+ when Hash
117
+ segments.push(conditions['value']) if conditions.fetch('match', nil) == 'qualified'
118
+ when Array
119
+ conditions.each do |condition|
118
120
  segments.concat @parse_segments.call(condition)
119
- when Hash
120
- segments.push(condition['value']) if condition.fetch('match', nil) == 'qualified'
121
121
  end
122
122
  end
123
123
 
@@ -110,8 +110,8 @@ module Optimizely
110
110
  # parent_id - String entity ID to use for bucketing ID
111
111
  # traffic_allocations - Array of traffic allocations
112
112
  #
113
- # Returns and array of two values where first value is the entity ID corresponding to the provided bucket value
114
- # or nil if no match is found. The second value contains the array of reasons stating how the deicision was taken
113
+ # Returns an array of two values where first value is the entity ID corresponding to the provided bucket value
114
+ # or nil if no match is found. The second value contains the array of reasons stating how the decision was taken
115
115
  decide_reasons = []
116
116
  bucketing_key = format(BUCKETING_ID_TEMPLATE, bucketing_id: bucketing_id, entity_id: parent_id)
117
117
  bucket_value = generate_bucket_value(bucketing_key)
@@ -93,7 +93,7 @@ module Optimizely
93
93
  @experiment_key_map = generate_key_map(@experiments, 'key')
94
94
  @experiment_id_map = generate_key_map(@experiments, 'id')
95
95
  @audience_id_map = generate_key_map(@audiences, 'id')
96
- @integration_key_map = generate_key_map(@integrations, 'key')
96
+ @integration_key_map = generate_key_map(@integrations, 'key', first_value: true)
97
97
  @audience_id_map = @audience_id_map.merge(generate_key_map(@typed_audiences, 'id')) unless @typed_audiences.empty?
98
98
  @variation_id_map = {}
99
99
  @variation_key_map = {}
@@ -184,20 +184,19 @@ module Optimizely
184
184
  # skip_json_validation - Optional boolean param which allows skipping JSON schema
185
185
  # validation upon object invocation. By default JSON schema validation will be performed.
186
186
  # Returns instance of DatafileProjectConfig, nil otherwise.
187
+ logger ||= SimpleLogger.new
187
188
  if !skip_json_validation && !Helpers::Validator.datafile_valid?(datafile)
188
- default_logger = SimpleLogger.new
189
- default_logger.log(Logger::ERROR, InvalidInputError.new('datafile').message)
189
+ logger.log(Logger::ERROR, InvalidInputError.new('datafile').message)
190
190
  return nil
191
191
  end
192
192
 
193
193
  begin
194
194
  config = new(datafile, logger, error_handler)
195
195
  rescue StandardError => e
196
- default_logger = SimpleLogger.new
197
196
  error_to_handle = e.instance_of?(InvalidDatafileVersionError) ? e : InvalidInputError.new('datafile')
198
197
  error_msg = error_to_handle.message
199
198
 
200
- default_logger.log(Logger::ERROR, error_msg)
199
+ logger.log(Logger::ERROR, error_msg)
201
200
  error_handler.handle_error error_to_handle
202
201
  return nil
203
202
  end
@@ -224,8 +223,9 @@ module Optimizely
224
223
  experiment = @experiment_key_map[experiment_key]
225
224
  return experiment if experiment
226
225
 
227
- @logger.log Logger::ERROR, "Experiment key '#{experiment_key}' is not in datafile."
228
- @error_handler.handle_error InvalidExperimentError
226
+ invalid_experiment_error = InvalidExperimentError.new(experiment_key: experiment_key)
227
+ @logger.log Logger::ERROR, invalid_experiment_error.message
228
+ @error_handler.handle_error invalid_experiment_error
229
229
  nil
230
230
  end
231
231
 
@@ -239,8 +239,9 @@ module Optimizely
239
239
  experiment = @experiment_id_map[experiment_id]
240
240
  return experiment if experiment
241
241
 
242
- @logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
243
- @error_handler.handle_error InvalidExperimentError
242
+ invalid_experiment_error = InvalidExperimentError.new(experiment_id: experiment_id)
243
+ @logger.log Logger::ERROR, invalid_experiment_error.message
244
+ @error_handler.handle_error invalid_experiment_error
244
245
  nil
245
246
  end
246
247
 
@@ -254,8 +255,9 @@ module Optimizely
254
255
  experiment = @experiment_id_map[experiment_id]
255
256
  return experiment['key'] unless experiment.nil?
256
257
 
257
- @logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
258
- @error_handler.handle_error InvalidExperimentError
258
+ invalid_experiment_error = InvalidExperimentError.new(experiment_id: experiment_id)
259
+ @logger.log Logger::ERROR, invalid_experiment_error.message
260
+ @error_handler.handle_error invalid_experiment_error
259
261
  nil
260
262
  end
261
263
 
@@ -269,8 +271,9 @@ module Optimizely
269
271
  event = @event_key_map[event_key]
270
272
  return event if event
271
273
 
272
- @logger.log Logger::ERROR, "Event '#{event_key}' is not in datafile."
273
- @error_handler.handle_error InvalidEventError
274
+ invalid_event_error = InvalidEventError.new(event_key)
275
+ @logger.log Logger::ERROR, invalid_event_error.message
276
+ @error_handler.handle_error invalid_event_error
274
277
  nil
275
278
  end
276
279
 
@@ -284,8 +287,9 @@ module Optimizely
284
287
  audience = @audience_id_map[audience_id]
285
288
  return audience if audience
286
289
 
287
- @logger.log Logger::ERROR, "Audience '#{audience_id}' is not in datafile."
288
- @error_handler.handle_error InvalidAudienceError
290
+ invalid_audience_error = InvalidAudienceError.new(audience_id)
291
+ @logger.log Logger::ERROR, invalid_audience_error.message
292
+ @error_handler.handle_error invalid_audience_error
289
293
  nil
290
294
  end
291
295
 
@@ -309,13 +313,15 @@ module Optimizely
309
313
  variation = variation_id_map[variation_id]
310
314
  return variation if variation
311
315
 
312
- @logger.log Logger::ERROR, "Variation id '#{variation_id}' is not in datafile."
313
- @error_handler.handle_error InvalidVariationError
316
+ invalid_variation_error = InvalidVariationError.new(variation_id: variation_id)
317
+ @logger.log Logger::ERROR, invalid_variation_error.message
318
+ @error_handler.handle_error invalid_variation_error
314
319
  return nil
315
320
  end
316
321
 
317
- @logger.log Logger::ERROR, "Experiment key '#{experiment_key}' is not in datafile."
318
- @error_handler.handle_error InvalidExperimentError
322
+ invalid_experiment_error = InvalidExperimentError.new(experiment_key: experiment_key)
323
+ @logger.log Logger::ERROR, invalid_experiment_error.message
324
+ @error_handler.handle_error invalid_experiment_error
319
325
  nil
320
326
  end
321
327
 
@@ -332,13 +338,15 @@ module Optimizely
332
338
  variation = variation_id_map_by_experiment_id[variation_id]
333
339
  return variation if variation
334
340
 
335
- @logger.log Logger::ERROR, "Variation id '#{variation_id}' is not in datafile."
336
- @error_handler.handle_error InvalidVariationError
341
+ invalid_variation_error = InvalidVariationError.new(variation_id: variation_id)
342
+ @logger.log Logger::ERROR, invalid_variation_error.message
343
+ @error_handler.handle_error invalid_variation_error
337
344
  return nil
338
345
  end
339
346
 
340
- @logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
341
- @error_handler.handle_error InvalidExperimentError
347
+ invalid_experiment_error = InvalidExperimentError.new(experiment_id: experiment_id)
348
+ @logger.log Logger::ERROR, invalid_experiment_error.message
349
+ @error_handler.handle_error invalid_experiment_error
342
350
  nil
343
351
  end
344
352
 
@@ -355,13 +363,15 @@ module Optimizely
355
363
  variation = variation_key_map[variation_key]
356
364
  return variation['id'] if variation
357
365
 
358
- @logger.log Logger::ERROR, "Variation key '#{variation_key}' is not in datafile."
359
- @error_handler.handle_error InvalidVariationError
366
+ invalid_variation_error = InvalidVariationError.new(variation_key: variation_key)
367
+ @logger.log Logger::ERROR, invalid_variation_error.message
368
+ @error_handler.handle_error invalid_variation_error
360
369
  return nil
361
370
  end
362
371
 
363
- @logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
364
- @error_handler.handle_error InvalidExperimentError
372
+ invalid_experiment_error = InvalidExperimentError.new(experiment_id: experiment_id)
373
+ @logger.log Logger::ERROR, invalid_experiment_error.message
374
+ @error_handler.handle_error invalid_experiment_error
365
375
  nil
366
376
  end
367
377
 
@@ -378,13 +388,15 @@ module Optimizely
378
388
  variation = variation_key_map[variation_key]
379
389
  return variation['id'] if variation
380
390
 
381
- @logger.log Logger::ERROR, "Variation key '#{variation_key}' is not in datafile."
382
- @error_handler.handle_error InvalidVariationError
391
+ invalid_variation_error = InvalidVariationError.new(variation_key: variation_key)
392
+ @logger.log Logger::ERROR, invalid_variation_error.message
393
+ @error_handler.handle_error invalid_variation_error
383
394
  return nil
384
395
  end
385
396
 
386
- @logger.log Logger::ERROR, "Experiment key '#{experiment_key}' is not in datafile."
387
- @error_handler.handle_error InvalidExperimentError
397
+ invalid_experiment_error = InvalidExperimentError.new(experiment_key: experiment_key)
398
+ @logger.log Logger::ERROR, invalid_experiment_error.message
399
+ @error_handler.handle_error invalid_experiment_error
388
400
  nil
389
401
  end
390
402
 
@@ -398,8 +410,9 @@ module Optimizely
398
410
  experiment = @experiment_id_map[experiment_id]
399
411
  return experiment['forcedVariations'] if experiment
400
412
 
401
- @logger.log Logger::ERROR, "Experiment ID '#{experiment_id}' is not in datafile."
402
- @error_handler.handle_error InvalidExperimentError
413
+ invalid_experiment_error = InvalidExperimentError.new(experiment_id: experiment_id)
414
+ @logger.log Logger::ERROR, invalid_experiment_error.message
415
+ @error_handler.handle_error invalid_experiment_error
403
416
  end
404
417
 
405
418
  def get_attribute_id(attribute_key)
@@ -421,8 +434,9 @@ module Optimizely
421
434
  end
422
435
  return attribute_key if has_reserved_prefix
423
436
 
424
- @logger.log Logger::ERROR, "Attribute key '#{attribute_key}' is not in datafile."
425
- @error_handler.handle_error InvalidAttributeError
437
+ invalid_attribute_error = InvalidAttributeError.new(attribute_key)
438
+ @logger.log Logger::ERROR, invalid_attribute_error.message
439
+ @error_handler.handle_error invalid_attribute_error
426
440
  nil
427
441
  end
428
442
 
@@ -440,8 +454,9 @@ module Optimizely
440
454
  variation = variation_id_map[variation_id]
441
455
  return true if variation
442
456
 
443
- @logger.log Logger::ERROR, "Variation ID '#{variation_id}' is not in datafile."
444
- @error_handler.handle_error InvalidVariationError
457
+ invalid_variation_error = InvalidVariationError.new(variation_id: variation_id)
458
+ @logger.log Logger::ERROR, invalid_variation_error.message
459
+ @error_handler.handle_error invalid_variation_error
445
460
  end
446
461
 
447
462
  false
@@ -525,15 +540,19 @@ module Optimizely
525
540
  flag_variation_map
526
541
  end
527
542
 
528
- def generate_key_map(array, key)
543
+ def generate_key_map(array, key, first_value: false)
529
544
  # Helper method to generate map from key to hash in array of hashes
530
545
  #
531
546
  # array - Array consisting of hash
532
547
  # key - Key in each hash which will be key in the map
548
+ # first_value - Determines which value to save if there are duplicate keys. By default the last instance of the key
549
+ # will be saved. Set to true to save the first key/value encountered.
533
550
  #
534
551
  # Returns map mapping key to hash
535
552
 
536
- Hash[array.map { |obj| [obj[key], obj] }]
553
+ array
554
+ .group_by { |obj| obj[key] }
555
+ .transform_values { |group| first_value ? group.first : group.last }
537
556
  end
538
557
  end
539
558
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2019-2020, 2022, Optimizely and contributors
4
+ # Copyright 2019-2020, 2022-2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -33,12 +33,12 @@ module Optimizely
33
33
  class HTTPProjectConfigManager < ProjectConfigManager
34
34
  # Config manager that polls for the datafile and updated ProjectConfig based on an update interval.
35
35
 
36
- attr_reader :stopped
36
+ attr_reader :stopped, :sdk_key
37
37
 
38
38
  # Initialize config manager. One of sdk_key or url has to be set to be able to use.
39
39
  #
40
- # sdk_key - Optional string uniquely identifying the datafile. It's required unless a URL is passed in.
41
- # datafile: Optional JSON string representing the project.
40
+ # sdk_key - Optional string uniquely identifying the datafile. It's required unless a datafile with sdk_key is passed in.
41
+ # datafile - Optional JSON string representing the project. If nil, sdk_key is required.
42
42
  # polling_interval - Optional floating point number representing time interval in seconds
43
43
  # at which to request datafile and set ProjectConfig.
44
44
  # blocking_timeout - Optional Time in seconds to block the config call until config object has been initialized.
@@ -83,6 +83,10 @@ module Optimizely
83
83
  @notification_center = notification_center.is_a?(Optimizely::NotificationCenter) ? notification_center : NotificationCenter.new(@logger, @error_handler)
84
84
  @optimizely_config = nil
85
85
  @config = datafile.nil? ? nil : DatafileProjectConfig.create(datafile, @logger, @error_handler, @skip_json_validation)
86
+ @sdk_key = sdk_key || @config&.sdk_key
87
+
88
+ raise MissingSdkKeyError if @sdk_key.nil?
89
+
86
90
  @mutex = Mutex.new
87
91
  @resource = ConditionVariable.new
88
92
  @async_scheduler = AsyncScheduler.new(method(:fetch_datafile_config), @polling_interval, auto_update, @logger)
@@ -98,11 +102,6 @@ module Optimizely
98
102
  end
99
103
 
100
104
  def start!
101
- if @stopped
102
- @logger.log(Logger::WARN, 'Not starting. Already stopped.')
103
- return
104
- end
105
-
106
105
  @async_scheduler.start!
107
106
  @stopped = false
108
107
  end
@@ -142,7 +141,7 @@ module Optimizely
142
141
  end
143
142
 
144
143
  def optimizely_config
145
- @optimizely_config = OptimizelyConfig.new(@config).config if @optimizely_config.nil?
144
+ @optimizely_config = OptimizelyConfig.new(@config, @logger).config if @optimizely_config.nil?
146
145
 
147
146
  @optimizely_config
148
147
  end
@@ -222,6 +221,10 @@ module Optimizely
222
221
 
223
222
  @notification_center.send_notifications(NotificationCenter::NOTIFICATION_TYPES[:OPTIMIZELY_CONFIG_UPDATE])
224
223
 
224
+ NotificationCenterRegistry
225
+ .get_notification_center(@sdk_key, @logger)
226
+ &.send_notifications(NotificationCenter::NOTIFICATION_TYPES[:OPTIMIZELY_CONFIG_UPDATE])
227
+
225
228
  @logger.log(Logger::DEBUG, 'Received new datafile and updated config. ' \
226
229
  "Old revision number: #{previous_revision}. New revision number: #{@config.revision}.")
227
230
  end
@@ -260,6 +263,13 @@ module Optimizely
260
263
  return
261
264
  end
262
265
 
266
+ if polling_interval < 30
267
+ @logger.log(
268
+ Logger::WARN,
269
+ 'Polling intervals below 30 seconds are not recommended.'
270
+ )
271
+ end
272
+
263
273
  @polling_interval = polling_interval
264
274
  end
265
275
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2019, Optimizely and contributors
4
+ # Copyright 2019, 2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -20,5 +20,6 @@ module Optimizely
20
20
  # Interface for fetching ProjectConfig instance.
21
21
 
22
22
  def config; end
23
+ def sdk_key; end
23
24
  end
24
25
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2019-2020, 2022, Optimizely and contributors
4
+ # Copyright 2019-2020, 2022-2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ require_relative 'project_config_manager'
23
23
  module Optimizely
24
24
  class StaticProjectConfigManager < ProjectConfigManager
25
25
  # Implementation of ProjectConfigManager interface.
26
- attr_reader :config
26
+ attr_reader :config, :sdk_key
27
27
 
28
28
  def initialize(datafile, logger, error_handler, skip_json_validation)
29
29
  # Looks up and sets datafile and config based on response body.
@@ -41,11 +41,13 @@ module Optimizely
41
41
  error_handler,
42
42
  skip_json_validation
43
43
  )
44
+ @logger = logger
45
+ @sdk_key = @config&.sdk_key
44
46
  @optimizely_config = nil
45
47
  end
46
48
 
47
49
  def optimizely_config
48
- @optimizely_config = OptimizelyConfig.new(@config).config if @optimizely_config.nil?
50
+ @optimizely_config = OptimizelyConfig.new(@config, @logger).config if @optimizely_config.nil?
49
51
 
50
52
  @optimizely_config
51
53
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2019-2020, 2022, Optimizely and contributors
4
+ # Copyright 2019-2020, 2022-2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ module Optimizely
72
72
 
73
73
  def build_attribute_list(user_attributes, project_config)
74
74
  visitor_attributes = []
75
- user_attributes&.keys&.each do |attribute_key|
75
+ user_attributes&.each_key do |attribute_key|
76
76
  # Omit attribute values that are not supported by the log endpoint.
77
77
  attribute_value = user_attributes[attribute_key]
78
78
  next unless Helpers::Validator.attribute_valid?(attribute_key, attribute_value)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2016-2019, 2022, Optimizely and contributors
4
+ # Copyright 2016-2019, 2022-2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -62,20 +62,20 @@ module Optimizely
62
62
 
63
63
  visitor_attributes = []
64
64
 
65
- attributes&.keys&.each do |attribute_key|
65
+ attributes&.each_key do |attribute_key|
66
66
  # Omit attribute values that are not supported by the log endpoint.
67
67
  attribute_value = attributes[attribute_key]
68
- if Helpers::Validator.attribute_valid?(attribute_key, attribute_value)
69
- attribute_id = project_config.get_attribute_id attribute_key
70
- if attribute_id
71
- visitor_attributes.push(
72
- entity_id: attribute_id,
73
- key: attribute_key,
74
- type: CUSTOM_ATTRIBUTE_FEATURE_TYPE,
75
- value: attribute_value
76
- )
77
- end
78
- end
68
+ next unless Helpers::Validator.attribute_valid?(attribute_key, attribute_value)
69
+
70
+ attribute_id = project_config.get_attribute_id attribute_key
71
+ next unless attribute_id
72
+
73
+ visitor_attributes.push(
74
+ entity_id: attribute_id,
75
+ key: attribute_key,
76
+ type: CUSTOM_ATTRIBUTE_FEATURE_TYPE,
77
+ value: attribute_value
78
+ )
79
79
  end
80
80
  # Append Bot Filtering Attribute
81
81
  if project_config.bot_filtering == true || project_config.bot_filtering == false
@@ -17,6 +17,7 @@
17
17
  #
18
18
  require_relative 'exceptions'
19
19
  require_relative 'helpers/http_utils'
20
+ require_relative 'helpers/constants'
20
21
 
21
22
  module Optimizely
22
23
  class NoOpEventDispatcher
@@ -26,9 +27,6 @@ module Optimizely
26
27
  end
27
28
 
28
29
  class EventDispatcher
29
- # @api constants
30
- REQUEST_TIMEOUT = 10
31
-
32
30
  def initialize(logger: nil, error_handler: nil, proxy_config: nil)
33
31
  @logger = logger || NoOpLogger.new
34
32
  @error_handler = error_handler || NoOpErrorHandler.new
@@ -40,7 +38,7 @@ module Optimizely
40
38
  # @param event - Event object
41
39
  def dispatch_event(event)
42
40
  response = Helpers::HttpUtils.make_request(
43
- event.url, event.http_verb, event.params.to_json, event.headers, REQUEST_TIMEOUT, @proxy_config
41
+ event.url, event.http_verb, event.params.to_json, event.headers, Helpers::Constants::EVENT_DISPATCH_CONFIG[:REQUEST_TIMEOUT], @proxy_config
44
42
  )
45
43
 
46
44
  error_msg = "Event failed to dispatch with response code: #{response.code}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2016-2020, 2022, Optimizely and contributors
4
+ # Copyright 2016-2020, 2022-2023, Optimizely and contributors
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -25,19 +25,45 @@ module Optimizely
25
25
  end
26
26
  end
27
27
 
28
+ class HTTPUriError < Error
29
+ # Raised when a provided URI is invalid.
30
+ def initialize(msg = 'Provided URI was invalid.')
31
+ super
32
+ end
33
+ end
34
+
35
+ class MissingSdkKeyError < Error
36
+ # Raised when a provided URI is invalid.
37
+ def initialize(msg = 'SDK key not provided/cannot be found in the datafile.')
38
+ super
39
+ end
40
+ end
41
+
28
42
  class InvalidAudienceError < Error
29
43
  # Raised when an invalid audience is provided
30
44
 
31
- def initialize(msg = 'Provided audience is not in datafile.')
32
- super
45
+ attr_reader :audience_id
46
+
47
+ def initialize(audience_id)
48
+ raise ArgumentError, 'audience_id must be provided' if audience_id.nil?
49
+
50
+ super("Audience id '#{audience_id}' is not in datafile.")
51
+
52
+ @audience_id = audience_id
33
53
  end
34
54
  end
35
55
 
36
56
  class InvalidAttributeError < Error
37
57
  # Raised when an invalid attribute is provided
38
58
 
39
- def initialize(msg = 'Provided attribute is not in datafile.')
40
- super
59
+ attr_reader :attribute_key
60
+
61
+ def initialize(attribute_key)
62
+ raise ArgumentError, 'attribute_key must be provided' if attribute_key.nil?
63
+
64
+ super("Attribute key '#{attribute_key}' is not in datafile.")
65
+
66
+ @attribute_key = attribute_key
41
67
  end
42
68
  end
43
69
 
@@ -60,24 +86,56 @@ module Optimizely
60
86
  class InvalidExperimentError < Error
61
87
  # Raised when an invalid experiment key is provided
62
88
 
63
- def initialize(msg = 'Provided experiment is not in datafile.')
64
- super
89
+ attr_reader :experiment_id, :experiment_key
90
+
91
+ def initialize(experiment_id: nil, experiment_key: nil)
92
+ raise ArgumentError, 'Either experiment_id or experiment_key must be provided.' if experiment_id.nil? && experiment_key.nil?
93
+ raise ArgumentError, 'Cannot provide both experiment_id and experiment_key.' if !experiment_id.nil? && !experiment_key.nil?
94
+
95
+ if experiment_id.nil?
96
+ @experiment_key = experiment_key
97
+ identifier = "key '#{@experiment_key}'"
98
+ else
99
+ @experiment_id = experiment_id
100
+ identifier = "id '#{@experiment_id}'"
101
+ end
102
+
103
+ super("Experiment #{identifier} is not in datafile.")
65
104
  end
66
105
  end
67
106
 
68
107
  class InvalidEventError < Error
69
108
  # Raised when an invalid event key is provided
70
109
 
71
- def initialize(msg = 'Provided event is not in datafile.')
72
- super
110
+ attr_reader :event_key
111
+
112
+ def initialize(event_key)
113
+ raise ArgumentError, 'event_key must be provided.' if event_key.nil?
114
+
115
+ super("Event key '#{event_key}' is not in datafile.")
116
+
117
+ @event_key = event_key
73
118
  end
74
119
  end
75
120
 
76
121
  class InvalidVariationError < Error
77
122
  # Raised when an invalid variation key or ID is provided
78
123
 
79
- def initialize(msg = 'Provided variation is not in datafile.')
80
- super
124
+ attr_reader :variation_id, :variation_key
125
+
126
+ def initialize(variation_id: nil, variation_key: nil)
127
+ raise ArgumentError, 'Either variation_id or variation_key must be provided.' if variation_id.nil? && variation_key.nil?
128
+ raise ArgumentError, 'Cannot provide both variation_id and variation_key.' if !variation_id.nil? && !variation_key.nil?
129
+
130
+ if variation_id.nil?
131
+ identifier = "key '#{variation_key}'"
132
+ @variation_key = variation_key
133
+ else
134
+ identifier = "id '#{variation_id}'"
135
+ @variation_id = variation_id
136
+ end
137
+
138
+ super("Variation #{identifier} is not in datafile.")
81
139
  end
82
140
  end
83
141