@@ -52,6 +52,12 @@ class ProjectConfig
5252 attr_reader :variation_id_map
5353 attr_reader :variation_key_map
5454
55+ # Hash of user IDs to a Hash
56+ # of experiments to variations. This contains all the forced variations
57+ # set by the user by calling setForcedVariation (it is not the same as the
58+ # whitelisting forcedVariations data structure in the Experiments class).
59+ attr_reader :forced_variation_map
60+
5561 def initialize ( datafile , logger , error_handler )
5662 # ProjectConfig init method to fetch and set project config data
5763 #
@@ -92,6 +98,9 @@ def initialize(datafile, logger, error_handler)
9298 @audience_id_map = generate_key_map ( @audiences , 'id' )
9399 @variation_id_map = { }
94100 @variation_key_map = { }
101+ @forced_variation_map = { }
102+ @variation_id_to_variable_usage_map = { }
103+ @variation_id_to_experiment_map = { }
95104 @experiment_key_map . each do |key , exp |
96105 variations = exp . fetch ( 'variations' )
97106 @variation_id_map [ key ] = generate_key_map ( variations , 'id' )
@@ -209,19 +218,113 @@ def get_variation_id_from_key(experiment_key, variation_key)
209218 nil
210219 end
211220
212- def get_forced_variations ( experiment_key )
213- # Retrieves forced variations for a given experiment Key
221+ def get_whitelisted_variations ( experiment_key )
222+ # Retrieves whitelisted variations for a given experiment Key
214223 #
215224 # experiment_key - String Key representing the experiment
216225 #
217- # Returns forced variations for the experiment or nil
226+ # Returns whitelisted variations for the experiment or nil
218227
219228 experiment = @experiment_key_map [ experiment_key ]
220229 return experiment [ 'forcedVariations' ] if experiment
221230 @logger . log Logger ::ERROR , "Experiment key '#{ experiment_key } ' is not in datafile."
222231 @error_handler . handle_error InvalidExperimentError
223232 end
224233
234+ def get_forced_variation ( experiment_key , user_id )
235+ # Gets the forced variation for the given user and experiment.
236+ #
237+ # experiment_key - String Key for experiment.
238+ # user_id - String ID for user
239+ #
240+ # Returns Variation The variation which the given user and experiment should be forced into.
241+
242+ # check for nil and empty string user ID
243+ if user_id . nil? or user_id . empty?
244+ @logger . log ( Logger ::DEBUG , "User ID is invalid" )
245+ return nil
246+ end
247+
248+ unless @forced_variation_map . has_key? ( user_id )
249+ @logger . log ( Logger ::DEBUG , "User '#{ user_id } ' is not in the forced variation map." )
250+ return nil
251+ end
252+
253+ experimentToVariationMap = @forced_variation_map [ user_id ]
254+ experiment = get_experiment_from_key ( experiment_key )
255+ experiment_id = experiment [ "id" ] if experiment
256+ # check for nil and empty string experiment ID
257+ if experiment_id . nil? or experiment_id . empty?
258+ # this case is logged in get_experiment_from_key
259+ return nil
260+ end
261+
262+ unless experimentToVariationMap . has_key? ( experiment_id )
263+ @logger . log ( Logger ::DEBUG , "No experiment '#{ experiment_key } ' mapped to user '#{ user_id } ' in the forced variation map." )
264+ return nil
265+ end
266+
267+ variation_id = experimentToVariationMap [ experiment_id ]
268+ variation_key = ""
269+ variation = get_variation_from_id ( experiment_key , variation_id )
270+ variation_key = variation [ "key" ] if variation
271+
272+ # check if the variation exists in the datafile
273+ if variation_key . empty?
274+ # this case is logged in get_variation_from_id
275+ return nil
276+ end
277+
278+ @logger . log ( Logger ::DEBUG , "Variation '#{ variation_key } ' is mapped to experiment '#{ experiment_key } ' and user '#{ user_id } ' in the forced variation map" )
279+
280+ variation
281+ end
282+
283+ def set_forced_variation ( experiment_key , user_id , variation_key )
284+ # Sets a Hash of user IDs to a Hash of experiments to forced variations.
285+ #
286+ # experiment_key - String Key for experiment.
287+ # user_id - String ID for user.
288+ # variation_key - String Key for variation. If null, then clear the existing experiment-to-variation mapping.
289+ #
290+ # Returns a boolean value that indicates if the set completed successfully.
291+
292+ # check for null and empty string user ID
293+ if user_id . nil? or user_id . empty?
294+ @logger . log ( Logger ::DEBUG , "User ID is invalid" )
295+ return false
296+ end
297+
298+ experiment = get_experiment_from_key ( experiment_key )
299+ experiment_id = experiment [ "id" ] if experiment
300+ # check if the experiment exists in the datafile
301+ if experiment_id . nil? or experiment_id . empty?
302+ return false
303+ end
304+
305+ # clear the forced variation if the variation key is null
306+ if variation_key . nil? or variation_key . empty?
307+ @forced_variation_map [ user_id ] . delete ( experiment_id ) if @forced_variation_map . has_key? ( user_id )
308+ @logger . log ( Logger ::DEBUG , "Variation mapped to experiment '#{ experiment_key } ' has been removed for user '#{ user_id } '." )
309+ return true
310+ end
311+
312+ variation_id = get_variation_id_from_key ( experiment_key , variation_key )
313+
314+ # check if the variation exists in the datafile
315+ unless variation_id
316+ # this case is logged in get_variation_id_from_key
317+ return false
318+ end
319+
320+ unless @forced_variation_map . has_key? user_id
321+ @forced_variation_map [ user_id ] = { }
322+ end
323+ @forced_variation_map [ user_id ] [ experiment_id ] = variation_id
324+ @logger . log ( Logger ::DEBUG , "Set variation '#{ variation_id } ' for experiment '#{ experiment_id } ' and user '#{ user_id } ' in the forced variation map." )
325+ return true
326+ end
327+
225328 def get_attribute_id ( attribute_key )
226329 attribute = @attribute_key_map [ attribute_key ]
227330 return attribute [ 'id' ] if attribute
@@ -253,7 +356,6 @@ def variation_id_exists?(experiment_id, variation_id)
253356 return true if variation
254357 @logger . log Logger ::ERROR , "Variation ID '#{ variation_id } ' is not in datafile."
255358 @error_handler . handle_error InvalidVariationError
256- return false
257359 end
258360
259361 false
0 commit comments