optimizely-sdk 3.3.2.rc1 → 3.6.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/lib/optimizely.rb +198 -36
- data/lib/optimizely/audience.rb +22 -13
- data/lib/optimizely/bucketer.rb +3 -8
- data/lib/optimizely/config/datafile_project_config.rb +17 -3
- data/lib/optimizely/config/proxy_config.rb +34 -0
- data/lib/optimizely/config_manager/async_scheduler.rb +6 -2
- data/lib/optimizely/config_manager/http_project_config_manager.rb +45 -25
- data/lib/optimizely/config_manager/static_project_config_manager.rb +6 -2
- data/lib/optimizely/custom_attribute_condition_evaluator.rb +133 -37
- data/lib/optimizely/decision_service.rb +30 -29
- data/lib/optimizely/event/batch_event_processor.rb +47 -39
- data/lib/optimizely/event_dispatcher.rb +8 -14
- data/lib/optimizely/exceptions.rb +17 -9
- data/lib/optimizely/helpers/constants.rb +18 -5
- data/lib/optimizely/helpers/http_utils.rb +64 -0
- data/lib/optimizely/helpers/variable_type.rb +8 -1
- data/lib/optimizely/optimizely_config.rb +117 -0
- data/lib/optimizely/optimizely_factory.rb +54 -5
- data/lib/optimizely/project_config.rb +3 -1
- data/lib/optimizely/semantic_version.rb +166 -0
- data/lib/optimizely/version.rb +1 -1
- metadata +9 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d8204dce32c85bea56820607c0268b363fb86e7506ce685a2675645b4ef581b
|
4
|
+
data.tar.gz: dce7cd63fde5e24e179a74f8f14c6a22ed389028faac38a373af105683b596f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cc88f9802b38a2eb29354507303c6dcdcf6a402f721d24689f1e42a52a79319568974cf3584c6bf94398ff5f1410aacf49a1adf7aa27ef9105f3e7b23d39e3d
|
7
|
+
data.tar.gz: a6f0a7f052bb851ce760c4c88e0fe0dea18c14b42d5bcf457ac9cfefe3eaa2027f1b847c2ab0c133233618502cfe9207b1e82a5b1d65d0d4a678b58f5ea0ff88
|
data/lib/optimizely.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2016-
|
4
|
+
# Copyright 2016-2020, 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,6 +33,7 @@ require_relative 'optimizely/helpers/validator'
|
|
33
33
|
require_relative 'optimizely/helpers/variable_type'
|
34
34
|
require_relative 'optimizely/logger'
|
35
35
|
require_relative 'optimizely/notification_center'
|
36
|
+
require_relative 'optimizely/optimizely_config'
|
36
37
|
|
37
38
|
module Optimizely
|
38
39
|
class Project
|
@@ -429,6 +430,32 @@ module Optimizely
|
|
429
430
|
variable_value
|
430
431
|
end
|
431
432
|
|
433
|
+
# Get the Json value of the specified variable in the feature flag in a Dict.
|
434
|
+
#
|
435
|
+
# @param feature_flag_key - String key of feature flag the variable belongs to
|
436
|
+
# @param variable_key - String key of variable for which we are getting the string value
|
437
|
+
# @param user_id - String user ID
|
438
|
+
# @param attributes - Hash representing visitor attributes and values which need to be recorded.
|
439
|
+
#
|
440
|
+
# @return [Dict] the Dict containing variable value.
|
441
|
+
# @return [nil] if the feature flag or variable are not found.
|
442
|
+
|
443
|
+
def get_feature_variable_json(feature_flag_key, variable_key, user_id, attributes = nil)
|
444
|
+
unless is_valid
|
445
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('get_feature_variable_json').message)
|
446
|
+
return nil
|
447
|
+
end
|
448
|
+
variable_value = get_feature_variable_for_type(
|
449
|
+
feature_flag_key,
|
450
|
+
variable_key,
|
451
|
+
Optimizely::Helpers::Constants::VARIABLE_TYPES['JSON'],
|
452
|
+
user_id,
|
453
|
+
attributes
|
454
|
+
)
|
455
|
+
|
456
|
+
variable_value
|
457
|
+
end
|
458
|
+
|
432
459
|
# Get the Boolean value of the specified variable in the feature flag.
|
433
460
|
#
|
434
461
|
# @param feature_flag_key - String key of feature flag the variable belongs to
|
@@ -483,6 +510,71 @@ module Optimizely
|
|
483
510
|
variable_value
|
484
511
|
end
|
485
512
|
|
513
|
+
# Get values of all the variables in the feature flag and returns them in a Dict
|
514
|
+
#
|
515
|
+
# @param feature_flag_key - String key of feature flag
|
516
|
+
# @param user_id - String user ID
|
517
|
+
# @param attributes - Hash representing visitor attributes and values which need to be recorded.
|
518
|
+
#
|
519
|
+
# @return [Dict] the Dict containing all the varible values
|
520
|
+
# @return [nil] if the feature flag is not found.
|
521
|
+
|
522
|
+
def get_all_feature_variables(feature_flag_key, user_id, attributes = nil)
|
523
|
+
unless is_valid
|
524
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('get_all_feature_variables').message)
|
525
|
+
return nil
|
526
|
+
end
|
527
|
+
|
528
|
+
return nil unless Optimizely::Helpers::Validator.inputs_valid?(
|
529
|
+
{
|
530
|
+
feature_flag_key: feature_flag_key,
|
531
|
+
user_id: user_id
|
532
|
+
},
|
533
|
+
@logger, Logger::ERROR
|
534
|
+
)
|
535
|
+
|
536
|
+
return nil unless user_inputs_valid?(attributes)
|
537
|
+
|
538
|
+
config = project_config
|
539
|
+
|
540
|
+
feature_flag = config.get_feature_flag_from_key(feature_flag_key)
|
541
|
+
unless feature_flag
|
542
|
+
@logger.log(Logger::INFO, "No feature flag was found for key '#{feature_flag_key}'.")
|
543
|
+
return nil
|
544
|
+
end
|
545
|
+
|
546
|
+
decision = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
547
|
+
variation = decision ? decision['variation'] : nil
|
548
|
+
feature_enabled = variation ? variation['featureEnabled'] : false
|
549
|
+
all_variables = {}
|
550
|
+
|
551
|
+
feature_flag['variables'].each do |variable|
|
552
|
+
variable_value = get_feature_variable_for_variation(feature_flag_key, feature_enabled, variation, variable, user_id)
|
553
|
+
all_variables[variable['key']] = Helpers::VariableType.cast_value_to_type(variable_value, variable['type'], @logger)
|
554
|
+
end
|
555
|
+
|
556
|
+
source_string = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
557
|
+
if decision && decision['source'] == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
558
|
+
source_info = {
|
559
|
+
experiment_key: decision.experiment['key'],
|
560
|
+
variation_key: variation['key']
|
561
|
+
}
|
562
|
+
source_string = Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
563
|
+
end
|
564
|
+
|
565
|
+
@notification_center.send_notifications(
|
566
|
+
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
567
|
+
Helpers::Constants::DECISION_NOTIFICATION_TYPES['ALL_FEATURE_VARIABLES'], user_id, (attributes || {}),
|
568
|
+
feature_key: feature_flag_key,
|
569
|
+
feature_enabled: feature_enabled,
|
570
|
+
source: source_string,
|
571
|
+
variable_values: all_variables,
|
572
|
+
source_info: source_info || {}
|
573
|
+
)
|
574
|
+
|
575
|
+
all_variables
|
576
|
+
end
|
577
|
+
|
486
578
|
# Get the Integer value of the specified variable in the feature flag.
|
487
579
|
#
|
488
580
|
# @param feature_flag_key - String key of feature flag the variable belongs to
|
@@ -523,6 +615,57 @@ module Optimizely
|
|
523
615
|
@event_processor.stop! if @event_processor.respond_to?(:stop!)
|
524
616
|
end
|
525
617
|
|
618
|
+
def get_optimizely_config
|
619
|
+
# Get OptimizelyConfig object containing experiments and features data
|
620
|
+
# Returns Object
|
621
|
+
#
|
622
|
+
# OptimizelyConfig Object Schema
|
623
|
+
# {
|
624
|
+
# 'experimentsMap' => {
|
625
|
+
# 'my-fist-experiment' => {
|
626
|
+
# 'id' => '111111',
|
627
|
+
# 'key' => 'my-fist-experiment'
|
628
|
+
# 'variationsMap' => {
|
629
|
+
# 'variation_1' => {
|
630
|
+
# 'id' => '121212',
|
631
|
+
# 'key' => 'variation_1',
|
632
|
+
# 'variablesMap' => {
|
633
|
+
# 'age' => {
|
634
|
+
# 'id' => '222222',
|
635
|
+
# 'key' => 'age',
|
636
|
+
# 'type' => 'integer',
|
637
|
+
# 'value' => '0',
|
638
|
+
# }
|
639
|
+
# }
|
640
|
+
# }
|
641
|
+
# }
|
642
|
+
# }
|
643
|
+
# },
|
644
|
+
# 'featuresMap' => {
|
645
|
+
# 'awesome-feature' => {
|
646
|
+
# 'id' => '333333',
|
647
|
+
# 'key' => 'awesome-feature',
|
648
|
+
# 'experimentsMap' => Object,
|
649
|
+
# 'variablesMap' => Object,
|
650
|
+
# }
|
651
|
+
# },
|
652
|
+
# 'revision' => '13',
|
653
|
+
# }
|
654
|
+
#
|
655
|
+
unless is_valid
|
656
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('get_optimizely_config').message)
|
657
|
+
return nil
|
658
|
+
end
|
659
|
+
|
660
|
+
# config_manager might not contain optimizely_config if its supplied by the consumer
|
661
|
+
# Generating a new OptimizelyConfig object in this case as a fallback
|
662
|
+
if @config_manager.respond_to?(:optimizely_config)
|
663
|
+
@config_manager.optimizely_config
|
664
|
+
else
|
665
|
+
OptimizelyConfig.new(project_config).config
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
526
669
|
private
|
527
670
|
|
528
671
|
def get_variation_with_config(experiment_key, user_id, attributes, config)
|
@@ -597,8 +740,6 @@ module Optimizely
|
|
597
740
|
# Error message logged in DatafileProjectConfig- get_feature_flag_from_key
|
598
741
|
return nil if variable.nil?
|
599
742
|
|
600
|
-
feature_enabled = false
|
601
|
-
|
602
743
|
# If variable_type is nil, set it equal to variable['type']
|
603
744
|
variable_type ||= variable['type']
|
604
745
|
# Returns nil if type differs
|
@@ -606,43 +747,24 @@ module Optimizely
|
|
606
747
|
@logger.log(Logger::WARN,
|
607
748
|
"Requested variable as type '#{variable_type}' but variable '#{variable_key}' is of type '#{variable['type']}'.")
|
608
749
|
return nil
|
609
|
-
else
|
610
|
-
source_string = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
611
|
-
decision = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
612
|
-
variable_value = variable['defaultValue']
|
613
|
-
if decision
|
614
|
-
variation = decision['variation']
|
615
|
-
if decision['source'] == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
616
|
-
source_info = {
|
617
|
-
experiment_key: decision.experiment['key'],
|
618
|
-
variation_key: variation['key']
|
619
|
-
}
|
620
|
-
source_string = Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
621
|
-
end
|
622
|
-
feature_enabled = variation['featureEnabled']
|
623
|
-
if feature_enabled == true
|
624
|
-
variation_variable_usages = config.variation_id_to_variable_usage_map[variation['id']]
|
625
|
-
variable_id = variable['id']
|
626
|
-
if variation_variable_usages&.key?(variable_id)
|
627
|
-
variable_value = variation_variable_usages[variable_id]['value']
|
628
|
-
@logger.log(Logger::INFO,
|
629
|
-
"Got variable value '#{variable_value}' for variable '#{variable_key}' of feature flag '#{feature_flag_key}'.")
|
630
|
-
else
|
631
|
-
@logger.log(Logger::DEBUG,
|
632
|
-
"Variable '#{variable_key}' is not used in variation '#{variation['key']}'. Returning the default variable value '#{variable_value}'.")
|
633
|
-
end
|
634
|
-
else
|
635
|
-
@logger.log(Logger::DEBUG,
|
636
|
-
"Feature '#{feature_flag_key}' for variation '#{variation['key']}' is not enabled. Returning the default variable value '#{variable_value}'.")
|
637
|
-
end
|
638
|
-
else
|
639
|
-
@logger.log(Logger::INFO,
|
640
|
-
"User '#{user_id}' was not bucketed into any variation for feature flag '#{feature_flag_key}'. Returning the default variable value '#{variable_value}'.")
|
641
|
-
end
|
642
750
|
end
|
643
751
|
|
752
|
+
decision = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
753
|
+
variation = decision ? decision['variation'] : nil
|
754
|
+
feature_enabled = variation ? variation['featureEnabled'] : false
|
755
|
+
|
756
|
+
variable_value = get_feature_variable_for_variation(feature_flag_key, feature_enabled, variation, variable, user_id)
|
644
757
|
variable_value = Helpers::VariableType.cast_value_to_type(variable_value, variable_type, @logger)
|
645
758
|
|
759
|
+
source_string = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
760
|
+
if decision && decision['source'] == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
761
|
+
source_info = {
|
762
|
+
experiment_key: decision.experiment['key'],
|
763
|
+
variation_key: variation['key']
|
764
|
+
}
|
765
|
+
source_string = Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
766
|
+
end
|
767
|
+
|
646
768
|
@notification_center.send_notifications(
|
647
769
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
648
770
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE_VARIABLE'], user_id, (attributes || {}),
|
@@ -658,6 +780,46 @@ module Optimizely
|
|
658
780
|
variable_value
|
659
781
|
end
|
660
782
|
|
783
|
+
def get_feature_variable_for_variation(feature_flag_key, feature_enabled, variation, variable, user_id)
|
784
|
+
# Helper method to get the non type-casted value for a variable attached to a
|
785
|
+
# feature flag. Returns appropriate variable value depending on whether there
|
786
|
+
# was a matching variation, feature was enabled or not or varible was part of the
|
787
|
+
# available variation or not. Also logs the appropriate message explaining how it
|
788
|
+
# evaluated the value of the variable.
|
789
|
+
#
|
790
|
+
# feature_flag_key - String key of feature flag the variable belongs to
|
791
|
+
# feature_enabled - Boolean indicating if feature is enabled or not
|
792
|
+
# variation - varition returned by decision service
|
793
|
+
# user_id - String user ID
|
794
|
+
#
|
795
|
+
# Returns string value of the variable.
|
796
|
+
|
797
|
+
config = project_config
|
798
|
+
variable_value = variable['defaultValue']
|
799
|
+
if variation
|
800
|
+
if feature_enabled == true
|
801
|
+
variation_variable_usages = config.variation_id_to_variable_usage_map[variation['id']]
|
802
|
+
variable_id = variable['id']
|
803
|
+
if variation_variable_usages&.key?(variable_id)
|
804
|
+
variable_value = variation_variable_usages[variable_id]['value']
|
805
|
+
@logger.log(Logger::INFO,
|
806
|
+
"Got variable value '#{variable_value}' for variable '#{variable['key']}' of feature flag '#{feature_flag_key}'.")
|
807
|
+
else
|
808
|
+
@logger.log(Logger::DEBUG,
|
809
|
+
"Variable value is not defined. Returning the default variable value '#{variable_value}' for variable '#{variable['key']}'.")
|
810
|
+
|
811
|
+
end
|
812
|
+
else
|
813
|
+
@logger.log(Logger::DEBUG,
|
814
|
+
"Feature '#{feature_flag_key}' is not enabled for user '#{user_id}'. Returning the default variable value '#{variable_value}'.")
|
815
|
+
end
|
816
|
+
else
|
817
|
+
@logger.log(Logger::INFO,
|
818
|
+
"User '#{user_id}' was not bucketed into experiment or rollout for feature flag '#{feature_flag_key}'. Returning the default variable value '#{variable_value}'.")
|
819
|
+
end
|
820
|
+
variable_value
|
821
|
+
end
|
822
|
+
|
661
823
|
def user_inputs_valid?(attributes = nil, event_tags = nil)
|
662
824
|
# Helper method to validate user inputs.
|
663
825
|
#
|
data/lib/optimizely/audience.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2016-2017, 2019, Optimizely and contributors
|
4
|
+
# Copyright 2016-2017, 2019-2020, 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.
|
@@ -24,23 +24,32 @@ module Optimizely
|
|
24
24
|
module Audience
|
25
25
|
module_function
|
26
26
|
|
27
|
-
def
|
28
|
-
# Determine for given experiment if user satisfies the
|
27
|
+
def user_meets_audience_conditions?(config, experiment, attributes, logger, logging_hash = nil, logging_key = nil)
|
28
|
+
# Determine for given experiment/rollout rule if user satisfies the audience conditions.
|
29
29
|
#
|
30
30
|
# config - Representation of the Optimizely project config.
|
31
|
-
# experiment - Experiment
|
31
|
+
# experiment - Experiment/Rollout rule in which user is to be bucketed.
|
32
32
|
# attributes - Hash representing user attributes which will be used in determining if
|
33
33
|
# the audience conditions are met.
|
34
|
+
# logger - Provides a logger instance.
|
35
|
+
# logging_hash - Optional string representing logs hash inside Helpers::Constants.
|
36
|
+
# This defaults to 'EXPERIMENT_AUDIENCE_EVALUATION_LOGS'.
|
37
|
+
# logging_key - Optional string to be logged as an identifier of experiment under evaluation.
|
38
|
+
# This defaults to experiment['key'].
|
34
39
|
#
|
35
40
|
# Returns boolean representing if user satisfies audience conditions for the audiences or not.
|
41
|
+
logging_hash ||= 'EXPERIMENT_AUDIENCE_EVALUATION_LOGS'
|
42
|
+
logging_key ||= experiment['key']
|
43
|
+
|
44
|
+
logs_hash = Object.const_get "Optimizely::Helpers::Constants::#{logging_hash}"
|
36
45
|
|
37
46
|
audience_conditions = experiment['audienceConditions'] || experiment['audienceIds']
|
38
47
|
|
39
48
|
logger.log(
|
40
49
|
Logger::DEBUG,
|
41
50
|
format(
|
42
|
-
|
43
|
-
|
51
|
+
logs_hash['EVALUATING_AUDIENCES_COMBINED'],
|
52
|
+
logging_key,
|
44
53
|
audience_conditions
|
45
54
|
)
|
46
55
|
)
|
@@ -50,8 +59,8 @@ module Optimizely
|
|
50
59
|
logger.log(
|
51
60
|
Logger::INFO,
|
52
61
|
format(
|
53
|
-
|
54
|
-
|
62
|
+
logs_hash['AUDIENCE_EVALUATION_RESULT_COMBINED'],
|
63
|
+
logging_key,
|
55
64
|
'TRUE'
|
56
65
|
)
|
57
66
|
)
|
@@ -74,7 +83,7 @@ module Optimizely
|
|
74
83
|
logger.log(
|
75
84
|
Logger::DEBUG,
|
76
85
|
format(
|
77
|
-
|
86
|
+
logs_hash['EVALUATING_AUDIENCE'],
|
78
87
|
audience_id,
|
79
88
|
audience_conditions
|
80
89
|
)
|
@@ -84,8 +93,8 @@ module Optimizely
|
|
84
93
|
result = ConditionTreeEvaluator.evaluate(audience_conditions, evaluate_custom_attr)
|
85
94
|
result_str = result.nil? ? 'UNKNOWN' : result.to_s.upcase
|
86
95
|
logger.log(
|
87
|
-
Logger::
|
88
|
-
format(
|
96
|
+
Logger::DEBUG,
|
97
|
+
format(logs_hash['AUDIENCE_EVALUATION_RESULT'], audience_id, result_str)
|
89
98
|
)
|
90
99
|
result
|
91
100
|
end
|
@@ -97,8 +106,8 @@ module Optimizely
|
|
97
106
|
logger.log(
|
98
107
|
Logger::INFO,
|
99
108
|
format(
|
100
|
-
|
101
|
-
|
109
|
+
logs_hash['AUDIENCE_EVALUATION_RESULT_COMBINED'],
|
110
|
+
logging_key,
|
102
111
|
eval_result.to_s.upcase
|
103
112
|
)
|
104
113
|
)
|
data/lib/optimizely/bucketer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2016-2017, 2019 Optimizely and contributors
|
4
|
+
# Copyright 2016-2017, 2019-2020 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.
|
@@ -39,7 +39,7 @@ module Optimizely
|
|
39
39
|
# Determines ID of variation to be shown for a given experiment key and user ID.
|
40
40
|
#
|
41
41
|
# project_config - Instance of ProjectConfig
|
42
|
-
# experiment - Experiment for which visitor is to be bucketed.
|
42
|
+
# experiment - Experiment or Rollout rule for which visitor is to be bucketed.
|
43
43
|
# bucketing_id - String A customer-assigned value used to generate the bucketing key
|
44
44
|
# user_id - String ID for user.
|
45
45
|
#
|
@@ -47,6 +47,7 @@ module Optimizely
|
|
47
47
|
return nil if experiment.nil?
|
48
48
|
|
49
49
|
# check if experiment is in a group; if so, check if user is bucketed into specified experiment
|
50
|
+
# this will not affect evaluation of rollout rules.
|
50
51
|
experiment_id = experiment['id']
|
51
52
|
experiment_key = experiment['key']
|
52
53
|
group_id = experiment['groupId']
|
@@ -82,11 +83,6 @@ module Optimizely
|
|
82
83
|
variation_id = find_bucket(bucketing_id, user_id, experiment_id, traffic_allocations)
|
83
84
|
if variation_id && variation_id != ''
|
84
85
|
variation = project_config.get_variation_from_id(experiment_key, variation_id)
|
85
|
-
variation_key = variation ? variation['key'] : nil
|
86
|
-
@logger.log(
|
87
|
-
Logger::INFO,
|
88
|
-
"User '#{user_id}' is in variation '#{variation_key}' of experiment '#{experiment_key}'."
|
89
|
-
)
|
90
86
|
return variation
|
91
87
|
end
|
92
88
|
|
@@ -98,7 +94,6 @@ module Optimizely
|
|
98
94
|
)
|
99
95
|
end
|
100
96
|
|
101
|
-
@logger.log(Logger::INFO, "User '#{user_id}' is in no variation.")
|
102
97
|
nil
|
103
98
|
end
|
104
99
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019, Optimizely and contributors
|
3
|
+
# Copyright 2019-2020, Optimizely and contributors
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -24,6 +24,7 @@ module Optimizely
|
|
24
24
|
RUNNING_EXPERIMENT_STATUS = ['Running'].freeze
|
25
25
|
RESERVED_ATTRIBUTE_PREFIX = '$opt_'
|
26
26
|
|
27
|
+
attr_reader :datafile
|
27
28
|
attr_reader :account_id
|
28
29
|
attr_reader :attributes
|
29
30
|
attr_reader :audiences
|
@@ -62,6 +63,7 @@ module Optimizely
|
|
62
63
|
|
63
64
|
config = JSON.parse(datafile)
|
64
65
|
|
66
|
+
@datafile = datafile
|
65
67
|
@error_handler = error_handler
|
66
68
|
@logger = logger
|
67
69
|
@version = config['version']
|
@@ -82,6 +84,17 @@ module Optimizely
|
|
82
84
|
@revision = config['revision']
|
83
85
|
@rollouts = config.fetch('rollouts', [])
|
84
86
|
|
87
|
+
# Json type is represented in datafile as a subtype of string for the sake of backwards compatibility.
|
88
|
+
# Converting it to a first-class json type while creating Project Config
|
89
|
+
@feature_flags.each do |feature_flag|
|
90
|
+
feature_flag['variables'].each do |variable|
|
91
|
+
if variable['type'] == 'string' && variable['subType'] == 'json'
|
92
|
+
variable['type'] = 'json'
|
93
|
+
variable.delete('subType')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
85
98
|
# Utility maps for quick lookup
|
86
99
|
@attribute_key_map = generate_key_map(@attributes, 'key')
|
87
100
|
@event_key_map = generate_key_map(@events, 'key')
|
@@ -159,8 +172,9 @@ module Optimizely
|
|
159
172
|
config = new(datafile, logger, error_handler)
|
160
173
|
rescue StandardError => e
|
161
174
|
default_logger = SimpleLogger.new
|
162
|
-
|
163
|
-
|
175
|
+
error_to_handle = e.class == InvalidDatafileVersionError ? e : InvalidInputError.new('datafile')
|
176
|
+
error_msg = error_to_handle.message
|
177
|
+
|
164
178
|
default_logger.log(Logger::ERROR, error_msg)
|
165
179
|
error_handler.handle_error error_to_handle
|
166
180
|
return nil
|