Skip to content

Commit 7658884

Browse files
[FSSDK-11140] Ruby: Update project config to track CMAB properties (#362)
* [FSSDK-11140] Ruby: Update project config to track CMAB properties * Fix errors * Fix errors * Fix test * Correct the experiment * Add new test cases related CMAB * Implement comments * Correct the type * Fix lint
1 parent 61a95c3 commit 7658884

File tree

4 files changed

+119
-1
lines changed

4 files changed

+119
-1
lines changed

lib/optimizely/config/datafile_project_config.rb

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class DatafileProjectConfig < ProjectConfig
2727
attr_reader :datafile, :account_id, :attributes, :audiences, :typed_audiences, :events,
2828
:experiments, :feature_flags, :groups, :project_id, :bot_filtering, :revision,
2929
:sdk_key, :environment_key, :rollouts, :version, :send_flag_decisions,
30-
:attribute_key_map, :audience_id_map, :event_key_map, :experiment_feature_map,
30+
:attribute_key_map, :attribute_id_to_key_map, :audience_id_map, :event_key_map, :experiment_feature_map,
3131
:experiment_id_map, :experiment_key_map, :feature_flag_key_map, :feature_variable_key_map,
3232
:group_id_map, :rollout_id_map, :rollout_experiment_id_map, :variation_id_map,
3333
:variation_id_to_variable_usage_map, :variation_key_map, :variation_id_map_by_experiment_id,
@@ -82,6 +82,10 @@ def initialize(datafile, logger, error_handler)
8282

8383
# Utility maps for quick lookup
8484
@attribute_key_map = generate_key_map(@attributes, 'key')
85+
@attribute_id_to_key_map = {}
86+
@attributes.each do |attribute|
87+
@attribute_id_to_key_map[attribute['id']] = attribute['key']
88+
end
8589
@event_key_map = generate_key_map(@events, 'key')
8690
@group_id_map = generate_key_map(@groups, 'id')
8791
@group_id_map.each do |key, group|
@@ -440,6 +444,40 @@ def get_attribute_id(attribute_key)
440444
nil
441445
end
442446

447+
def get_attribute_by_key(attribute_key)
448+
# Get attribute for the provided attribute key.
449+
#
450+
# Args:
451+
# Attribute key for which attribute is to be fetched.
452+
#
453+
# Returns:
454+
# Attribute corresponding to the provided attribute key.
455+
attribute = @attribute_key_map[attribute_key]
456+
return attribute if attribute
457+
458+
invalid_attribute_error = InvalidAttributeError.new(attribute_key)
459+
@logger.log Logger::ERROR, invalid_attribute_error.message
460+
@error_handler.handle_error invalid_attribute_error
461+
nil
462+
end
463+
464+
def get_attribute_key_by_id(attribute_id)
465+
# Get attribute key for the provided attribute ID.
466+
#
467+
# Args:
468+
# Attribute ID for which attribute is to be fetched.
469+
#
470+
# Returns:
471+
# Attribute key corresponding to the provided attribute ID.
472+
attribute = @attribute_id_to_key_map[attribute_id]
473+
return attribute if attribute
474+
475+
invalid_attribute_error = InvalidAttributeError.new(attribute_id)
476+
@logger.log Logger::ERROR, invalid_attribute_error.message
477+
@error_handler.handle_error invalid_attribute_error
478+
nil
479+
end
480+
443481
def variation_id_exists?(experiment_id, variation_id)
444482
# Determines if a given experiment ID / variation ID pair exists in the datafile
445483
#

lib/optimizely/helpers/constants.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ module Constants
201201
},
202202
'forcedVariations' => {
203203
'type' => 'object'
204+
},
205+
'cmab' => {
206+
'type' => 'object'
204207
}
205208
},
206209
'required' => %w[
@@ -303,6 +306,18 @@ module Constants
303306
},
304307
'required' => %w[key]
305308
}
309+
},
310+
'cmab' => {
311+
'type' => 'object',
312+
'properties' => {
313+
'attributeIds' => {
314+
'type' => 'array',
315+
'items' => {'type' => 'string'}
316+
},
317+
'trafficAllocation' => {
318+
'type' => 'integer'
319+
}
320+
}
306321
}
307322
},
308323
'required' => %w[

lib/optimizely/project_config.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ def get_whitelisted_variations(experiment_id); end
8686

8787
def get_attribute_id(attribute_key); end
8888

89+
def get_attribute_by_key(attribute_key); end
90+
91+
def get_attribute_key_by_id(attribute_id); end
92+
8993
def variation_id_exists?(experiment_id, variation_id); end
9094

9195
def get_feature_flag_from_key(feature_flag_key); end

spec/config/datafile_project_config_spec.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,67 @@
10781078
end
10791079
end
10801080

1081+
describe '#test_cmab_field_population' do
1082+
it 'Should return CMAB details' do
1083+
config_dict = Marshal.load(Marshal.dump(OptimizelySpec::VALID_CONFIG_BODY))
1084+
config_dict['experiments'][0]['cmab'] = {'attributeIds' => %w[808797688 808797689], 'trafficAllocation' => 4000}
1085+
config_dict['experiments'][0]['trafficAllocation'] = []
1086+
1087+
config_json = JSON.dump(config_dict)
1088+
project_config = Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler)
1089+
1090+
experiment = project_config.get_experiment_from_key('test_experiment')
1091+
expect(experiment['cmab']).to eq({'attributeIds' => %w[808797688 808797689], 'trafficAllocation' => 4000})
1092+
1093+
experiment2 = project_config.get_experiment_from_key('test_experiment_with_audience')
1094+
expect(experiment2['cmab']).to eq(nil)
1095+
end
1096+
it 'should return nil if cmab field is missing' do
1097+
config_dict = Marshal.load(Marshal.dump(OptimizelySpec::VALID_CONFIG_BODY))
1098+
config_dict['experiments'][0].delete('cmab')
1099+
config_json = JSON.dump(config_dict)
1100+
project_config = Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler)
1101+
experiment = project_config.get_experiment_from_key('test_experiment')
1102+
expect(experiment['cmab']).to eq(nil)
1103+
end
1104+
1105+
it 'should handle empty cmab object' do
1106+
config_dict = Marshal.load(Marshal.dump(OptimizelySpec::VALID_CONFIG_BODY))
1107+
config_dict['experiments'][0]['cmab'] = {}
1108+
config_json = JSON.dump(config_dict)
1109+
project_config = Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler)
1110+
experiment = project_config.get_experiment_from_key('test_experiment')
1111+
expect(experiment['cmab']).to eq({})
1112+
end
1113+
1114+
it 'should handle cmab with only attributeIds' do
1115+
config_dict = Marshal.load(Marshal.dump(OptimizelySpec::VALID_CONFIG_BODY))
1116+
config_dict['experiments'][0]['cmab'] = {'attributeIds' => %w[808797688]}
1117+
config_json = JSON.dump(config_dict)
1118+
project_config = Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler)
1119+
experiment = project_config.get_experiment_from_key('test_experiment')
1120+
expect(experiment['cmab']).to eq({'attributeIds' => %w[808797688]})
1121+
end
1122+
1123+
it 'should handle cmab with only trafficAllocation' do
1124+
config_dict = Marshal.load(Marshal.dump(OptimizelySpec::VALID_CONFIG_BODY))
1125+
config_dict['experiments'][0]['cmab'] = {'trafficAllocation' => 1234}
1126+
config_json = JSON.dump(config_dict)
1127+
project_config = Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler)
1128+
experiment = project_config.get_experiment_from_key('test_experiment')
1129+
expect(experiment['cmab']).to eq({'trafficAllocation' => 1234})
1130+
end
1131+
1132+
it 'should not affect other experiments when cmab is set' do
1133+
config_dict = Marshal.load(Marshal.dump(OptimizelySpec::VALID_CONFIG_BODY))
1134+
config_dict['experiments'][0]['cmab'] = {'attributeIds' => %w[808797688 808797689], 'trafficAllocation' => 4000}
1135+
config_json = JSON.dump(config_dict)
1136+
project_config = Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler)
1137+
experiment2 = project_config.get_experiment_from_key('test_experiment_with_audience')
1138+
expect(experiment2['cmab']).to eq(nil)
1139+
end
1140+
end
1141+
10811142
describe '#feature_experiment' do
10821143
let(:config) { Optimizely::DatafileProjectConfig.new(config_body_JSON, logger, error_handler) }
10831144

0 commit comments

Comments
 (0)