/// <summary> /// Buckets visitor and sends impression event to Optimizely. /// </summary> /// <param name="experimentKey">experimentKey string Key identifying the experiment</param> /// <param name="userId">string ID for user</param> /// <param name="attributes">associative array of Attributes for the user</param> /// <returns>null|Variation Representing variation</returns> public Variation Activate(string experimentKey, string userId, UserAttributes userAttributes = null) { if (!IsValid) { Logger.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'activate'."); return(null); } var experiment = Config.GetExperimentFromKey(experimentKey); if (experiment.Key == null) { Logger.Log(LogLevel.INFO, string.Format("Not activating user {0}.", userId)); return(null); } var variation = DecisionService.GetVariation(experiment, userId, userAttributes); if (variation == null || variation.Key == null) { Logger.Log(LogLevel.INFO, string.Format("Not activating user {0}.", userId)); return(null); } if (userAttributes != null) { userAttributes = userAttributes.FilterNullValues(Logger); } SendImpressionEvent(experiment, variation, userId, userAttributes); return(variation); }
public void TestGetVariationEvaluatesUserProfileBeforeAudienceTargeting() { Experiment experiment = ProjectConfig.Experiments[8]; Variation variation = experiment.Variations[0]; Decision decision = new Decision(variation.Id); UserProfile userProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision> { { experiment.Id, decision } }); UserProfileServiceMock.Setup(up => up.Lookup(WhitelistedUserId)).Returns(userProfile.ToMap()); DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, ProjectConfig, UserProfileServiceMock.Object, LoggerMock.Object); decisionService.GetVariation(experiment, GenericUserId, new UserAttributes()); LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" does not meet conditions to be in experiment \"{1}\".", GenericUserId, experiment.Key)), Times.Once); // ensure that a user with a saved user profile, sees the same variation regardless of audience evaluation decisionService.GetVariation(experiment, UserProfileId, new UserAttributes()); BucketerMock.Verify(_ => _.Bucket(It.IsAny <ProjectConfig>(), It.IsAny <Experiment>(), It.IsAny <string>(), It.IsAny <string>()), Times.Never); }
public void TestGetVariationForcedVariationPrecedesAudienceEval() { DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, ProjectConfig, null, LoggerMock.Object); Experiment experiment = ProjectConfig.Experiments[8]; Variation expectedVariation = experiment.Variations[0]; // user excluded without audiences and whitelisting Assert.IsNull(decisionService.GetVariation(experiment, GenericUserId, new UserAttributes())); var actualVariation = decisionService.GetVariation(experiment, WhitelistedUserId, new UserAttributes()); LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" is forced in variation \"vtag5\".", WhitelistedUserId)), Times.Once); // no attributes provided for a experiment that has an audience Assert.IsTrue(TestData.CompareObjects(actualVariation, expectedVariation)); BucketerMock.Verify(_ => _.Bucket(It.IsAny <ProjectConfig>(), It.IsAny <Experiment>(), It.IsAny <string>(), It.IsAny <string>()), Times.Never); }
public void TestGetVariationSavesANewUserProfile() { Experiment experiment = ProjectConfig.Experiments[6]; Variation variation = experiment.Variations[0]; Decision decision = new Decision(variation.Id); UserProfile expectedUserProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision> { { experiment.Id, decision } }); var mockBucketer = new Mock <Bucketer>(LoggerMock.Object); mockBucketer.Setup(m => m.Bucket(ProjectConfig, experiment, UserProfileId, UserProfileId)).Returns(variation); Dictionary <string, object> userProfile = null; UserProfileServiceMock.Setup(up => up.Lookup(UserProfileId)).Returns(userProfile); DecisionService decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, ProjectConfig, UserProfileServiceMock.Object, LoggerMock.Object); Assert.IsTrue(TestData.CompareObjects(variation, decisionService.GetVariation(experiment, UserProfileId, new UserAttributes()))); UserProfileServiceMock.Verify(_ => _.Save(It.IsAny <Dictionary <string, object> >()), Times.Once); }
public void TestGetVariationSavesBucketedVariationIntoUserProfile() { Experiment experiment = ProjectConfig.Experiments[6]; Variation variation = experiment.Variations[0]; Decision decision = new Decision(variation.Id); UserProfile originalUserProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision>()); UserProfileServiceMock.Setup(ups => ups.Lookup(UserProfileId)).Returns(originalUserProfile.ToMap()); UserProfile expectedUserProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision> { { experiment.Id, decision } }); var mockBucketer = new Mock <Bucketer>(LoggerMock.Object); mockBucketer.Setup(m => m.Bucket(ProjectConfig, experiment, UserProfileId, UserProfileId)).Returns(variation); DecisionService decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, ProjectConfig, UserProfileServiceMock.Object, LoggerMock.Object); Assert.IsTrue(TestData.CompareObjects(variation, decisionService.GetVariation(experiment, UserProfileId, new UserAttributes()))); LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("Saved variation \"{0}\" of experiment \"{1}\" for user \"{2}\".", variation.Id, experiment.Id, UserProfileId)), Times.Once); UserProfileServiceMock.Verify(_ => _.Save(It.IsAny <Dictionary <string, object> >()), Times.Once); }
/// <summary> /// Buckets visitor and sends impression event to Optimizely. /// </summary> /// <param name="experimentKey">experimentKey string Key identifying the experiment</param> /// <param name="userId">string ID for user</param> /// <param name="userAttributes">associative array of Attributes for the user</param> /// <returns>null|Variation Representing variation</returns> public Variation Activate(string experimentKey, string userId, UserAttributes userAttributes = null) { if (!IsValid) { Logger.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'activate'."); return(null); } var inputValues = new Dictionary <string, string> { { USER_ID, userId }, { EXPERIMENT_KEY, experimentKey } }; if (!ValidateStringInputs(inputValues)) { return(null); } var experiment = Config.GetExperimentFromKey(experimentKey); if (experiment.Key == null) { Logger.Log(LogLevel.INFO, string.Format("Not activating user {0}.", userId)); return(null); } var variation = DecisionService.GetVariation(experiment, userId, userAttributes); if (variation == null || variation.Key == null) { Logger.Log(LogLevel.INFO, string.Format("Not activating user {0}.", userId)); return(null); } SendImpressionEvent(experiment, variation, userId, userAttributes); return(variation); }
/// <summary> /// Get variation where user will be bucketed /// </summary> /// <param name="experimentKey">experimentKey string Key identifying the experiment</param> /// <param name="userId">ID for the user</param> /// <param name="userAttributes">Attributes for the users</param> /// <returns>null|Variation Representing variation</returns> public Variation GetVariation(string experimentKey, string userId, UserAttributes userAttributes = null) { if (!IsValid) { Logger.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetVariation'."); return(null); } var inputValues = new Dictionary <string, string> { { USER_ID, userId }, { EXPERIMENT_KEY, experimentKey } }; if (!ValidateStringInputs(inputValues)) { return(null); } Experiment experiment = Config.GetExperimentFromKey(experimentKey); if (experiment.Key == null) { return(null); } var variation = DecisionService.GetVariation(experiment, userId, userAttributes); var decisionInfo = new Dictionary <string, object> { { "experimentKey", experimentKey }, { "variationKey", variation?.Key }, }; userAttributes = userAttributes ?? new UserAttributes(); var decisionNotificationType = Config.IsFeatureExperiment(experiment.Id) ? DecisionNotificationTypes.FEATURE_TEST : DecisionNotificationTypes.AB_TEST; NotificationCenter.SendNotifications(NotificationCenter.NotificationType.Decision, decisionNotificationType, userId, userAttributes, decisionInfo); return(variation); }
public void TestBucketReturnsVariationStoredInUserProfile() { Experiment experiment = ProjectConfig.Experiments[6]; Variation variation = experiment.Variations[0]; Decision decision = new Decision(variation.Id); UserProfile userProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision> { { experiment.Id, decision } }); UserProfileServiceMock.Setup(_ => _.Lookup(UserProfileId)).Returns(userProfile.ToMap()); DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, ProjectConfig, UserProfileServiceMock.Object, LoggerMock.Object); Assert.IsTrue(TestData.CompareObjects(variation, decisionService.GetVariation(experiment, UserProfileId, new UserAttributes()))); LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("Returning previously activated variation \"{0}\" of experiment \"{1}\" for user \"{2}\" from user profile.", variation.Key, experiment.Key, UserProfileId))); //BucketerMock.Verify(_ => _.Bucket(It.IsAny<ProjectConfig>(), It.IsAny<Experiment>(), It.IsAny<string>()), Times.Once); }