@@ -56,6 +56,12 @@ class ProjectConfig
5656 attr_reader :variation_id_to_variable_usage_map
5757 attr_reader :variation_key_map
5858
59+ # Hash of user IDs to a Hash
60+ # of experiments to variations. This contains all the forced variations
61+ # set by the user by calling setForcedVariation (it is not the same as the
62+ # whitelisting forcedVariations data structure in the Experiments class).
63+ attr_reader :forced_variation_map
64+
5965 def initialize ( datafile , logger , error_handler )
6066 # ProjectConfig init method to fetch and set project config data
6167 #
@@ -98,6 +104,7 @@ def initialize(datafile, logger, error_handler)
98104 @audience_id_map = generate_key_map ( @audiences , 'id' )
99105 @variation_id_map = { }
100106 @variation_key_map = { }
107+ @forced_variation_map = { }
101108 @variation_id_to_variable_usage_map = { }
102109 @variation_id_to_experiment_map = { }
103110 @experiment_key_map . each do |key , exp |
@@ -246,19 +253,113 @@ def get_variation_id_from_key(experiment_key, variation_key)
246253 nil
247254 end
248255
249- def get_forced_variations ( experiment_key )
250- # Retrieves forced variations for a given experiment Key
256+ def get_whitelisted_variations ( experiment_key )
257+ # Retrieves whitelisted variations for a given experiment Key
251258 #
252259 # experiment_key - String Key representing the experiment
253260 #
254- # Returns forced variations for the experiment or nil
261+ # Returns whitelisted variations for the experiment or nil
255262
256263 experiment = @experiment_key_map [ experiment_key ]
257264 return experiment [ 'forcedVariations' ] if experiment
258265 @logger . log Logger ::ERROR , "Experiment key '#{ experiment_key } ' is not in datafile."
259266 @error_handler . handle_error InvalidExperimentError
260267 end
261268
269+ def get_forced_variation ( experiment_key , user_id )
270+ # Gets the forced variation for the given user and experiment.
271+ #
272+ # experiment_key - String Key for experiment.
273+ # user_id - String ID for user
274+ #
275+ # Returns Variation The variation which the given user and experiment should be forced into.
276+
277+ # check for nil and empty string user ID
278+ if user_id . nil? or user_id . empty?
279+ @logger . log ( Logger ::DEBUG , "User ID is invalid" )
280+ return nil
281+ end
282+
283+ unless @forced_variation_map . has_key? ( user_id )
284+ @logger . log ( Logger ::DEBUG , "User '#{ user_id } ' is not in the forced variation map." )
285+ return nil
286+ end
287+
288+ experimentToVariationMap = @forced_variation_map [ user_id ]
289+ experiment = get_experiment_from_key ( experiment_key )
290+ experiment_id = experiment [ "id" ] if experiment
291+ # check for nil and empty string experiment ID
292+ if experiment_id . nil? or experiment_id . empty?
293+ # this case is logged in get_experiment_from_key
294+ return nil
295+ end
296+
297+ unless experimentToVariationMap . has_key? ( experiment_id )
298+ @logger . log ( Logger ::DEBUG , "No experiment '#{ experiment_key } ' mapped to user '#{ user_id } ' in the forced variation map." )
299+ return nil
300+ end
301+
302+ variation_id = experimentToVariationMap [ experiment_id ]
303+ variation_key = ""
304+ variation = get_variation_from_id ( experiment_key , variation_id )
305+ variation_key = variation [ "key" ] if variation
306+
307+ # check if the variation exists in the datafile
308+ if variation_key . empty?
309+ # this case is logged in get_variation_from_id
310+ return nil
311+ end
312+
313+ @logger . log ( Logger ::DEBUG , "Variation '#{ variation_key } ' is mapped to experiment '#{ experiment_key } ' and user '#{ user_id } ' in the forced variation map" )
314+
315+ variation
316+ end
317+
318+ def set_forced_variation ( experiment_key , user_id , variation_key )
319+ # Sets a Hash of user IDs to a Hash of experiments to forced variations.
320+ #
321+ # experiment_key - String Key for experiment.
322+ # user_id - String ID for user.
323+ # variation_key - String Key for variation. If null, then clear the existing experiment-to-variation mapping.
324+ #
325+ # Returns a boolean value that indicates if the set completed successfully.
326+
327+ # check for null and empty string user ID
328+ if user_id . nil? or user_id . empty?
329+ @logger . log ( Logger ::DEBUG , "User ID is invalid" )
330+ return false
331+ end
332+
333+ experiment = get_experiment_from_key ( experiment_key )
334+ experiment_id = experiment [ "id" ] if experiment
335+ # check if the experiment exists in the datafile
336+ if experiment_id . nil? or experiment_id . empty?
337+ return false
338+ end
339+
340+ # clear the forced variation if the variation key is null
341+ if variation_key . nil? or variation_key . empty?
342+ @forced_variation_map [ user_id ] . delete ( experiment_id ) if @forced_variation_map . has_key? ( user_id )
343+ @logger . log ( Logger ::DEBUG , "Variation mapped to experiment '#{ experiment_key } ' has been removed for user '#{ user_id } '." )
344+ return true
345+ end
346+
347+ variation_id = get_variation_id_from_key ( experiment_key , variation_key )
348+
349+ # check if the variation exists in the datafile
350+ unless variation_id
351+ # this case is logged in get_variation_id_from_key
352+ return false
353+ end
354+
355+ unless @forced_variation_map . has_key? user_id
356+ @forced_variation_map [ user_id ] = { }
357+ end
358+ @forced_variation_map [ user_id ] [ experiment_id ] = variation_id
359+ @logger . log ( Logger ::DEBUG , "Set variation '#{ variation_id } ' for experiment '#{ experiment_id } ' and user '#{ user_id } ' in the forced variation map." )
360+ return true
361+ end
362+
262363 def get_attribute_id ( attribute_key )
263364 attribute = @attribute_key_map [ attribute_key ]
264365 return attribute [ 'id' ] if attribute
@@ -290,7 +391,6 @@ def variation_id_exists?(experiment_id, variation_id)
290391 return true if variation
291392 @logger . log Logger ::ERROR , "Variation ID '#{ variation_id } ' is not in datafile."
292393 @error_handler . handle_error InvalidVariationError
293- return false
294394 end
295395
296396 false
0 commit comments