@@ -52,6 +52,12 @@ class ProjectConfig
52
52
attr_reader :variation_id_map
53
53
attr_reader :variation_key_map
54
54
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
+
55
61
def initialize ( datafile , logger , error_handler )
56
62
# ProjectConfig init method to fetch and set project config data
57
63
#
@@ -92,6 +98,9 @@ def initialize(datafile, logger, error_handler)
92
98
@audience_id_map = generate_key_map ( @audiences , 'id' )
93
99
@variation_id_map = { }
94
100
@variation_key_map = { }
101
+ @forced_variation_map = { }
102
+ @variation_id_to_variable_usage_map = { }
103
+ @variation_id_to_experiment_map = { }
95
104
@experiment_key_map . each do |key , exp |
96
105
variations = exp . fetch ( 'variations' )
97
106
@variation_id_map [ key ] = generate_key_map ( variations , 'id' )
@@ -209,19 +218,113 @@ def get_variation_id_from_key(experiment_key, variation_key)
209
218
nil
210
219
end
211
220
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
214
223
#
215
224
# experiment_key - String Key representing the experiment
216
225
#
217
- # Returns forced variations for the experiment or nil
226
+ # Returns whitelisted variations for the experiment or nil
218
227
219
228
experiment = @experiment_key_map [ experiment_key ]
220
229
return experiment [ 'forcedVariations' ] if experiment
221
230
@logger . log Logger ::ERROR , "Experiment key '#{ experiment_key } ' is not in datafile."
222
231
@error_handler . handle_error InvalidExperimentError
223
232
end
224
233
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
+
225
328
def get_attribute_id ( attribute_key )
226
329
attribute = @attribute_key_map [ attribute_key ]
227
330
return attribute [ 'id' ] if attribute
@@ -253,7 +356,6 @@ def variation_id_exists?(experiment_id, variation_id)
253
356
return true if variation
254
357
@logger . log Logger ::ERROR , "Variation ID '#{ variation_id } ' is not in datafile."
255
358
@error_handler . handle_error InvalidVariationError
256
- return false
257
359
end
258
360
259
361
false
0 commit comments